- Авторизация с помощью сертификата ssl на nginx let’s encrypt
- Для кого это актуально и некоторые исходные данные
- Использовать образы со вшитыми сертификатами
- Конфигурирование openssl
- Монтирование с хостов
- Настройка acme-dns сервера и процесс выпуска сертификата
- Об авторе
- Обновление сертификатов цс
- Общий план развёртывания
- Отступление про сборку docker-образов
- Пайплайны
- Подготовка веб-сервера
- Поиск подключенных устройств
- Полезные ссылки
- Получать сертификаты из первоисточника
- Получение информации об устройстве
- Предварительная конфигурация
- Предустановочная конфигурация
- Прочие настройки
- Работа с ключевыми парами гост р 34.10-2001
- Работа с сертификатами
- Расшифрование данных, полученных с сервера, на клиенте
- Резервное копирование
- Рекомендации
- Сертификат выдается при регистрации в системе
- Сертификат уже имеется на токене, выдан внешним уц
- Скрипт настройки
- Словарь терминов
- Смена pin-кода
- Строгая аутентификация на портале
- Установка издающего цс
- Установка компонента цс
- Установка корневого цс
- Шаблоны сертификатов
- Шифрование данных на клиенте для сервера
- Итоговая настройка
Авторизация с помощью сертификата ssl на nginx let’s encrypt
Добрый день, вечер или ночь, все зависит от времени суток в который вам довелось прочитать мою статью.
В связи с ростом количества корпоративных клиентов, было принято решение дать доступ к учетной системе внешним пользователям. Для самостоятельного оформления заказов и отслеживания их состояний. Реализация была создан web интерфейс с необходимым функционалом и доступом. Тут же стал вопрос безопасности, кроме стандартных пользователь-пароль было решено еще усилить безопасность, для этого применили OpenVPN, но появились клиенты, для которых нельзя применять OpenVPN (политики безопасности, нежелания и.д.), тут на глаза попались статьи про доступ по ssl сертификату.

Исходные данные:
Сервер с учетной программой web интерфейс находятся в DMZ;
WEB-server на nginx, на него проброшены порты http(80) и https(443);
На web-server настроен proxy_pass на сервер с учетной программой, доступ только по порту 8080 и только с IP web-server, большего доступа с серверу нет(обычная безопасность);
На сайт для доступа установлен сертификат от Let’s Encrypt.
Переходим к самому процессу создания сертификата пользователя:
Для сертификатов будем использовать каталог “/etc/ssl/crm.example.ru”
Создаём структуру каталогов:
# mkdir /etc/ssl/crm.example.ru
# cd /etc/ssl/crm.example.ru
# mkdir db
# mkdir db/certs
# mkdir db/newcerts
# touch db/index.txt
# echo "01" > db/serial
# chmod 700 ./
Создаем конфигурационный файл для подписи сертификатов.
/etc/ssl/crm.example.ru/ca.conf”
[ ca ]
default_ca = CA_CITENAME # Секция по умолчанию для подписи сертификатов
[ CA_CITENAME ]
droot = /etc/ssl/crm.example.ru # Корневой каталог хранилища
dir = $droot/db # Каталог базы хранилища
certs = $dir/certs # Каталог сертификатов
new_certs_dir = $dir/newcerts # Каталог для новых сертификатов (pem)
database = $dir/index.txt # Файл базы сертификатов
serial = $dir/serial # Файл серийного номера
# Файл доверенного сертификата
certificate = $droot/ca.crt
# Закрытый ключ доверенного сертификата
private_key = $droot/ca.key
default_days = 365 # Срок действия нового сертификата (дни)
default_crl_days = 7 # Срок действия списка отозванных сертификатов
default_md = md5 # Использовать алгоритм MD5
policy = policy_citename # Политика секции
[ policy_citename ]
countryName = optional # Необязательный параметр
stateOrProvinceName = optional # .......................
localityName = optional # .......................
organizationName = optional # .......................
organizationalUnitName = optional # .......................
commonName = supplied # обязательный параметр
emailAddress = supplied # .....................
[ req_distinguished_name ]
countryName = Название страны (2-буквенный код)
countryName_default = RU
countryName_min = 2
countryName_max = 2
stateOrProvinceName = Название области (полное название)
stateOrProvinceName_default = Tyumen region
localityName = Название местности (например, город)
localityName_default = Tyumen
0.organizationName = Название организации
0.organizationName_default = EXAMPLE
organizationalUnitName = Название организационной единицы (например, отдел)
commonName = Ваше имя
commonName_max = 64
emailAddress = Email адрес
emailAddress_max = 64
Создаем самоподписанный сертификат и новый ключ сервера без пароля:
# openssl req -new -newkey rsa:2048 -nodes -keyout ca.key -x509 -days 365
-subj "/C=RU/ST=Tyumen region/L=Tyumen/O=EXAMPLE/OU=CRM/CN=crm.example.ru/emailAddress=crm@example.ru"
-out ca.crtЛибо, если хотите всё вводить вручную.
# openssl req -new -newkey rsa:2048 -nodes -keyout ca.key -x509 -days 365 -out ca.crtПросмотреть данные закрытого ключа и сертификата вы можете с помощью команд:
# openssl rsa -noout -text -in ca.key (для ключа)
# openssl x509 -noout -text -in ca.crt (для сертификата)
Создание клиентского закрытого ключа и запроса на сертификат (CSR):
# openssl req -new -newkey rsa:2048 -nodes -keyout client01.key
-subj "/C=RU/ST=Tyumen region/L=Tyumen/O=EXAMPLE/OU=CRM/CN=User example1/emailAddress=user@example1.ru"
-out client01.csr
Либо, если хотите всё вводить вручную.
#openssl req -new -newkey rsa:2048 -nodes -keyout client01.key -out client01.csr
Заместо User example1 можно указать почту клиента, а за место EXAMPLE компанию клиента, это поможет отслеживать сертификаты.
В результате выполнения команды появятся два файла client01.key и client01.csr. Просмотреть данные закрытого ключа и запроса на сертификат (CSR) вы можете с помощью команд:
# openssl rsa -noout -text -in client01.key (для ключа)
# openssl req -noout -text -in client01.csr (для запроса)
Подпись запроса на сертификат (CSR) с помощью доверенного сертификата (CA). При подписи запроса используются параметры заданные в файле ca.config
# openssl ca -config ca.config -in client01.csr -out client01.crt -batch
Подготовка данных для передачи клиенту. Для передачи полученных в результате предыдущих операций файлов клиенту, обычно используется файл в формате PKCS#12. В этот файл упаковывается и защищается паролем вся информация необходимая клиенту для инсталляции сертификата в броузер.
# openssl pkcs12 -export -in client01.crt -inkey client01.key
-certfile ca.crt -out client01.p12 -passout pass:123ewqasdcxz
Выставляем права доступа на ключи.
# chmod 600 /etc/ssl/crm.example.ru/client*.crt
# chmod 600 /etc/ssl/crm.example.ru/client*.key
Переместим все созданные файлы в каталог db/certs на хранение.
# mv ./client01.* db/certs/
В nginx надо установить:
ssl_client_certificate /etc/ssl/crm.example.ru/ca.crt;
ssl_verify_client on;
ssl_verify_depth 1;
Для того чтобы клиент смог подключиться по сертификату ему необходимо отправить файл client01.p12 и ca.crt, а так же сообщить пароль для установки сертификата. ca.crt необходим, так как мы не используем его для сертификации сервера, для этомо используеться Let’s Encrypt.
Процесс выдачи сертификатов можно автоматизировать, написать просто скрипт не составит труда. У нас таких клиентов не много, около 15, так что вбить всё руками не составило проблем.
Мой рабочий пример:
Окно выбора сертификата:

Сам сертификат:

Работоспособность Let’s Encrypt:

В подготовке материала помогли статьи:
→ «Авторизация клиентов в nginx посредством SSL сертификатов»
→ «Авторизация по SSL сертификатам»
→ «Авторизация с помощью клиентских SSL сертификатов. (ssl crypt mod_ssl apache)»
→ «Великий и могучий Google»
P.S. Проверка проводилась на Google Chrome.
Для кого это актуально и некоторые исходные данные
Компания К в лице автора. URL (для примера): company.tld
Проект X — один из наших проектов, занимаясь которым я пришел к выводу что все таки нужно двигаться в сторону максимальной экономии времени при работе с сертификатами. У этого проекта есть четыре окружения: dev, test, staging и production. Dev и test находятся на нашей стороне, staging и production на клиентской.
Особенностью проекта является то, что у него есть большое количество модулей, которые доступны как поддомены.
То-есть, имеем следующую картину:
Для production используется купленный wildcard сертификат, тут вопросов не возникает. Но он покрывает только первый уровень поддомена. Соответственно, если есть сертификат для *.projectX.tld — то для staging.projectX.tld он работать будет, а вот для module1.staging.projectX.tld уже нет. А покупать отдельный как-то не хочется.
И это только на примере одного проекта одной компании. А проект, естественно, не один.
Общие для всех причины заняться решением этого вопроса выглядят примерно так:
Использовать образы со вшитыми сертификатами
Рано или поздно многие компании обнаруживают потребность контролировать свою инфраструктуру. Админам надоедает отвечать на одинаковые вопросы разработчиков («почему у меня не качает с гитхаба?, «что значит x509?»), безопасникам надоедает наблюдать за тем, как все докер-файлы начинаются со строчки FROM vasyapupkin/zvercd, а разработчикам надоедает решать головоломки с изменчивыми промежуточными сертификатами и прочими вещами вне их области экспертизы. Тогда ответственные за платформу идут и пишут много-много докер-файлов наподобие такого:
Конфигурирование openssl
Openssl поддерживает российские криптоалгоритмы, начиная с версии 1.0. Для того, чтобы их использовать, в openssl требуется подгружать engine gost. В большинстве дистрибутивов openssl эта библиотека присутствует. Чтобы engine подгружалась, можно прописать ее в конфигурационном файле openssl:
[openssl_def]
engines = engine_section
[engine_section]
gost = gost_section
[gost_section]
engine_id = gost
default_algorithms = ALL
Если конфигурационный файл openssl не расположен в стандартном месте, то путь к нему можно задать через переменную окружения OPENSSL_CONF.
Другим вариантом подгрузки engine gost является ее передача в параметрах командной строки утилиты openssl.
Если engine gost не расположена в стандартном месте, то через переменную окружения OPENSSL_ENGINES можно задать путь к директории, в которой openssl будет ее искать.
Для получения информации о том, успешен ли был вызов утилиты openssl или нет, с возможностью уточнения ошибки, требуется парсить stdout и stderror. В конце статьи приведена ссылка на PHP-скрипт, который использует данную утилиту.
Теперь перейдем к реализации законченных пользовательских сценариев.
Монтирование с хостов
Если прописать в config.toml
[[runners]]
executor = "kubernetes"
(...)
[runners.kubernetes]
(...)
[runners.kubernetes.volumes]
[[runners.kubernetes.volumes.host_path]]
host_path = "/usr/local/share/ca-certificates"
mount_path = "/usr/local/share/ca-certificates"
name = "certs-volume"
read_only = trueто сертификаты будут монтироваться в основные и сервисные контейнеры запускаемых джобов. В случае с докер-экзекьютором аналогичный результат можно получить так:
[runners.docker]
(...)
volumes = ["/usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro"]Минус подхода в том, что ответственность за актуальность сертификатов сдвигается на конфигурацию инфраструктуры, поэтому подход удобен, если вы этой инфраструктурой управляете. Если же вы, например, работаете в отдельной команде, которая в многопользовательском кластере Kubernetes сама подняла свой раннер, но не имеет админского доступа туда, вы не можете быть уверены в актуальности сертификатов на хосте, да и можете вовсе не иметь прав на монтирование hostPath.
kubectl create secret generic -n runner-namespace certs --from-file=/usr/local/share/ca-certificatesа config.toml исправить следующим образом:
[[runners]]
executor = "kubernetes"
(...)
[runners.kubernetes]
(...)
[runners.kubernetes.volumes]
[[runners.kubernetes.volumes.secret]]
name = "certs"
mount_path = "/usr/local/share/ca-certificates"
read_only = trueЕсли используется докер-экзекьютор на недоступном вам build-сервере, из этого тут же следует, что у вас нет доступа к конфигурации раннера, если только не используется экзотичный вариант подключения к сокету докер-демона по tcp (подобный доступ почти всегда означает, что и доступ к хосту получить тривиально).
Один из плюсов такого подхода в том, что можно делать следующее:
build:
stage: build
image: docker:stable
services:
- name: docker:18.09.6-dind
entrypoint:
- /bin/sh
command:
- -c
- update-ca-certificates && dockerd-entrypoint.shКлючевой шаг, естественно, update-ca-certificates.
Поскольку для сервисных контейнеров нельзя прописать последовательность команд аналогично script, а писать длинные скрипты для установки сертификатов под ключом command не очень удобно, меньшим из зол является подобное монтирование сертификатов и сравнительно короткая последовательность команд.
Настройка acme-dns сервера и процесс выпуска сертификата
Для примера, я создал домен 2nd.pp.ua, и в дальнейшем буду использовать его.
Обязательным требованием для корректной работы сервера является создание NS и А записи для его домена. И первый неприятный момент с которым я столкнулся — cloudflare (по крайней мере в режиме бесплатного использования) не позволяет одновременно создать NS и A запись для одного и того же хоста.
acmens.2nd.pp.ua. IN A 35.237.128.147
acme.2nd.pp.ua. IN NS acmens.2nd.pp.ua.На данном этапе у нас должен резолвиться хост acmens.2nd.pp.ua.
$ ping acmens.2nd.pp.ua
PING acmens.2nd.pp.ua (35.237.128.147) 56(84) bytes of dataА вот acme.2nd.pp.ua резолвиться не будет, так как DNS сервер который его обслуживает еще не запущен.
Записи созданы, переходим к настройке и запуску ACME-DNS сервера. Жить он у меня будет на ubuntu server в docker контейнере, но запустить его можно везде где есть golang. Windows тоже вполне подойдет, но я все же предпочитаю Linux сервер.
Создаем необходимые директории и файлы:
$ mkdir config
$ mkdir data
$ touch config/config.cfgВоспользуемся
vim
вашим любимым текстовым редактором и вставим в config.cfg образец
Для успешной работы достаточно подправить секции general и api:
Об авторе
Вадим Поданс
— специалист в области автоматизации PowerShell и Public Key Infrastructure, Microsoft MVP: Cloud and Datacenter Management с 2009 года и автор модуля PowerShell PKI. На протяжении 9 лет в своём блоге освещает различные вопросы эксплуатации и автоматизации PKI на предприятии. Статьи Вадима о PKI и PowerShell можно найти на его
Обновление сертификатов цс
Периодически необходимо обновлять сертификаты ЦС. Рассмотрим несколько аспектов, связанных с обновлением сертификатов ЦС.
Периодичность обновления сертификата ЦС
Это делается в следующих случаях:
Первый вопрос, если всё идёт штатно, за какое время до истечения срока действия сертификата ЦС его нужно обновлять?
Сертификат издающего ЦС должен обновляться за максимальный срок действия издаваемых сертификатов. В нашем случае срок действия сертификата издающего ЦС 15 лет, а максимальный срок действия издаваемых сертификатов 5 лет (см. конфигурационную таблицу).
Порядок обновления ЦС
В нашей двухуровневой иерархии сертификаты корневого и издающего ЦС имеют одинаковый срок действия. Поэтому, когда вы принимаете решение об обновлении сертификата любого ЦС, необходимо обновлять их вместе. Первым обновляется сертификат корневого ЦС, затем сертификат издающего ЦС.
Генерация ключей при обновлении сертификатов ЦС
При обновлении сертификатов ЦС вам предлагается две опции: использовать существующую ключевую пару или сгенерировать новую:
В диалоговом окне обновления ключевой пары приведены рекомендации Microsoft по выбору ключевой пары. Однако, практика показывает, что эти рекомендации устарели. Следует всегда генерировать новую ключевую пару. При использовании нескольких сертификатов ЦС клиентский модуль построения цепочки сертификатов иногда может ошибиться и выбрать неправильный сертификат. В базе знаний Microsoft отмечены такие проблемы. Примеры статей:
При генерации новой ключевой пары для каждого сертификата будет гарантирован только один путь к корневому сертификату и модуль построения цепочек сертификатов уже не ошибётся.
Общий план развёртывания
Для развёртывания службы сертификатов нам потребуется четыре машины с Windows Server 2021, которые будут выполнять следующие функции:
- Контроллер домена — необходим для функционирования домена Active Directory;
- Веб-сервер — будет обеспечивать доступ к сертификатам ЦС и спискам отзывов для клиентов;
- Корневой ЦС — будет выполнять функции корневого ЦС;
- Подчинённый ЦС — будет выполнять функции издающего ЦС.
Развёртывание PKI будет проходить поэтапно на каждом сервере в том порядке, в котором они указаны выше. Подготовка контроллера домена будет сводиться к обеспечению функций Active Directory, GPO и учётных записей.
Отступление про сборку docker-образов
Если вы в пайплайнах собираете докер-образы, то, независимо от того, используется docker-in-docker, kaniko или другой сборщик в пайплайне, в контексте сборки сертификаты снова отсутствуют, если их не вшили в базовый образ. Предположим, что каким-либо образом в контейнер пайплайна сертификаты были доставлены (либо примонтированы с хоста, либо получены из другого источника командами в before_script). Тогда конфигурация пайплайнов должна будет выглядеть так:
build:
stage: build
# допустим, сборка докером
image: docker:stable
services:
- name: docker:18.09.6-dind
entrypoint:
- /bin/sh
command:
- -c
- update-ca-certificates && dockerd-entrypoint.sh
# before_script:
# - script_to_get_certs.sh
script:
- mkdir -p certs
- cp /usr/local/share/ca-certificates/* certs/
- docker build (...) # или канико или что угодно ещё
- (...)а в докер-файлах придётся всегда указывать что-нибудь вроде
Пайплайны
Действия выше выполняются относительно редко, однако если используется Docker или Kubernetes экзекьютор, то каждый джоб будет выполняться в свежесозданном контейнере, в котором снова нет нужных сертификатов. Поэтому необходим способ динамически доставлять сертификаты в контейнеры. Есть несколько таких способов:
Подготовка веб-сервера
На веб-сервере нам потребуется выполнить следующее: установить службу IIS (если ещё не установлена), создать общую папку и сконфигурировать веб-сайт на использование этой папки.
Для установки службы IIS можно воспользоваться следующей командой:
Install-WindowsFeature -Name Web-Server, Web-WebServer -IncludeManagementToolsСогласно нашей конфигурационной таблице (см. часть 2), для хранения сертификатов ЦС и списков отзыва нам потребуется общая папка с сетевым именем PKI по следующему пути: C:InetPubwwwrootPKIdata
New-Item -ItemType Directory -Path C:InetPubwwwroot -Name PKIdata -Force
New-SmbShare -Path C:inetpubwwwrootPKIdata -Name PKI -FullAccess everyoneПосле этого нужно выдать права NTFS на запись в эту папку для группы Cert Publishers.
Поиск подключенных устройств
Любой клиентский сценарий начинается с поиска подключенных к компьютеру USB-устройств Рутокен. В контексте данной статьи акцент делается на устройство Рутокен ЭЦП.
var devices = Array();
try
{
devices = plugin.enumerateDevices();
}
catch (error)
{
console.log(error);
}
При этом возвращается список идентификаторов подключенных устройств. Идентификатор представляет собой число, связанное с номером слота, к которому подключено устройство. При повторном перечислении это число может отличаться для одного и того же устройства.
Рутокен Плагин определяет все подключенные к компьютеру USВ-устройства Рутокен ЭЦП, Рутокен PINPad, Рутокен WEB. Поэтому следующим шагом следует определить тип устройства.
Полезные ссылки
Данные ссылки могут быть полезны разработчикам инфосистем с поддержкой ЭЦП на базе Рутокен Плагин и openssl:
Демосистема Рутокен ПлагинWEB-сервис генерации ключей, формирования запросов, управления сертификатами, формирования шаблонов запросов на сертификаты Документация на Рутокен ПлагинДокументация по использованию утилиты openssl с российскими крипталгоритмамиПример скрипта на PHP, использующего утилиту openssl
Получать сертификаты из первоисточника
Если источник корневых сертификатов предоставляет удобный API для их получения, можно не утруждать себя хранением сертификатов на своих серверах с последующим монтированием в пайплайны. Допустим, корневой сертификат можно получить командой
Получение информации об устройстве
Для определения типа устройства следует использовать функцию
с параметром TOKEN_INFO_DEVICE_TYPE. Значение этой константы содержится в объекте плагина.
var type;
try
{
type = plugin.getDeviceInfo(deviceId, plugin.TOKEN_INFO_DEVICE_TYPE);
}
catch (error)
{
console.log(error);
}
switch (type)
{
case plugin.TOKEN_TYPE_UNKNOWN:
message = "Неизвестное устройство";
break;
case plugin.TOKEN_TYPE_RUTOKEN_ECP:
message = "Рутокен ЭЦП";
break;
case plugin.TOKEN_TYPE_RUTOKEN_WEB:
message = "Рутокен Web";
break;
case plugin.TOKEN_TYPE_RUTOKEN_PINPAD_2:
message = "Рутокен PINPad";
break;
}
Также с помощью функции getDeviceInfo можно получить:
Предварительная конфигурация
Предварительные конфигурационные файлы необходимы для ряда настроек, которые невозможно задать во время установки компонента (ни при помощи графического интерфейса, ни при помощи командной строки или PowerShell). К ним обычно относятся настройки расширений сертификата ЦС.
Например, для настройки расширения сертификата Certificate Policies, необходимо использовать предварительный конфигурационный файл, в котором настраиваются параметры расширения. Для Microsoft ADCS таким файлом является файл CAPolicy.inf, который должен быть расположен по следующему пути: %windir%CAPolicy.inf. С синтаксисом этого файла можно ознакомиться в следующей статье:
. Поскольку никаких специфичных или нестандартных настроек в сертификате корневого ЦС мы делать не будем, поэтому и предварительный конфигурационный файл сейчас нам не потребуется.
Предустановочная конфигурация
Если для корневого ЦС предустановочный конфигурационный файл нам не требовался, то для издающего ЦС он понадобится. В нём мы настроим расширения Certificate Policies и Basic Constraints для сертификата ЦС. Если с политиками всё понятно, то в расширении Basic Constraints мы запретим выдачу сертификатов другим ЦС с издающего ЦС, поскольку у нас двухуровневая иерархия и добавление новых уровней только усложняет нашу структуру и увеличивает время, затрачиваемое на проверку сертификатов клиентами.
- Контроллеры домена практически мгновенно обнаруживают появление ЦС в лесу и даже при отключённой политике автоматической выдачи сами запрашивают себе сертификаты.
- Администраторы сами должны определять какие шаблоны будут использовать в организации.
Поэтому мы сконфигурируем ЦС так, что список шаблонов к выдаче будет пустым. Это возможно сделать только через CAPolicy.inf. В нашем случае он будет иметь следующее содержимое:
Прочие настройки
После того как издающий ЦС установлен и сконфигурирован, убедитесь, что всё прошло без ошибок:
Когда основные параметры проверены, необходимо убедиться в правильной связи иерархии ЦС и доступности всех внешних файлов для клиентов. Для этого на сервере ЦС (а лучше, на рабочей станции, где установлены средства удалённого администрирования ЦС) необходимо запустить оснастку
Enterprise PKI Health
(pkiview.msc). Оснастка автоматически построит текущую иерархию и проверит доступность всех путей для скачивания сертификатов ЦС и списков отзыва. Никаких ошибок быть не должно. Если есть ошибка, необходимо её точно идентифицировать и устранить. В случае успешной настройки оснастка будет выглядеть следующим образом для корневого ЦС:
И для издющего ЦС:
Если вся итоговая конфигурация соответствует ожидаемым значениям и оснастка Enterprise PKI Health не показывает ошибок, это может судить о том, что PKI установлена верно.
Работа с ключевыми парами гост р 34.10-2001
1. Для получения декрипторов ключевых пар, хранящихся на устройстве, требуется ввод PIN-кода. Следует понимать, что само значение закрытого ключ получено быть не может, так как ключ является неизвлекаемым.
var keys = Array();
try
{
plugin.login(deviceId, "12345678");
keys = plugin.enumerateKeys(deviceId, null);
}
catch (error)
{
console.log(error);
}
2. Для генерации ключевой пары требуется ввод PIN-кода. При генерации ключа параметры могут быть выбраны из набора:
Пример генерации ключевой пары ГОСТ Р 34.10-2001:
var options = {};
var keyId;
try
{
keyId = plugin.generateKeyPair(deviceId, "A", null, options);
}
catch (error)
{
console.log(error);
}
3. С помощью функции deleteKeyPair ключевая пара может быть удалена с токена.
Работа с сертификатами
1. На токене могут храниться 3 категории сертификатов:
Расшифрование данных, полученных с сервера, на клиенте
Для расшифрования данных, полученных с сервера, предназначена функция cmsDecrypt. Так как сервер шифрует для клиента, используя его сертификат, то в качестве keyId должен быть передан дескриптор закрытого ключа клиента, соответствующий открытому ключу в сертификате.
Этот дескриптор является уникальным и неизменным и потому может быть сохранен в учетной записи пользователя на сервере. Кроме того, дескриптор ключа пользователя может быть получен явным образом, путем вызова функции getKeyByCertificate.
Шифрование данных на сервере для клиента:
Резервное копирование
Вопросы резервного копирования и восстановления после отказа являются отдельной темой. Здесь я лишь отмечу основные моменты, которые следует учесть при планировании стратегии резервного копирования.
Microsoft Active Directory Certificate Services предоставляет инструменты для резервного копирования компонентов ЦС:
С ними можно сделать резервную копию для ключевой пары ЦС и базы данных. Однако эти инструменты не позволяют делать резервную копию настроек ЦС. Эти операции необходимо выполнять вручную. Все настройки ЦС находятся в реестре по следующему пути:
HKLMSystemCurrentControlSetServicesCertSvcПри резервном копировании всегда экспортируйте данную ветку реестра. При восстановлении ЦС сохранённый REG файл импортируется обратно в реестр после установки роли ЦС.
Полный список элементов ЦС, который подлежит обязательному резервному копированию выглядит так:
Этот список не зависит от принятой в вашей компании стратегии резервного копирования, он всегда должен быть включён в список резервных копий.
Рекомендации
После того, как все ЦС установлены, сконфигурированы и их работоспособность проверена, можно приступать к их эксплуатации. В этом разделе я дам несколько полезных рекомендаций, которых следует придерживаться, чтобы предостеречь себя от возможных потенциальных проблем во время эксплуатации PKI.
Сертификат выдается при регистрации в системе
Последовательность вызовов в клиентском скрипте будет следующей:
Далее запрос отправляется на сервер, где на его основе выдается сертификат.Для этого на сервере должен быть установлен и правильно сконфигурирован openssl версии от 1.0 и развернут функционал УЦ.
1. Генерация улюча УЦ:
openssl genpkey -engine gost -algorithm GOST2001 -pkeyopt paramset:A -out ca.key
После этого в файле ca.key будет создан закрытый ключ
2. Создание самоподписанного сертификата УЦ:
openssl req -engine gost -x509 -new -key ca.key -out ca.crt
После ввода необходимой информации об издателе в файле ca.crt будет создан сертификат УЦ.
Сертификат уже имеется на токене, выдан внешним уц
Ключевая пара при этом должна быть создана в формате, совместимом с библиотекой rtPKCS11ECP для Рутокен ЭЦП.
Последовательность вызовов на клиенте:
Подпись получается в base64-формате. При проверке ее на сервере с помощью openssl подпись следует обрамить заголовками, чтобы сделать из нее PEM. Выглядеть подобная подпись будет примерно так:
-----BEGIN CMS-----
MIIDUQYJKoZIhvcNAQcCoIIDQjCCAz4CAQExDDAKBgYqhQMCAgkFADCBygYJKoZI
hvcNAQcBoIG8BIG5PCFQSU5QQURGSUxFIFVURjg PFY 0JLRi9C/0L7Qu9C90LjR
gtGMINCw0YPRgtC10L3RgtC40YTQuNC60LDRhtC40Y4/PCE c2VydmVyLXJhbmRv
bS1kYXRhZTI6ZGE6MmM6MDU6MGI6MzY6MjU6MzQ6YzM6NDk6Nzk6Mzk6YmI6MmY6
YzU6Mzc6ZGI6MzA6MTQ6NDQ6ODM6NjY6Njk6NmI6OWY6YTU6MDk6MzQ6YmY6YzQ6
NzY6YzmgggGeMIIBmjCCAUegAwIBAgIBATAKBgYqhQMCAgMFADBUMQswCQYDVQQG
EwJSVTEPMA0GA1UEBxMGTW9zY293MSIwIAYDVQQKFBlPT08gIkdhcmFudC1QYXJr
LVRlbGVjb20iMRAwDgYDVQQDEwdUZXN0IENBMB4XDTE0MTIyMjE2NTEyNVoXDTE1
MTIyMjE2NTEyNVowEDEOMAwGA1UEAxMFZmZmZmYwYzAcBgYqhQMCAhMwEgYHKoUD
AgIjAQYHKoUDAgIeAQNDAARADKA/O1Zw50PzMpcNkWnW39mAJcTehAhkQ2Vg7bHk
IwIdf7zPe2PxHyAr6lH stqdACK6sFYmkZ58cBjzL0WBwaNEMEIwJQYDVR0lBB4w
HAYIKwYBBQUHAwIGCCsGAQUFBwMEBgYpAQEBAQIwCwYDVR0PBAQDAgKkMAwGA1Ud
EwEB/wQCMAAwCgYGKoUDAgIDBQADQQD5TY55KbwADGKJRK bwCGZw24sdIyayIX5
dn9hrKkNrZsWdetWY3KJFylSulykS/dfJ871IT 8dXPU5A7WqG4 MYG7MIG4AgEB
MFkwVDELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEiMCAGA1UEChQZT09P
ICJHYXJhbnQtUGFyay1UZWxlY29tIjEQMA4GA1UEAxMHVGVzdCBDQQIBATAKBgYq
hQMCAgkFADAKBgYqhQMCAhMFAARAco5PumEfUYVcLMb1cnzETNOuWC8Goda8pdUL
W5ASK tztCwM7wpXgAy Y6/sLtClO9sh8dKnAaEY2Yavg3altQ==
-----END CMS-----
Проверка подписи на сервере:
Скрипт настройки
Для конфигурирования настроек ЦС мы будем использовать BATCH скрипт с использованием утилиты certutil.exe:
Словарь терминов
В этой части серии использованы следующие сокращения и аббревиатуры:
Смена pin-кода
Пример смены PIN-кода на устройстве:
var options = {};
try
{
plugin.changePin(deviceId, "12345678", "12345671", options);
}
catch (error)
{
console.log(error);
}
Здесь первым параметром выступает старый PIN-код, а вторым новый PIN-код.
Строгая аутентификация на портале
Общая схема аутентификации, используемая в Рутокен Плагин, выглядит следующим образом:
Реализация данной схемы ничем принципиально не отличается от «Регистрация, сертификат уже имеется, выдан внешним УЦ».
Установка издающего цс
Как и в случае с корневым ЦС, установка издающего ЦС включает в себя четыре этапа:
- Подготовка предустановочных конфигурационных файлов (CAPolicy.inf);
- Установка компонента ЦС;
- Выполнение постустановочной конфигурации;
- Проверка установки и конфигурации.
Установка компонента цс
Прежде всего необходимо добавить установочные компоненты для AD CS:
Install-WindowsFeature AD-Certificate, ADCS-Cert-Authority -IncludeManagementToolsПосле этого посмотрим на установочную таблицу, чтобы определить параметры установки:
В таблице я выделил только те параметры, которые задаются в процессе установки. Остальные параметры будут настраиваться после установки. Исходя из этих данных сформируем параметры для командлета
Install-AdcsCertificationAuthority -CACommonName "Contoso Lab Issuing Certification authority" `
-CADistinguishedNameSuffix "OU=Division Of IT, O=Contoso Pharmaceuticals, C=US" `
-CAType EnterpriseSubordinateCa `
-CryptoProviderName "RSA#Microsoft Software Key Storage Provider" `
-KeyLength 4096 `
-HashAlgorithmName SHA256После выполнения этой команды будет выведено сообщение о том, что установка ЦС не завершена и для её завершения необходимо отправить сгенерированный запрос (находится в корне системного диска) на вышестоящий ЦС и получить подписанный сертификат. Поэтому находим файл с расширением «.req» в корне системного диска и копируем его на корневой ЦС и на корневом ЦС выполняем следующие команды:
Установка корневого цс
Фактическая установка ЦС будет включать в себя несколько этапов:
- Подготовка предустановочных конфигурационных файлов (CAPolicy.inf);
- Установка компонента ЦС;
- Выполнение постустановочной конфигурации;
- Проверка установки.
Перед установкой корневого ЦС, необходимо ещё раз вернуться к конфигурационным таблицам:
В таблице я выделил только те параметры, которые задаются до и в процессе установки. Остальные параметры будут настраиваться после установки.
Шаблоны сертификатов
Наряду с установкой издающего ЦС, в Active Directory устанавливается набор уже готовых шаблонов сертификатов. Их можно просмотреть в оснастке
Certificate Templates MMC
(certtmpl.msc). Рекомендации по шаблонам сертификатов:
Использование готовых шаблонов сертификатов
Я рекомендую использовать их копии, даже если вы не планируете вносить в них изменения. Для создания копии шаблона выберите в списке подходящий шаблон, в контекстном меню выберите Duplicate Template и создайте его копию. Целесообразно в имя шаблона включить название компании, чтобы отличить предустановленный шаблон от вами созданного.
Версия шаблона
Начиная с Windows Server 2021, интерфейс создания шаблона несколько изменился. В самом начале появляется окно с выбором версии ОС на ЦС и предполагаемом клиенте:
Если у вас используются современные версии ОС (например, Windows 7 и выше), может появиться желание выставить настройки на максимум. Если вы не уверены, что ваше приложение совместимо с CNG (Cryptography Next Generation), следует использовать настройки, которые приведены на картинке.
Если вы выставляете ОС сервера и клиента выше, чем Windows Server 2003/Windows XP, шаблон будет использовать криптографию несовместимую с этими приложениями. Например, большинство приложений, написанных на .NET, семейство продуктов System Center, службы федераций (AD FS) и т.д. не смогут использовать ключи таких сертификатов (но проверять смогут).
Успешно такие сертификаты смогут использовать приложения, которые используют не .NET, а нативные функции CryptoAPI. К таким приложениям можно отнести, например, IIS, Remote Desktop Services.Поля Subject и Subject Alternative Names
Существует два метода заполнения поля Subject и расширения Subject Alternative Names: автоматический и ручной. Это настраивается в настройках шаблона сертификата, во вкладке Subject Name.
Если выбран второй пункт (как на картинке), ЦС игнорирует имя субъекта из запроса сертификата и заполняет эти поля из свойств учётной записи пользователя или устройства, которое запрашивает сертификат. В ряде случаев это не подходит (например, сертификаты для внутренних веб-сайтов) и имя субъекта заполняется из значения в запросе сертификата.
Это необходимо затем, что имя для сертификата никак не проверяется. Если этот момент не контролировать, пользователь может запросить сертификаты на любое имя и скомпрометировать весь лес Active Directory. Вряд ли вы позволите рядовому пользователю получить сертификат на имя администратора.
После требования одобрения запроса менеджером сертификатов на ЦС, каждый запрос с явным указанием субъекта сертификата будет попадать на ЦС в папку Pending Requests и не будет подписан, пока оператор ЦС не изучит его содержимое и не примет решение о выпуске. Т.е. каждый такой запрос необходимо вручную проверять на содержимое и убедиться, что в запросе указаны верные и допустимые имена. В противном случае запрос должен быть отклонён.
Права на шаблоны сертификатов
Шаблоны сертификатов в Active Directory хранятся в разделе configuration naming context, который реплицируется между всеми контроллерами домена в лесу. Поэтому для назначения прав на шаблоны сертификатов можно использовать только глобальные и универсальные группы. Избегайте назначения прав отдельным пользователям и устройствам.
Шифрование данных на клиенте для сервера
Для того, чтобы обеспечить конфиденциальность обмена данными между клиентом и сервером в плагине предусмотрено шифрование/расшифрование данных. Данные шифруются в формате CMS. Для того, чтобы зашифровать данные в формате CMS, требуется сертификат открытого ключа «адресата».
При этом расшифровать такое сообщение сможет только владелец закрытого ключа. При шифровании данных для сервера рекомендуется хранить сертификат сервера на Рутокен ЭЦП. Этот сертификат может быть записан на устройство при регистрации пользователя на портале.
Для этого следует использовать функцию importCertificate, при этом в качестве параметра category следует передать CERT_CATEGORY_OTHER. Для использования в функции cmsEncrypt нужно получить тело сертификата по его дескриптору с помощью функции getCertificate.
При этом дескриптор является уникальным и неизменным и может быть сохранен в учетной записи пользователя на сервере при импорте сертификата сервера. Для того, чтобы использовалось аппаратное шифрование по ГОСТ 28147-89, требуется установить опцию useHardwareEncryption в true. В противном случае будет использована быстрая программная реализация ГОСТ 28147-89.
Последовательность вызовов приведена на картинке:
Шифрование данных на клиенте:
try
{
var recipientCert = plugin.getCertificate(deviceId, certRecId);
}
catch (error)
{
console.log(error);
}
var options = {};
options.useHardwareEncryption = true;
var cms;
try
{
cms = plugin.cmsEncrypt(deviceId, certSenderId, recipientCert, data, options);
}
catch (error)
{
console.log(error);
}
Расшифрование данных на сервере, перед расшифрованием сообщение нужно обрамить PEM-заголовками “—–BEGIN PKCS7—–” и “—–END PKCS7—–“:
openssl smime -engine gost -decrypt -in message.cms -inform PEM -recip recipient.crt -inkey recipient.key
recipient.crt — сертификат того, для кого зашифровано сообщение, recipient.key — ключ того, для кого зашифровано сообщение.
Итоговая настройка
По аналогии с корневым ЦС, нам потребуется сконфигурировать ряд параметров на издающем ЦС. Для этого мы снова напишем BATCH скрипт с использованием утилиты certutil.exe. Но прежде всего посмотрим установочную таблицу и выясним параметры, которые нам необходимо настроить:
Аналогичная таблица составляется и для издающего ЦС.
За основу мы возьмём скрипт с корневого ЦС и изменим только отдельные фрагменты:
