Секреты и безопасная автоматизация
Play ITЗагрузка интерактивного демо…
Пароли, API-ключи и токены никогда не коммитят в Git и не вставляют в .ps1. См. также Опасные скрипты.
Зачем отдельная статья
Скрипт с $password = 'P@ssw0rd' работает на демо и ломает безопасность в продакшене. Автоматизация по Практическая автоматизация — модель и окупаемость и Триггеры — расписание и наблюдатели почти всегда требует учётных данных — SQL, SMTP, Azure, сетевые шары. Здесь — принципы и практика PowerShell.
Принципы безопасной автоматизации
| Принцип | Суть |
|---|---|
| Секреты вне скрипта | Пароли, ключи, строки подключения — в хранилище или CI, не в .ps1 |
| Минимальные привилегии | УЗ службы только с правами, нужными для одной роли скрипта |
| Учёт контекста | Интерактивный запуск и планировщик — разные модели доступа |
| Ролевые УЗ | Отдельные учётки для SQL, почты, AD — "одна УЗ на систему и роль" |
| Логирование и алерты | Кто запустил, успех/сбой — без записи секретов в лог |
| Защита репозитория | Подпись скриптов, ревью, .gitignore для локальных конфигов с секретами |
Что считать чувствительным
Очевидно:
- пароли;
- API-ключи;
- SSH-ключи;
- закрытые ключи сертификатов.
Менее очевидно, но тоже ценно для атакующего:
- строка подключения к SQL (сужает цель);
- имена служебных УЗ (половина пары "логин + пароль");
- URL внутренних админок и webhook-токены в query string.
Правило: если данные помогают злоумышленнику — их нет в исходнике скрипта.
SecureString и PSCredential
SecureString — строка в зашифрованном виде в памяти процесса (Windows DPAPI). PSCredential — объект UserName + Password (SecureString).
Интерактивный ввод:
$cred = Get-Credential -Message 'Учётные данные для SQL'
$cred.UserName
# $cred.Password — SecureString, не выводить в лог
Создание из переменной окружения или файла только на этапе подготовки машины, не в репозитории:
# Антипаттерн в Git — допустимо только в одноразовом setup-скрипте на сервере
$secure = Read-Host 'Пароль' -AsSecureString
$cred = New-Object PSCredential ('DOMAIN\svc-backup', $secure)
ConvertTo-SecureString с -AsPlainText -Force оставляет след в истории и памяти — для автоматизации используйте SecretManagement или CI secrets.
SecretManagement и SecretStore
Модуль Microsoft.PowerShell.SecretManagement — единый API; провайдеры подключают бэкенд.
| Провайдер | Сценарий |
|---|---|
SecretStore (Microsoft.PowerShell.SecretStore) | Один сервер, задачи планировщика |
| KeePass | Команда, офлайн-хранилище, общая база |
| Azure Key Vault | Облако, ротация, аудит |
Установка и настройка SecretStore:
Install-Module Microsoft.PowerShell.SecretManagement, Microsoft.PowerShell.SecretStore -Scope AllUsers
Install-SecretVault -Name LocalStore -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
Set-Secret -Name 'SqlMonitor' -Secret (Get-Credential) -Vault LocalStore
Set-Secret -Name 'SmtpApiKey' -Secret 'sg.xxxx' -Vault LocalStore
Использование в скрипте:
Import-Module Microsoft.PowerShell.SecretManagement
$sqlCred = Get-Secret -Name 'SqlMonitor' -AsCredential
$apiKey = Get-Secret -Name 'SmtpApiKey'
Invoke-Sqlcmd -Query 'SELECT 1' -Credential $sqlCred
# $apiKey — передать в заголовок HTTP, не Write-Host
Секреты и модули для задачи от SYSTEM ставят с -Scope AllUsers. Иначе планировщик не увидит vault — см. 126.
Контекст выполнения
| Режим | Как получить секрет | Пример |
|---|---|---|
| Интерактив | Get-Credential, Get-Secret после входа оператора | Разовая миграция |
| Планировщик + УЗ службы | SecretStore на машине, gMSA, Windows Integrated Auth | Мониторинг SQL |
| CI/CD | Secrets в GitHub Actions / Azure DevOps / Jenkins | Deploy pipeline |
| Azure Automation | Credential asset, Managed Identity — Экосистема автоматизации на PowerShell | Runbook в облаке |
Windows Integrated Auth к SQL или файловому ресурсу часто снимает необходимость пароля в скрипте: задача планировщика от доменной УЗ с нужными ACL.
Ролевые учётные записи
Один "универсальный admin" для всех скриптов упрощает жизнь на неделю и усложняет на годы.
| Роль скрипта | Права |
|---|---|
Мониторинг SQL (только sys.databases) | VIEW ANY DATABASE, без чтения данных |
| Отправка почты через SMTP relay | Только Send As на одном relay, ограничение по IP |
| Архивация логов | Read/Write на каталог логов и архива, без админов ОС |
gMSA (group Managed Service Account) в AD — пароль не хранят в скрипте; Windows обновляет его автоматически. Подходит для служб и длительных задач в домене.
Логирование без утечек
Write-Verbose "Подключение к SQL как $($cred.UserName)"
# Плохо: Write-Host $cred.Password или $connectionString с паролем
Write-Log "SQL check finished: exit 0"
При -Verbose в планировщике включайте в настройках задачи или передавайте -Verbose в аргументах pwsh.
Риски, о которых стоит помнить
| Риск | Митигация |
|---|---|
| Скрипт в публичном gist | Секреты только в vault; ревью перед публикацией |
Invoke-Expression с URL | Выполнение чужого кода = чужие секреты в памяти |
| Экспорт Scheduled Task XML с паролем | Хранить XML в защищённом месте или создавать задачу кодом |
Clixml с Export-Clixml для $cred | Привязка к пользователю/машине; не переносить между серверами без понимания DPAPI |
Чек-лист
| # | Вопрос |
|---|---|
| 1 | В репозитории нет паролей, ключей, .pfx без пароля? |
| 2 | УЗ службы имеет минимальные права? |
| 3 | Секреты читаются через SecretManagement / CI / gMSA? |
| 4 | Логи не содержат connection string и токены? |
| 5 | При компрометации одной УЗ ущерб ограничен одной системой? |
Дальше
| Тема | Материал |
|---|---|
| Конфиги без секретов в JSON | Конфигурация и адаптивные скрипты |
| Триггеры и контекст УЗ | Триггеры — расписание и наблюдатели |
| Azure Automation, runbook | Экосистема автоматизации на PowerShell |
| Общая безопасность кода | 8.03/101 |