
Введение
В корпоративной среде с ростом количества сотрудников, которым требуется доступ к системам с использованием ЭЦП, возникла необходимость автоматизировать процесс установки сертификатов.
Попытки применить стандартные средства — Import-PfxCertificate
, certutil
и другие — результата не дали: сертификаты не виделись рядом приложений, включая СБИС. Готовых рабочих решений тоже не нашлось. Пришлось разрабатывать собственный метод.
В этой статье описан механизм, применяемый для распространения сертификатов ИФНС. Методы экспорта ключей и сертификатов можно найти в сети, поэтому они здесь не рассматриваются. Вопросы безопасности при передаче приватных ключей также остаются за рамками — предполагается, что всё выполняется во внутреннем доверенном контуре.
За основу была взята статья «Перенос контейнеров закрытых ключей и сертификатов CryptoPro», где описан ручной процесс. Я доработал его и автоматизировал для централизованного распространения через GPO.
Проблема
При переносе сертификатов и ключей между машинами или профилями возникает одна и та же трудность: они «привязаны» к SID пользователя.
Если импортировать .reg
напрямую, записи окажутся связаны с SID другого пользователя и работать не будут.
Поэтому при автоматическом распространении необходимо корректно подставлять текущий SID.
Решение
Я подготовил набор PowerShell-скриптов, которые выполняются от имени пользователя при логоне (через GPO Logon Script).
Сценарий работы такой:
Шаблон реестра
В исходном.reg
файле хранится конфигурация с «старым» SID.Подмена SID
Скрипт получает SID текущего пользователя[System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
и заменяет им статический идентификатор в файле.
Импорт реестра
Обновлённый.reg
файл импортируется в HKCU.Копирование сертификатов
Из сетевой папки (\\share\Cert\My
) копируются нужные файлы в профиль пользователя:%APPDATA%\Microsoft\SystemCertificates\My
Готово
При следующем запуске приложений (Outlook, браузеры, CryptoPro) пользователь сразу получает доступ к сертификатам.
Пример кода
Запуск разных скриптов по группам
Этот пример показывает, как можно привязывать разные сценарии к членству пользователя в группах AD. Каждое группа соответствует отдельному сертификату.
# Задаем группы и соответствующие пути к скриптам для каждой группы
$groupScriptMap = @{
"First Group" = "\\path\first_script.ps1"
"Second Group" = "\\path\second_script.ps1"
}
# Получаем информацию о текущем пользователе
$user = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$userGroups = $user.Groups | ForEach-Object {
$_.Translate([System.Security.Principal.NTAccount]).Value.Split("\")[1]
}
# Перебираем каждую группу из маппинга и проверяем, состоит ли в ней пользователь
foreach ($group in $groupScriptMap.Keys) {
if ($userGroups -contains $group) {
Write-Output "Пользователь $($user.Name) принадлежит группе $group."
# Получаем путь к скрипту для этой группы
$scriptPath = $groupScriptMap[$group]
Write-Output "Запускается скрипт для группы: $scriptPath"
# Выполняем соответствующий скрипт
try {
#Start-Process -FilePath "powershell.exe" -ArgumentList "-ExecutionPolicy Bypass -File $scriptPath" -NoNewWindow -Wait
Start-Process -FilePath "powershell.exe" -ArgumentList "-ExecutionPolicy", "Bypass", "-File", "`"$scriptPath`"" -NoNewWindow -Wait
} catch {
Write-Output "Ошибка при выполнении скрипта для группы $[group]: $_"
}
} else {
Write-Output "Пользователь $($user.Name) не состоит в группе $group."
}
}
Данные скрипт производит основные действия по замене SID, импорте reg файла и копировании хранилища личных сертификатов пользователя
# Указываем путь к файлу реестра (исходный шаблон .reg файл)
$regFileSource = "\\path\first_file.reg"
# Определяем временную папку текущего пользователя
$tempFolder = [System.IO.Path]::GetTempPath()
# Определяем SID текущего пользователя
$userSID = (Get-WmiObject -Class Win32_UserAccount -Filter "Name='$env:USERNAME'").SID
# Определяем целевой файл во временной папке
$regFileTemp = Join-Path $tempFolder "modified_registry.reg"
# Читаем содержимое исходного файла реестра
$regContent = Get-Content -Path $regFileSource -Encoding Unicode
# Статический SID, который будем заменять
$oldSID = "S-1-5-21-3734670798-76392145-1373982661-1117"
# Заменяем статический SID на SID текущего пользователя
$updatedContent = $regContent -replace $oldSID, $userSID
# Записываем обновленный файл реестра во временную папку
$updatedContent | Out-File -FilePath $regFileTemp -Encoding Unicode
# Импортируем обновленный файл реестра
reg import $regFileTemp
# Указываем сетевую папку для копирования
$networkFolder = "\\path\My"
# Папка пользователя, куда нужно скопировать сетевую папку
$userFolder = "C:\Users\$env:USERNAME\AppData\Roaming\Microsoft\SystemCertificates"
# Копируем содержимое с заменой конфликтов
Copy-Item -Path $networkFolder -Destination $userFolder -Recurse -Force
Write-Host "Файл реестра был успешно импортирован, и папка скопирована."
Варианты использования
Распространение сертификатов ЭЦП среди сотрудников
Миграция рабочих мест и перенос профилей
Репозиторий
Исходный код доступен здесь. Там же постарался создать подробный и понятный README.
👉 GitHub — provision_of_certificates_GPO
Заключение
Предложенный метод позволяет автоматизировать раздачу сертификатов через GPO без ручных действий. Он прост в реализации.
При этом стоит помнить о недостатках:
нет централизованного контроля за сроком действия сертификатов;
приватные ключи передаются в файлах, что требует доверенной среды;
метод рассчитан именно на Windows-среду с CryptoPro.