Avanpost FAM/MFA+ : 4.3.9 Настройка Avanpost ESIA IdP Adapter

Avanpost ESIA IdP Adapter представляет собой OpenID Connect-сервер, который перенаправляет аутентификацию пользователя в ЕСИА. Компонент реализует функции сервера OpenID Connect и клиента ЕСИА, позволяя осуществлять простую и централизованную аутентификацию в OIDC-приложениях при помощи механизма ЕСИА. Использование компонента позволяет выполнять настройку OIDC-приложений стандартизованным способом без необходимости отдельно настраивать специфичные для ЕСИА параметры. Обработка криптографических операций (подпись и проверка JWT) выполняется локально с использованием КриптоПро CSP, что повышает безопасность и упрощает интеграцию.

Компонент Avanpost ESIA IdP Adapter может использоваться для работы по протоколу OpenID Connect с любым OIDC-клиентом. В данной инструкции описывается настройка Avanpost ESIA IdP Adapter для Avanpost FAM Server.

Настройка Avanpost ESIA IdP Adapter

Настройку компонента следует выполнять следующим образом:

  1. Настроить в административной консоли FAM Server OIDC-приложение (описание настройки приложения представлено в статье Управление OpenID Connect-приложениями), в котором должен аутентифицироваться пользователь посредством ЕСИА.
  2. Настроить в административной консоли FAM Server IdP типа ЕСИА (описание настройки провайдера идентификации описано в статье Управление внешними провайдерами идентификации), посредством которого будет аутентифицироваться пользователь.
  3. Скачать Avanpost ESIA IdP Adapter из репозитория. 
  4. Настроить конфигурацию Avanpost ESIA IdP Adapter при помощи переменных окружения, задав следующие параметры:
    ПараметрЗначение
    DEBUGФлаг, активирующий режим отладки. При значении true сервис выводит расширенную диагностическую информацию в логи. В рабочей среде рекомендуется устанавливать значение false.
    BASE_URLБазовый URL-адрес, по которому доступен сервис Adapter. Должен соответствовать реальному сетевому расположению сервиса.
    HOSTСетевой интерфейс, на котором сервис Adapter принимает входящие HTTP-соединения. 
    PORTНомер порта, на котором сервис Adapter ожидает входящие HTTP-запросы.
    KEYПуть к файлу, содержащему приватный RSA-ключ в формате PEM. Этот ключ использует IdP Adapter для подписи JWT-токенов (ID Token, Access Token), выдаваемых OIDC-клиентам.
    KEY_IDУникальный идентификатор приватного ключа, указанного в параметре KEY. Используется для ссылки на конкретный ключ в наборе ключей.
    CLIENTSПуть к JSON-файлу, содержащему список доверенных OIDC-клиентов. Каждая запись в файле определяет ID клиента и его Domain для валидации redirect_uri.
    EXTIDPПуть к JSON-файлу, содержащему конфигурацию внешнего провайдера идентификации (ЕСИА). Данный файл определяет параметры подключения к ЕСИА.
    EXTIDP_REQUEST_TTLВремя жизни запроса к внешнему IdP (ЕСИА). Определяет, как долго Adapter будет хранить состояние (state) и другие параметры запроса авторизации до его завершения или истечения срока действия..
    EXTIDP_REQUEST_CLEAN_UPИнтервал времени, по истечении которого сервис выполняет фоновую очистку устаревших или завершенных запросов к внешнему IdP.
    USERINFO_TTLВремя жизни кэшированной информации о пользователе, полученной от ЕСИА. Используется, чтобы избежать повторных запросов к API ЕСИА в течение указанного периода.
    USERINFO_CLEAN_UPИнтервал времени, по прошествии сервис выполняет фоновую очистку устаревшей кэшированной информации о пользователях.
    SESSION_COOKIE_NAMEИмя HTTP cookie, используемой Adapter для хранения идентификатора сессии пользователя. 
    SESSION_COOKIE_LIFETIMEВремя жизни сессионной HTTP cookie в секундах. Определяет, как долго браузер пользователя будет хранить куку до ее автоматического удаления.
    SESSION_COOKIE_SECUREФлаг безопасности для сессионной cookie. При значении true cookie будет передаваться только по защищенному HTTPS-соединению.
    SESSION_EXPIREDВремя жизни серверной сессии пользователя в секундах. Определяет, через какое время неактивная сессия будет автоматически уничтожена на стороне сервера.
    CPROCSP_BIN_DIRПуть к директории, содержащей исполняемые файлы криптопровайдера КриптоПро CSP.
    NODEIDУникальный идентификатор экземпляра (ноды) адаптера. Используется для корректной работы внешней балансировки нагрузки ЕСИА Адаптера. Параметр (nid) передается внутри параметра state при формировании Authorization Code. В сценарии Authorization Code Flow код генерируется на одной ноде, и для его обмена на токен важно, чтобы запрос попал на ту же ноду. Параметр помогает обеспечить маршрутизацию последующих запросов от того же клиента на ту же ноду. 
    GEN_GUIDS_BIN_PATHПуть к бинарному файлу утилиты genguids. Указывается абсолютный путь к исполняемому файлу. Пример значения: /opt/avanpost/esia-adapter/genguids.
    GEN_GUIDS_BATCH_SIZEКоличество генерируемых идентификаторов за один вызов утилиты genguids. Определяет, сколько UUID будет сгенерировано при каждом обращении к утилите.
    GEN_GUIDS_SEPARATORРазделитель идентификаторов в выводе утилиты genguids. Определяет символ или последовательность символов, которыми разделяются сгенерированные UUID в потоке вывода. Пример значения: \r.
  5. Для автоматического запуска Avanpost ESIA IdP Adapter при загрузке системы необходимо зарегистрировать его как службу systemd:
    1. Создать конфигурационный файл службы при помощи команды:
      sudo vi /etc/systemd/system/esia-idp.service
    2. Настроить конфигурационный файл согласно примеру: 
      [Unit]
      Description=Avanpost ESIA IdP Adapter
      After=network.target
      
      [Service]
      WorkingDirectory=/opt/esia-idp
      ExecStart=/opt/esia-idp/esia-idp
      Restart=always
      RestartSec=10
      SyslogIdentifier=esia-idp
      User=esia-idp
      Environment="DEBUG=false"
      Environment="BASE_URL=https://esia-adapter.corp:4010"
      Environment="CPROCSP_BIN_DIR=/opt/cprocsp/bin/amd64"
      
      [Install]
      WantedBy=multi-user.target
    3. Выполнить команды:
      sudo systemctl daemon-reload
      sudo systemctl enable esia-idp
      sudo systemctl start esia-idp
  6. Убедиться, что пользователь корректно проходит аутентификацию в целевом OIDC-приложении посредством ЕСИА. 

Выпуск сертификата ЕСИА Адаптер

Для интеграции Avanpost FAM с Единой системой идентификации и аутентификации (ЕСИА) требуется:

  • Выпустить ГОСТ-совместимый сертификат в тестовом удостоверяющем центре (УЦ) КриптоПро;
  • Зарегистрировать сертификат в ЕСИА.

До начала работы с УЦ требуется выполнить следующие действия:

  1. Установить СКЗИ КриптоПро CSP;
  2. Установить КриптоПро ЭЦП Browser plug-in;
  3. Скачать и установить корневой сертификат тестового Удостоверяющего центра в хранилище Доверенные корневые центры сертификации;
  4. Скачать и установить промежуточный сертификат тестового Удостоверяющего центра в хранилище Промежуточные центры сертификации.

    Для работы с УЦ рекомендуется использовать браузер с поддержкой ГОСТ TLS, например: chromium-gost, Internet Explorer, Яндекс.Браузер, Microsoft Edge (в режиме Internet Explorer). Для работы браузеров отличных от IE, следует установить расширение для Chrome-подобных браузеров или Яндекс.Браузера.

Выпуск и регистрацию сертификата для ЕСИА Адаптера требуется выполнять следующим образом:

  1. Войти в УЦ:
    1. Допускается авторизоваться под учётной записью тестового пользователя:
      • Логин: avanpost-dev-2;
      • Пароль: 7705494692.
    2. Допускается зарегистрировать нового пользователя.
  2. Убедиться, что в профиле заполнены все обязательные поля для ЕСИА:
    • Общее имя;
    • Страна;
    • Область;
    • Город;
    • Адрес;
    • Организация;
    • ОГРН;
    • ИНН ЮЛ.

       Если вышеперечисленные поля не заполнены, сертификат не будет валиден для ЕСИА.

  3. Перейти в раздел "Сертификаты", нажать кнопку "Создать" и создать сертификат со следующими параметрами:
    ПараметрЗначение
    Шаблон сертификатаТестовый квалифицированный сертификат
    КриптопровайдерCrypto-Pro GOST R 34.10-2012 Cryptographic Service Provider
    Ключ будет использоваться дляВыбрать "Подписи и шифрования"
    Размер ключа512
    Алгоритм хешированияГОСТ Р 34.11-2012 256 бит
  4. Выпустить сертификат, используя в качестве хранилища ключа HDImage (директория).
  5. Открыть утилиту «Инструменты КриптоПро» (входит в состав CSP) и выбрать хранилище HDImage.
  6. Выбрать созданный сертификат и нажать кнопку «Экспортировать ключи».
  7. Выбрать «Экспортировать PXF в файл», указать пароль и сохранить файл.
  8. При помощи утилиты «Инструменты КриптоПро» экспортировать сертификат (без закрытого ключа) для регистрации в ЕСИА, нажав кнопку «Экспортировать сертификаты».
  9. Войти в тестовую ЕСИА:
    • Логин: EsiaTest031@yandex.ru;
    • Пароль: 11111111. 
  10. Найти зарегистрированную информационную систему (интерфейс позволяет выполнить поиск по названию или по мнемонике).
  11. Нажать для перехода в раздел управления сертификатами.
  12. Нажать кнопку «Загрузить сертификат» и указать путь до ранее созданного сертификата. 

Утилита для генерации GUID

Основным методом борьбы с CSRF-атаками является использование анти-CSRF токенов, (например, посредством генерации GUID). В сценариях аутентификации через ЕСИА параметр state используется для защиты от атак CSRF и обеспечения целостности сессии. Для генерации данного параметра реализована утилита genguids, обеспечивающая получение случайных значений на базе сертифицированного СКЗИ «КриптоПро CSP». При формировании авторизационного запроса к ЕСИА ESIA Adapter вызывает утилиту genguids. Утилита genguids генерирует UUID v4 (random-based) в соответствии с RFC 4122. Полученное значение используется как значение параметра state. Значение state сохраняется в сессии и впоследствии сверяется при получении ответа от ЕСИА.

Рекомендуется использовать утилиту genguids с ОС Astra Linux Special Edition, совместимой с КриптоПро CSP 5.0 R3.

При развертывании следует выполнить тестовый пуск утилиты в консоли на целевой системе:

  1. Выполнить проверку зависимостей связанных библиотек:
    ldd ./genguids
  2. Запустить утилиту, задав через пробел количество генерируемых значений (в приведенном примере 1): 
    ./genguids 1
  3. Убедиться в корректности результата:  вывод результата в формате UUID (пример: 5f39e5c2-ffc0-4b17-ac2a-3187339b02e4) и полученный код возврата 0.

    Значения кодов возврата:

    • 0 – успешное выполнение;
    • 1 – ошибка аргумента командной строки;
    • 2 – ошибка инициализации API КриптоПро CSP;
    • 3 – ошибка генерации случайных чисел.
  4. Для автоматического запуска genguids компонентом настроить переменные окружения GEN_GUIDS_BIN_PATH, GEN_GUIDS_BATCH_SIZE, GEN_GUIDS_SEPARATOR.

Приложение А. Пример настройки переменных окружения 

Ниже приведен пример конфигурирования Avanpost ESIA IdP Adapter при помощи переменных окружения:

{
  "DEBUG": "false",
  "BASE_URL": "http://localhost:4010",
  "HOST": "0.0.0.0",
  "PORT": 4010,
  "KEY": "key.pem",
  "KEY_ID": 1,
  "CLIENTS": "clients.json",
  "EXTIDP": "extidp.json",
  "EXTIDP_REQUEST_TTL": "1h",
  "EXTIDP_REQUEST_CLEAN_UP": "1h",
  "USERINFO_TTL": "1h",
  "USERINFO_CLEAN_UP": "1h",
  "SESSION_COOKIE_NAME": "sid",
  "SESSION_COOKIE_LIFETIME": 3600,
  "SESSION_COOKIE_SECURE": "true",
  "SESSION_EXPIRED": 3600,
  "CPROCSP_BIN_DIR": "/opt/cprocsp/bin/amd64"
}

Приложение Б. Пример файла clients.json

Пример JSON-файла, содержащего список доверенных OIDC-клиентов

[
  {
    "ID": "pkce-only-client",
    "Domain": "localhost:9094"
  },
  {
    "ID": "client-with-secret",
    "Secret": "test-secret",
    "Domain": "example.com"
  }
]

Приложение В. Пример конфигурационного файла внешнего провайдера идентификации

Пример JSON-файла, содержащего конфигурацию внешнего провайдера идентификации (ЕСИА). Допускается использовать файл из DevTools браузера (доступен при просмотре деталей настроенного внешнего IdP). 

Параметру synonym должно соответствовать значение esia.

{
  "id": "db2b0bcf-92d5-4ab7-805a-2c3e9f444d4e",
  "authorizeUri": "{{.extidp_details.baseUrl}}/aas/oauth2/ac",
  "redirectMethod": 0,
  "type": "esia",
  "name": "esia",
  "synonym": "esia",
  "typeDetails": " {\n    \"baseUrl\": \"https://esia-portal1.test.gosuslugi.ru\",\n    \"clientCertHash\": \"\",\n    \"clientID\": \"04QN02\",\n    \"cryptoProvider\": {\n      \"details\": {\n        \"certPath\": \"/Users/michael/Downloads/esia/esia/TESIA GOST 2012 new.cer\",\n        \"containerPIN\": \"123\",\n        \"sha1Thumbprint\": \"7f159ecf770dfb58489c7ad9ef45132b7e181092\"\n      },\n      \"name\": \"cprocsp_cms\"\n    },\n    \"scope\": \"openid fullname email mobile\",\n    \"scopeOrg\": \"\"\n  }",
  "redirectForm": {
    "response_type": "code",
    "client_id": "{{ .extidp_details.clientID }}",
    "redirect_uri": "{{ .extidp_request.CallbackURI }}",
    "scope": "{{ .extidp_details.scope }}",
    "scope_org": "{{ .extidp_details.scopeOrg }}",
    "client_secret": "{{ $ts := timeFormat \"2006.01.02 15:04:05 Z0700\" .process_started}}{{$clientSecretRaw := join .extidp_details.scope $ts .extidp_details.clientID .extidp_request.ID}}{{ cryptoSign .context $clientSecretRaw .extidp_details.cryptoProvider | base64 }}",
    "client_certificate_hash": "{{ .extidp_details.clientCertHash }}",
    "timestamp": "{{ timeFormat \"2006.01.02 15:04:05 Z0700\" .process_started }}",
    "state": "{{ .extidp_request.ID }}",
    "access_type": "offline"
  },
  "userInfoPipeline": [
    {
      "t": 0,
      "r": "token",
      "d": {
        "client_certificate_hash": "{{.extidp_details.clientCertHash}}",
        "client_id": "{{.extidp_details.clientID}}",
        "client_secret": "{{$ts := timeFormat \"2006.01.02 15:04:05 Z0700\" .process_started}}{{$clientSecretRaw := join .extidp_details.scope $ts .extidp_details.clientID .extidp_request.ID}}{{ cryptoSign .context $clientSecretRaw .extidp_details.cryptoProvider | base64 }}",
        "code": "{{.code}}",
        "grant_type": "authorization_code",
        "redirect_uri": "{{.extidp_request.CallbackURI}}",
        "scope": "{{.extidp_details.scope}}",
        "state": "{{.extidp_request.ID}}",
        "timestamp": "{{timeFormat \"2006.01.02 15:04:05 Z0700\" .process_started}}",
        "token_type": "Bearer"
      },
      "m": "POST",
      "u": "{{.extidp_details.baseUrl}}/aas/oauth2/te"
    },
    {
      "t": 1,
      "d": {
        "verify_id_token": "{{ cryptoVerifyJWT .context .token.id_token .extidp_details.cryptoProvider }}"
      }
    },
    {
      "t": 2,
      "d": {
        "id_token_claims": "jwt(token.id_token)"
      }
    },
    {
      "t": 1,
      "d": {
        "is_trusted": "{{ with index .id_token_claims \"urn:esia:sbj\" \"urn:esia:sbj:is_tru\" }}{{ if not . }}{{ fail \"user is not trusted\" }}{{ end }}{{ end }}"
      }
    },
    {
      "t": 0,
      "r": "person",
      "m": "GET",
      "u": "{{.extidp_details.baseUrl}}/rs/prns/{{printf \"%.0f\" .id_token_claims.sub}}",
      "h": {
        "Authorization": "Bearer {{.token.access_token}}"
      }
    },
    {
      "t": 0,
      "r": "contacts",
      "d": {
        "embed": "(elements)"
      },
      "m": "GET",
      "u": "{{.extidp_details.baseUrl}}/rs/prns/{{printf \"%.0f\" .id_token_claims.sub}}/ctts",
      "h": {
        "Authorization": "Bearer {{.token.access_token}}"
      }
    },
    {
      "t": 2,
      "d": {
        "main_email": "email = \"\"; for (i = 0; i < contacts.elements.length; i++) {if (contacts.elements[i].type === \"EML\" && contacts.elements[i].vrfStu === \"VERIFIED\") {email = contacts.elements[i].value}} email;",
        "main_phone": "phone = \"\"; for (i = 0; i < contacts.elements.length; i++) {if (contacts.elements[i].type === \"MBT\" && contacts.elements[i].vrfStu === \"VERIFIED\") {phone = contacts.elements[i].value}} phone;"
      }
    }
  ],
  "attrMapping": {
    "fn": "{{.person.firstName}}",
    "ln": "{{.person.lastName}}",
    "mn": "{{.person.middleName}}",
    "un": "",
    "e": "{{.main_email}}",
    "p": "{{.main_phone}}",
    "l": "",
    "xid": "",
    "rid": "state",
    "x": {
      "snils": "{{.snils}}"
    }
  },
  "isActive": true
}

Приложение Г. Список эндпоинтов ЕСИА Адаптер 

ЭндпоинтОписание
/oauth2/authorize Запрос аутентификации.
/oauth2/tokenЗапрос токена.
/oauth2/logoutЗапрос выхода из системы.
/oauth2/userinfoВозврат JSON с информацией о пользователе, идентичный данным в id_token (используется для старых версий клиентов, подключаемых к ESIA Adapter).
/extidp/esiaЗапрос перенаправления в ЕСИА.
/extidp/esia/callbackОбработка перенаправления от ЕСИА.
/extidp/esia/logoutЗапрос перенаправления в ЕСИА для выхода.
/health/live

Проверка, что адаптер запущен и отвечает на запросы:

  • 200 OK – Адаптер запущен и работает;
  • 503 Service Unavailable – Адаптер не отвечает.
/health/ready

Проверка готовности адаптера к обработке запросов:

  • 200 OK – Адаптер готов к работе (тестовая подпись выполнена успешно);
  • 503 Service Unavailable - Адаптер не готов (ошибка инициализации КриптоПро CSP или конфигурации).



Обсуждение