Где живут секреты: от конфигурационных файлов до Vault
Вы настраиваете новое приложение. Создаёте файл .env с учётными данными базы данных, ключами API и адресами серверов. На вашей машине всё работает. Вы коммитите файл в Git, чтобы коллега мог запустить такое же окружение. Через несколько месяцев приложение оказывается в продакшене, и кто-то случайно пушит этот .env в публичный репозиторий. Через несколько минут пароль от вашей продакшен-базы данных оказывается в интернете.
Этот сценарий не редкость. Он возникает потому, что самый простой способ хранения секретов одновременно является и самым опасным. Путь от хранения секретов в конфигурационных файлах до использования специализированных инструментов управления секретами проходит каждая команда, часто — после болезненного опыта.
Проблема конфигурационных файлов
Когда вы только учитесь создавать приложения, складывать всё в один конфигурационный файл кажется естественным. Ваш .env, config.json или application.properties превращается в «солянку». Адреса серверов, которые не являются чувствительными, соседствуют с паролями баз данных, которые крайне чувствительны. Весь файл попадает в Git, и любой, у кого есть доступ к репозиторию, может увидеть всё.
Такой подход работает, пока вы единственный разработчик и приложение запускается на вашем ноутбуке. Но как только команда растёт или приложение добирается до реальных пользователей, проявляются трещины. Каждый разработчик, клонирующий репозиторий, видит продакшен-пароли. Даже если репозиторий приватный, секреты навсегда остаются в истории Git. Удаление файла из последнего коммита не удаляет его из старых коммитов. Секрет остаётся там навсегда, доступный любому, кто умеет просматривать историю Git.
Следующий шаг, который предпринимают большинство команд — отделение секретов от обычной конфигурации. Конфигурационный файл остаётся в Git, но чувствительные значения заменяются плейсхолдерами вроде DB_PASSWORD=changeme. Настоящие значения хранятся в другом месте: в файле, который не коммитится, в переменных окружения на сервере или в документе, пересланном в чате. Это лучше, чем хранение секретов в Git, но порождает новые проблемы. Нет записи о том, кто получил доступ к секрету. Ротация пароля означает его обновление вручную в нескольких местах. Если файл с секретами потеряется или повредится, не будет управляемого бэкапа для восстановления.
Что меняет выделенное хранилище секретов
Команды, работающие с несколькими приложениями и окружениями, рано или поздно обращаются к инструментам, созданным специально для секретов. Vault, AWS Secrets Manager, Azure Key Vault и GCP Secret Manager спроектированы для корректной обработки чувствительных данных. Секреты больше не являются файлами на диске. Они становятся объектами, которые приложения получают через API.
Переход от файлов к хранилищу секретов меняет три фундаментальные вещи:
Вот краткий пример того, как сохранить и получить пароль базы данных с помощью HashiCorp Vault:
# Сохраняем секрет
vault kv put secret/myapp DB_PASSWORD=supersecret
# Получаем секрет
vault kv get secret/myapp
# Вывод:
# ====== Data ======
# Key Value
# --- -----
# DB_PASSWORD supersecret
Контроль доступа. С конфигурационным файлом любой, кто может его прочитать, видит секрет. С Vault вы определяете, какое приложение или пайплайн может получить доступ к какому секрету. CI-пайплайн для staging-окружения может получить staging-учётные данные, но не может трогать продакшен-секреты. Такая гранулярность невозможна с файлами.
Аудит. Файлы не логируют, кто их читал. Vault записывает каждый запрос доступа: кто запросил, какой секрет и когда это произошло. Если секрет утёк, вы можете отследить, какие приложения или пользователи обращались к нему примерно в момент инцидента.
Шифрование в покое и при передаче. Конфигурационные файлы хранят секреты в открытом виде на диске. Vault шифрует секреты при хранении и при передаче по сети. Даже если кто-то получит доступ к нижележащему хранилищу, он не сможет прочитать секреты без ключей шифрования.
Операционные затраты на использование Vault
Инструменты управления секретами не бесплатны, и затраты не ограничиваются деньгами. Вашей команде нужно научиться работать с инструментом. Если Vault упадёт, приложения не смогут получить секреты и могут полностью перестать работать. Вам понадобятся стратегии высокой доступности, кэширования или fallback-механизмов, чтобы отказ Vault не обрушил вашу продакшен-систему.
Управляемые облачные хранилища секретов снижают операционную нагрузку, но вводят оплату за запрос или за секрет. Команде, делающей тысячи запросов секретов в минуту, нужно оценить, будет ли такая стоимость устойчивой. Самостоятельно размещаемые решения, такие как Vault, дают больше контроля, но требуют выделенных усилий на поддержку, обновление и обеспечение безопасности.
Выбор подходящего для вашей команды решения
Не существует единственно правильного ответа на вопрос, где хранить секреты. Правильный выбор зависит от размера вашей команды, количества приложений и толерантности к риску.
Следующая блок-схема поможет вам решить, какой подход подходит для вашей текущей ситуации:
Небольшая команда с одним приложением и несколькими окружениями может использовать отдельный файл, который не коммитится в Git, при условии, что все понимают риски. Ключевой момент — осознанность выбора, а не попадание в него по умолчанию.
Команда с несколькими приложениями, несколькими окружениями и несколькими разработчиками выиграет от использования выделенного хранилища секретов. Затраты на его настройку окупаются в первый же раз, когда вам нужно будет ротировать учётные данные во всех окружениях или расследовать, кто получил доступ к секрету, который позже утёк.
Важный принцип — консистентность. Какой бы метод вы ни выбрали, применяйте его единообразно. Смешивание подходов — часть секретов в файлах, часть в переменных окружения, часть в Vault — создаёт путаницу и увеличивает вероятность случайной утечки.
Практический чеклист для хранения секретов
- Отделены ли секреты от обычной конфигурации?
- Исключены ли секреты из системы контроля версий (проверьте
.gitignore)? - Можете ли вы ротировать учётные данные без изменения кода приложения?
- Знаете ли вы, какие приложения и пайплайны имеют доступ к каждому секрету?
- Есть ли у вас логи, показывающие, кто и когда получил доступ к секрету?
- Если ваше хранилище секретов упадёт, сможет ли ваше приложение запуститься или корректно обработать ошибку?
Что дальше
Знать, где хранить секреты — только половина работы. Следующий вопрос: как ваш пайплайн получает эти секреты, не сохраняя их внутри конфигурации самого пайплайна. CI/CD-пайплайн, который выводит секреты в логи, хранит их в переменных окружения, видимых всем шагам, или кэширует в файлах рабочей области, ничем не лучше конфигурационного файла, закоммиченного в Git. Способ хранения важен, но то, как секреты проходят через ваш процесс доставки, не менее важно.