CloudTrail присылает алерт: 340 вызовов
GetSecretValue к продакшн-секрету базы данных за 12 минут - при baseline в 8-10 обращений в час. Сервисный аккаунт CI/CD-пайплайна, который штатно дёргает секрет только при деплое, тянет credentials непрерывно. Чуть позднее картина собрана: аккаунт скомпрометирован через утёкший OIDC-токен из лога GitHub Actions, атакующий получил connection string к RDS и начал дамп таблиц. Итог - два часа простоя, утечка PII на 12 000 записей, уведомление регулятора по 152-ФЗ с перспективой оборотного штрафа и полный пересмотр модели доступа к секретам.Я разбирал шесть похожих инцидентов за последние два года. Пять из шести объединяет одно: секреты лежали в менеджере, но обращения к ним никто не мониторил. Бронированная дверь без камер наблюдения.
Как утекают пароли и API-ключи из CI/CD: kill chain секрета
Управление секретами DevSecOps на практике часто сводится к задаче «положить пароль в Vault и забыть». Kill chain реальной утечки секрета выглядит иначе:
- Initial Access - атакующий получает доступ к CI/CD-пайплайну. Типичные векторы: утёкший токен в репозитории, YAML-инъекция в self-hosted агенте, OAuth token theft. Pipeline secret leakage фигурирует в рекомендациях Microsoft как recurring issue для Azure DevOps и GitHub Enterprise.
- Credential Access - через скомпрометированный пайплайн атакующий обращается к секрет-менеджеру с легитимными правами сервисного аккаунта. Vault отдаёт секрет по валидной policy, AWS SM - по IAM role. Никаких алертов.
- Collection и Exfiltration - полученные credentials используются для прямого доступа к базам данных, API, облачным ресурсам. Секрет-менеджер на этом этапе уже не при делах.
Показательный пример атаки на инфраструктуру вокруг секретов - CVE-2026-9133 (CVSS 8.3 HIGH, CWE-489 - Active Debug Code): оставленная в production debug-схема ARN (
arn:aws-debug:file) в эндпоинте PUT /api/aws/arn/validate плагина rabbitmq-aws (до версии 0.2.1). Аутентифицированный удалённый пользователь мог прочитать произвольные файлы, доступные процессу RabbitMQ - включая TLS-сертификаты и приватные ключи. Доступ к секретам шёл на уровне файловой системы, минуя Secrets Manager API. CloudTrail этого не видел вообще. Attack surface управления API-ключами и credentials шире, чем интерфейс самого менеджера, - и про это регулярно забывают.Сравнение инструментов: HashiCorp Vault, AWS Secrets Manager и Azure Key Vault
Почему эти три и что осталось за рамками
Vault, AWS Secrets Manager и Azure Key Vault - три архитектурно разных подхода к хранению паролей и токенов в CI/CD: multi-cloud с полным контролем (Vault), managed-сервис для AWS-native стека (Secrets Manager), решение для Microsoft-хозяйства (Key Vault). Все три активно поддерживаются: Vault - open-source с BSL-лицензией, релизы ежеквартально, плюс HCP Vault Dedicated как managed-вариант; AWS SM и Azure KV - managed-сервисы с SLA от провайдера.За рамками остались: Doppler (SaaS-only - секреты транзитом через чужую инфраструктуру, ряд compliance-фреймворков это запрещает), CyberArk Conjur (PAM-first архитектура, не secrets-first), GCP Secret Manager (архитектурно аналогичен Azure KV, но с меньшей долей в enterprise-сегменте RU).
| Критерий | HashiCorp Vault | AWS Secrets Manager | Azure Key Vault |
|---|---|---|---|
| Динамические секреты | Да, 20+ backends (DB, AWS, PKI, SSH) | Нет, статическая ротация через Lambda | Нет, статическая ротация |
| Audit log | JSON audit device, каждый запрос, HMAC accessor | CloudTrail (GetSecretValue, PutSecretValue) | Diagnostic logs + Event Grid |
| SIEM-интеграция | syslog/file/socket -> любой SIEM | CloudTrail -> CloudWatch -> SIEM | Diagnostic Settings -> Log Analytics / Event Hub |
| Модель ротации | Lease TTL (минуты-часы), автоматический revoke | Lambda, built-in для RDS/Redshift/DocumentDB | Event Grid + custom handler |
| Failure mode при ротации | Старый lease живёт до TTL expiry | Two-user: два набора credentials валидны одновременно | Версионирование, старая версия доступна |
| Multi-cloud | Да | Только AWS | Только Azure / Microsoft 365 |
| Стоимость | OSS бесплатно; HCP Vault Dedicated - цена зависит от тира и региона, актуальное на cloud.hashicorp.com/pricing/vault | $0.40/секрет/мес + API-вызовы | Standard: бесплатно (лимит операций); Premium (HSM): $1/ключ/мес |
| HSM-защита | Enterprise + cloud KMS auto-unseal | AWS KMS (FIPS 140-2 validated, HSM-модули Level 3) | Premium: FIPS 140-3 Level 3 |
Когда что брать:
- Vault - multi-cloud или гибрид, нужны динамические секреты Vault, максимальный контроль над audit. Но за это платишь operational overhead: продакшн-кластер требует HA-конфигурации на Raft или Consul, настройки auto-unseal через AWS KMS или Azure Key Vault (в роли KMS-backend, не как secrets manager), выделенной ops-экспертизы. Я разворачивал Vault-кластер на 3 ноды с Raft - только на отладку auto-unseal через AWS KMS ушло два дня.
- AWS Secrets Manager - full-AWS стек, managed ротация RDS/Redshift, минимум ops. Но vendor lock-in, per-secret pricing кусается при тысячах секретов, а гранулярность audit слабая - CloudTrail это общий поток для всего аккаунта, secret-related events тонут в шуме.
- Azure Key Vault - Microsoft-стек, Entra ID как IdP, HSM на Premium tier с FIPS 140-3 Level 3. Вне Azure интеграция слабая; типичная misconfiguration из advisory - legacy access policies вместо RBAC mode, что ограничивает granular audit и открывает дорогу для secret enumeration.
Ротация credentials и динамические секреты Vault: что ломается в середине деплоя
Автоматизация управления секретами - вопрос не только безопасности, но и доступности. Вот что реально происходит при ротации credentials в каждой системе.Vault: динамические секреты как архитектурное решение. Vault не ротирует общий пароль - он выдаёт каждому потребителю уникальный credential с lease TTL. Приложение запрашивает доступ к PostgreSQL, Vault создаёт временного пользователя БД с TTL в 1 час. По истечении lease Vault отзывает credentials автоматически. Нет shared password, нечего ротировать глобально, компрометация одного lease не затрагивает остальных. Blast radius измеряется часами, а не месяцами. Но есть нюанс: не все legacy-сервисы умеют работать с обновляемыми credentials. Если ваше приложение при старте читает пароль из конфига и больше его не перечитывает - Vault Agent с template rendering решает проблему, но требует доработки деплоя.
AWS Secrets Manager: two-user rotation. При ротации пароля RDS Lambda-функция создаёт нового пользователя БД, обновляет секрет в менеджере, а старый пользователь остаётся активным до следующего цикла. Zero-downtime гарантирован, но возникает окно, когда два набора credentials валидны одновременно. С точки зрения detection: одновременное использование обоих наборов из разных source IP - аномалия и IOC.
Azure Key Vault: версионирование. Каждое обновление секрета создаёт новую версию, старая доступна по прямому URI. Для zero-downtime Microsoft рекомендует dual credentials. Event Grid отправляет
SecretNearExpiry, но advisory-паттерн Azure фиксирует типичную проблему: race condition при auto-rotation сертификатов - приложение считывает старую версию до завершения ротации. Если вы видите в логах чтение двух разных версий одного секрета из одного сервиса с интервалом в секунды - скорее всего, race condition, а не атака. Если из разных IP - уже другой разговор.Автоматизация управления секретами: аудит и корреляция аномалий в SIEM
Требования к окружению:
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Типичная ошибка в Vault policies, которую я вижу регулярно:
path "secret/data/[I]" { capabilities = ["read"] } - даёт сервису доступ ко всему дереву prod-секретов. Скомпрометированный CI-аккаунт с такой policy спокойно прочитает credentials от платёжного шлюза, хотя штатно ему нужен только пароль от staging-базы. Правильный подход - per-service policy с конкретными путями: path "secret/data/prod/service-a/[/I]".AWS CloudTrail. Событие
GetSecretValue содержит ARN секрета, source IP и user identity. Базовый фильтр: eventName = "GetSecretValue" с группировкой по requestParameters.secretId. Строите baseline: количество вызовов на секрет в час, список source IP для каждой IAM role. Аномалия: burst выше 3-sigma от baseline, новый IP, обращение к секрету, к которому роль раньше не обращалась.Azure Key Vault. Включить Diagnostic Settings с категорией
AuditEvent -> Log Analytics или Event Hub. KQL для поиска аномального burst:
Код:
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.KEYVAULT"
| where OperationName == "SecretGet"
| summarize cnt=count() by CallerIPAddress, bin(TimeGenerated, 1h)
| where cnt > 50
Insider threat: скомпрометированный сервисный аккаунт. Самый тяжёлый сценарий для detection - атакующий действует от имени легитимного сервиса. Признаки: обращение к секретам вне нормального расписания (деплой в 3 ночи при baseline 9-18), чтение секретов, к которым сервис имеет доступ по policy, но раньше не обращался, обращение с нового IP при стабильном Vault Agent в Kubernetes. IP пода в K8s не должен меняться между запросами в рамках одного lease - если меняется, это либо переезд пода на другую ноду, либо подмена.
Detection-чеклист: что передать в SOC
- Включить audit logging на всех секрет-менеджерах: Vault - audit device (file или socket), AWS - CloudTrail в каждом регионе, Azure - Diagnostic Settings с категорией AuditEvent
- Построить baseline обращений к каждому продакшн-секрету: количество в час, список source IP, привязка к accessor или IAM role
- Алерт на burst: более N обращений к одному секрету за 15 минут (N = 3× baseline; пример: 20 при baseline 6/час) - порог адаптировать под свой baseline
- Алерт на «первое обращение»: accessor или роль читает секрет, к которому раньше не обращалась - IOC для lateral movement через секреты
- Корреляция: обращение к секрету + подключение к целевому ресурсу (RDS, API) с нового IP - объединять CloudTrail или Vault audit с VPC Flow Logs и NSG Flow Logs
- Azure Key Vault: перейти с access policies на RBAC mode
- Включить soft-delete + purge protection для Azure Key Vault
- Vault: ревизия policies на wildcard-path -
path "secret/*"даёт доступ ко всему дереву - Алерт на
ListSecretsиlistоперации - enumeration секретов обычно предшествует exfiltration - Ротация: убедиться, что rotation function (Lambda, Event Grid handler) - единственный источник write-операций к секретам.
PutSecretValueот другого principal - инцидент
Заключение
За два года я участвовал в разборе шести инцидентов с утечкой секретов. В пяти секрет-менеджер был развёрнут и работал штатно. Проблема была не в хранении - никто не смотрел, кто и как часто к секретам обращается. Динамические секреты Vault частично закрывают вопрос: каждый lease уникален и короткоживущий. Но даже с Vault без мониторинга вы не узнаете, что скомпрометированный pod запрашивает credentials к продакшн-базе каждые 30 секунд вместо штатного раза в час.Cloud-native менеджеры (AWS Secrets Manager, Azure Key Vault) дают заметно более слабый audit по сравнению с Vault. CloudTrail - общий поток событий всего AWS-аккаунта, secret-related events там - иголка в стоге сена без отдельной фильтрации и выделенного trail. Azure Key Vault удобнее для lifecycle-автоматизации за счёт Event Grid, но Diagnostic Logs выключены по умолчанию (и об этом забывают с завидным постоянством).
Если у вас мультиоблако и SIEM-стек с фокусом на detection - Vault даёт единообразный поток аудита по всем средам. Проверьте прямо сейчас: включён ли audit device на вашем Vault? Есть ли алерт на burst
GetSecretValue в CloudTrail? Если на оба вопроса ответ «нет» - у вас та же проблема, что была у пяти из шести моих кейсов. Если адаптируете правила мониторинга secret access под свой SIEM - на codeby.net коллеги делятся шаблонами корреляции Vault audit и CloudTrail-событий Secrets Manager с привязкой к конкретным стекам.
Последнее редактирование модератором: