Хранение секретов в приложении: сравниваем 4 подхода
Пароли баз данных, токены и ключи API нельзя оставлять в репозитории. Сравниваем переменные окружения, файлы, Secret Manager и KMS по рискам, удобству ротации и поведению в контейнерах.

Пароль базы данных в Git остаётся проблемой даже после удаления строки из файла: секрет мог попасть в историю коммитов, кеш CI или резервную копию. Для приложения в контейнерах выбор между переменной окружения, смонтированным файлом, Secret Manager и KMS определяет не только безопасность, но и то, сможете ли вы заменить ключ без простоя. Ниже — практическое сравнение для Docker Engine 26.x и Kubernetes 1.30+; пример с Vault относится к ветке 1.17.
Сначала разделите секреты и конфигурацию
Конфигурация описывает поведение приложения: порт, имя очереди, уровень логирования. Секрет даёт доступ: пароль, токен, приватный ключ, строка подключения с учётными данными. Это разные категории, и хранить их одинаково не стоит.
У секрета должны быть владелец, срок действия, процедура замены и журнал обращений. Если вы не знаете, кто может его прочитать и как быстро отозвать, место хранения — только часть проблемы.
Безопасный секрет — не тот, который спрятан в необычном файле, а тот, который можно ограниченно выдать, проверить и заменить без публикации нового образа.
Секрет-менеджер — сервис, который хранит секретные значения, контролирует доступ к ним, ведёт аудит и часто поддерживает версии и ротацию. Это не просто папка с файлами и не обязательно облачный продукт.
Четыре варианта хранения
1. Переменные окружения
Приложение получает значения через окружение процесса: например, DATABASE_PASSWORD или PAYMENT_TOKEN. Такой способ легко подключить к Docker Compose, Kubernetes и большинству библиотек конфигурации.
Главный плюс — секрет не входит в образ. Главный минус — он становится частью окружения процесса и может быть раскрыт через диагностические команды, дампы, отладочные инструменты или неосторожное логирование. В Kubernetes объект Secret по умолчанию хранится в etcd в кодировке Base64, а не в зашифрованном виде; шифрование at rest нужно настраивать отдельно.
Переменные окружения подходят для небольшого сервиса, если доступ к хосту и CI ограничен, а ротация не требует долгого параллельного запуска старого и нового секрета.
2. Секретный файл, смонтированный в контейнер
Секрет записывается в файл, доступный процессу по пути вроде /run/secrets/database_password. В Kubernetes файл может появиться из Secret, внешнего оператора или CSI-драйвера; конкретный механизм зависит от кластера.
Файл снижает риск случайного вывода всех переменных окружения и удобен для сертификатов, JSON-ключей и многострочных значений. Но приложение должно уметь читать файл и реагировать на его замену. Важно также проверить права доступа, поведение симлинков и то, перечитывает ли процесс файл или требует перезапуска.
Этот вариант часто лучше окружения для TLS-сертификатов и крупных ключей. Он не решает вопрос доверия к узлу: процесс с достаточными правами всё равно может прочитать файл.
3. Secret Manager с выдачей по идентичности
Приложение обращается к Vault 1.17 или аналогичному сервису по своей машинной идентичности и получает только разрешённые секреты. В Kubernetes для этого обычно связывают сервисный аккаунт, роль и политику доступа.
Преимущество — централизованные политики, аудит, версии, короткоживущие учётные данные и ротация без хранения постоянного пароля в CI. Цена — ещё один критичный сервис. Нужно проектировать старт приложения, кеширование, повторные запросы и поведение при недоступности Secret Manager.
Секрет не должен выдаваться по общей переменной вроде VAULT_TOKEN, лежащей в каждом контейнере. Лучше использовать идентичность workload: сервис должен доказать, кто он, а не предъявить общий пароль.
4. Зашифрованный файл и KMS
Значения хранятся в репозитории или артефакте в зашифрованном виде, а ключ расшифровки выдаёт KMS или другой защищённый сервис при запуске. В Git попадает ciphertext, но не исходный пароль.
Подход удобен для декларативной инфраструктуры и ревью изменений: видно, что секрет обновился, но не видно его значения. При этом ключ расшифровки становится новым критическим секретом. Если он доступен каждому CI-job или каждому узлу, защита быстро теряет смысл.
KMS не заменяет управление секретами. Он решает задачу шифрования и контроля ключа, но не обязательно предоставляет версионирование значений, выдачу по ролям и удобный аудит обращений.
Сравнение по цене и риску
| Подход | Что получает приложение | Ротация | Основной риск | Когда выбирать |
|---|---|---|---|---|
| Переменные окружения | Значение при запуске процесса | Обычно нужен перезапуск | Утечки через окружение, дампы и логи | Небольшой сервис и простая инфраструктура |
| Смонтированный файл | Файл с ограниченными правами | Возможна без пересоздания контейнера, если приложение умеет перечитывать файл | Неверные права и чтение файла всеми процессами | Сертификаты, многострочные ключи, Kubernetes |
| Secret Manager | Секрет по политике и идентичности | Версии, отзыв и короткий срок жизни | Недоступность сервиса и ошибка политики | Несколько окружений, команда, аудит и частая ротация |
| KMS плюс зашифрованный файл | Расшифрованное значение после проверки доступа к ключу | Нужно обновить ciphertext и иногда перезапустить сервис | Утечка ключа расшифровки | GitOps и контроль ключей на уровне инфраструктуры |
Как выбрать вариант на рабочем проекте
Не начинайте с вопроса «где спрятать пароль». Начните с жизненного цикла: кто выдаёт доступ, сколько живёт секрет, как его отозвать и что произойдёт при сбое хранилища.
- Опишите границу доступа. Для каждого сервиса перечислите нужные секреты и отделите их от секретов соседних сервисов. Если одному приложению нужны ключи пяти систем без явной причины, сначала исправьте модель доступа. Проверка: для каждого значения есть один владелец и одна причина выдачи.
- Выберите способ доставки. Для простого приложения используйте окружение или файл, но не передавайте секрет в Dockerfile и не встраивайте его в образ. Для нескольких окружений и частой ротации выбирайте Secret Manager. Проверка: новый образ не требуется для замены значения, если это обязательное требование проекта.
- Ограничьте права. Роль сервиса должна читать только свои пути и операции. Запретите массовое чтение всех секретов namespace или хранилища. Проверка: тестовая учётная запись не может получить секрет другого сервиса.
- Продумайте отказ. Решите, может ли приложение использовать короткий кеш, продолжать работу со старым значением или должно остановиться. Не добавляйте бесконечные повторы: при недоступном хранилище они способны перегрузить и приложение, и сам Secret Manager. Проверка: отдельно испытан старт при недоступном хранилище.
- Проверьте ротацию. Сначала выдайте новый секрет, затем переключите потребителей, после чего отзовите старый. Если система поддерживает только один активный пароль, ротация может потребовать короткого окна или специального порядка действий. Проверка: старое значение больше не работает, а сервис продолжает обслуживать запросы.
Что чаще всего ломается
Секрет попадает в образ или репозиторий
Строка с паролем в Dockerfile, конфигурации или тестовом файле остаётся в слоях образа и истории Git. Удаление файла в следующем коммите не очищает старые слои и коммиты. Такой секрет нужно немедленно отозвать и выпустить новый, а затем проверить CI-логи, кеши и артефакты.
Приложение печатает конфигурацию
Отладочный endpoint, дамп настроек и сообщение об ошибке подключения могут вывести пароль целиком. Маскируйте значения до записи в лог и отдельно проверяйте исключения, трассировки и метрики с labels. Нельзя считать секретом только то, что начинается со слова PASSWORD: токены и приватные ключи тоже требуют фильтрации.
Ротация обновляет хранилище, но не процесс
Новый файл или значение в Secret Manager не гарантирует, что уже запущенный процесс его увидит. Некоторые приложения читают конфигурацию только при старте, другие держат соединение с базой и продолжают использовать старые учётные данные. Зафиксируйте способ применения: reload, rolling update или контролируемый перезапуск.
Доступ к хранилищу становится единой точкой отказа
Если каждый запрос к Secret Manager выполняется синхронно и без кеша, краткий сетевой сбой превращается в каскад ошибок. Если кеш бесконечный, отозванный секрет продолжит работать дольше, чем вы рассчитывали. Укажите допустимое время жизни кеша и наблюдайте ошибки выдачи, задержку, число обращений и возраст используемого значения.
Когда переменных окружения достаточно
Они разумны для одного-двух сервисов, редкой ротации и контролируемого CI, если секреты не попадают в логи, дампы и манифесты, а доступ к хосту ограничен. Но при росте числа приложений окружение быстро превращается в неявный реестр доступов: непонятно, кто читает значение, когда оно выдано и какие сервисы нужно обновить.
Для Kubernetes не путайте объект Secret с полноценным Secret Manager. Это удобный способ доставки данных, но безопасность зависит от RBAC, шифрования etcd, прав на namespace, аудита и источника, из которого объект создаётся.
Что сделать дальше
Составьте инвентаризацию секретов: имя, владелец, сервис-потребитель, способ доставки, срок действия и процедура отзыва. Затем выберите один секрет для тестовой ротации и измерьте три показателя: время отзыва, время обновления всех потребителей и количество ошибок во время переключения. После этого добавьте сканирование Git и образов, запрет вывода конфигурации в логах и проверку минимальных ролей в CI.
Термин: ротация — плановая замена секрета новым значением с отзывом старого. Ротация не равна простому добавлению ещё одного пароля: важно проверить, что все потребители перешли на новую версию.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: Kubernetes Documentation: Secrets, OWASP Secrets Management Cheat Sheet
Частые вопросы
Можно ли хранить секреты в переменных окружения?
Безопасен ли Kubernetes Secret?
Что делать, если секрет уже попал в Git?
Нужно ли использовать Secret Manager для одного небольшого сервиса?
Что произойдёт, если Secret Manager недоступен во время запуска?
Можно ли шифровать файл секретов ключом, который тоже лежит рядом?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.