Секрет это всё, что даёт доступ: пароли баз, токены API, ключи облака, приватные ключи TLS, ключи подписи. Утечка секрета равна утечке доступа, поэтому вопрос «где у вас хранятся пароли» звучит почти на каждом DevOps-собесе.
Где секретам не место
- Git, даже приватный: история хранит всё навсегда, клонов много. Если секрет попал в коммит, его нужно отозвать и выпустить новый, чистка истории вторична.
- Docker-образ:
ENV PASSWORD=...или скопированный.envвиден черезdocker historyи в любом слое. - Логи и вывод CI:
echo,set -x, отладочные дампы конфигов. - Чаты, тикеты и вики.
Сканеры (gitleaks, trufflehog) ставят в pre-commit хуки и в CI, а платформы (GitHub secret scanning, GitLab) ищут известные форматы ключей сами.
Kubernetes Secret
Secret хранит значения в base64. Это кодирование, а не шифрование: base64 -d раскодирует любой, у кого есть право читать Secret. Что делать:
- включить шифрование etcd at rest (EncryptionConfiguration, лучше через KMS);
- ограничить RBAC на чтение
secretsв namespace; - не класть Secret-манифесты открытым текстом в git: Sealed Secrets, SOPS или External Secrets Operator.
Переменные окружения или файлы
Переменные окружения просты, но легко утекают: их видят дочерние процессы, они попадают в дампы ошибок и в /proc/<pid>/environ. Файлы (смонтированный Secret, tmpfs) можно ограничить правами и обновлять без перезапуска процесса. Компромисс: env для несекретного конфига, файлы или прямое чтение из хранилища для секретов.
HashiCorp Vault
Vault это централизованное хранилище секретов с аудитом и выдачей по политикам. С 2023 года Vault под лицензией BSL; открытый форк называется OpenBao.
Ключевые понятия:
- Seal / unseal: после старта Vault запечатан и не может расшифровать данные. Мастер-ключ разделён схемой Шамира на части (по умолчанию 5 частей, нужно 3). В проде настраивают auto-unseal через KMS облака или HSM.
- Auth methods: как клиент доказывает, кто он. Kubernetes (по токену сервисного аккаунта), AppRole для приложений и CI, OIDC для людей, JWT для CI-систем.
- Policies: какие пути и операции доступны.
path "secret/data/billing/*" {
capabilities = ["read"]
}
- Secrets engines:
kv(версия 2 хранит версии значений): статические секреты.database: динамические учётки к базе. Vault создаёт пользователя с TTL по запросу и удаляет его по истечении lease.pki: выпуск короткоживущих TLS-сертификатов.transit: шифрование как сервис, ключ не покидает Vault.
- Lease и TTL: у динамического секрета есть срок жизни, его можно продлить или отозвать.
vault kv put secret/billing db_password='s3cr3t'
vault kv get -field=db_password secret/billing
vault read database/creds/billing-ro # новая временная учётка
Динамические секреты
Статический пароль базы живёт годами, его знают десятки сервисов и людей. Динамический выдаётся каждому экземпляру приложения на час: утечка ограничена по времени, а в аудите видно, кто какую учётку получил. Это главный аргумент за Vault перед «просто зашифрованным файлом».
Как секрет попадает в приложение в Kubernetes
- External Secrets Operator синхронизирует значение из Vault или облачного менеджера секретов в обычный Secret.
- Vault Agent Injector или CSI Secrets Store кладут секрет файлом в под.
- Приложение само ходит в Vault через SDK, аутентифицируясь сервисным аккаунтом.
Ротация
Секреты нужно менять: по расписанию, при уходе сотрудника, при подозрении на утечку. Ротация без простоя требует поддержки двух значений одновременно: выпускаем новый ключ, переводим клиентов, отзываем старый. Если ротация страшна и делается вручную раз в год, это сигнал автоматизировать.
Частые ошибки
- Считать base64 шифрованием.
- Один «вечный» токен CI с правами админа.
- Секрет в
ARGилиENVDockerfile. - Хранить unseal-ключи Vault в том же месте, что и бэкапы Vault.
- Удалить секрет из git и не перевыпустить его.
Что спросят на собесе
- Где хранить секреты приложения и CI.
- Почему Kubernetes Secret это не шифрование и как его защитить.
- Что такое динамические секреты и зачем они.
- Как устроены seal и unseal в Vault.
- Что делать, если секрет утёк в публичный репозиторий.