Секреты в инфраструктуре: что нельзя в Git

Весь этот модуль держится на одной мысли: инфраструктура становится кодом и переезжает в Git, со всей историей и ревью. Но у этой же мысли есть оборотная сторона. Откройте настоящий проект на Terraform и Ansible, и окажется, что он насквозь пропитан секретами: токен для доступа в облако, приватный SSH-ключ, пароль от базы данных, ключи к внешним сервисам. И все это так и просится в те же файлы, которые вы коммитите. Сила подхода, когда все лежит в Git, оборачивается ловушкой: вместе с инфраструктурой в Git норовят уехать и ее секреты.

Где в инфраструктуре прячутся секреты

Секреты тут конкретные и узнаваемые. В Terraform это в первую очередь доступ к облаку, тот самый токен, который в шаге про Terraform мы скромно отметили словами «доступ настроен заранее». Этим токеном Terraform от вашего имени создает и удаляет серверы. Сюда же относятся пароли, которые вы задаете ресурсам, например пароль администратора базы данных прямо в блоке resource.

В Ansible секреты приходят с настройкой: пароль для become, ключи к внешним API в переменных, тот самый SSH-ключ, которым Ansible заходит на серверы. Все это лежит рядом с playbook и инвентарем.

Главное правило не меняется

В модуле про Git вы уже вывели общее правило: секреты не коммитят, потому что в истории они остаются навсегда, а утекший секрет приходится ротировать, то есть менять, делая старое значение недействительным. Для инфраструктуры это правило ровно то же. Меняется только список секретов, и добавляется одна ловушка, которой у обычного кода нет.

Ловушка Terraform, state хранит секреты открытым текстом

Помните файл состояния из шага про Terraform, ту память, где Terraform записывает все, что создал? Вот неприятная деталь: в этом файле значения хранятся открытым текстом, в том числе секретные. Пароль базы, который вы задали в resource, ложится в terraform.tfstate как есть, читаемой строкой.

Из этого следует жесткое правило: файл состояния в Git не коммитят никогда. Даже если в самих .tf секретов нет, они могут оказаться в state. Поэтому состояние держат не рядом с кодом, а в защищенном удаленном хранилище (remote backend), например в бакете облака с шифрованием и контролем доступа, где его видят только те, кому положено. Код инфраструктуры лежит в Git, а ее состояние отдельно и под замком.

Как секреты подают правильно

Если в файлы секреты класть нельзя, откуда их берут инструменты в момент запуска? Способов несколько, от простого к взрослому.

Самый базовый это переменные окружения и отдельные файлы вне Git. Токен облака кладут в переменную окружения, и Terraform с Ansible читают его оттуда, а не из коммита. Файл с переменными вроде secrets.auto.tfvars заносят в .gitignore, как .env из модуля про Git.

Дальше идут хранилища секретов (secret managers). Это отдельные сервисы, чья единственная работа безопасно хранить секреты и отдавать их по запросу с проверкой доступа: HashiCorp Vault, а в облаках AWS Secrets Manager и Yandex Lockbox. Инструмент в момент применения идет туда за паролем, и в файлах не лежит даже намека на секрет, только адрес, откуда его взять.

У Ansible есть и свой встроенный прием, Ansible Vault. Он шифрует файл с секретами, и зашифрованный файл уже можно спокойно коммитить: в Git он лежит нечитаемым набором символов, а Ansible расшифровывает его при запуске по паролю. Это редкий случай, когда секрет все-таки живет в репозитории, но в зашифрованном виде.

И отдельно стоит знать про sensitive. В Terraform переменную можно пометить sensitive = true, и тогда ее значение не будет светиться в выводе plan и apply. Но помните про ловушку выше: на содержимое state это не влияет, там пароль все равно окажется. Пометка sensitive прячет секрет от глаз в логах, но не из состояния.

Почему в инфраструктуре цена утечки выше

У обычного приложения утекший пароль это доступ к одному сервису. В инфраструктуре утекает не пароль, а ключи от всего хозяйства. Токен облака, попавший в публичный репозиторий, дает чужому человеку право создавать и удалять у вас серверы, читать данные, поднять под вашим счетом ферму для майнинга. А боты, как вы помните из модуля про Git, вычесывают публичные репозитории и находят такие ключи за минуты.

Поэтому в инфраструктуре дисциплина с секретами не пожелание, а необходимость, и если облачный токен все же утек, первым делом его отзывают и выпускают новый, а уже потом разбираются, как он туда попал.

Причем здесь DevOps

Когда инфраструктура и доставка автоматизированы, секреты подает не человек, а пайплайн. Terraform и Ansible в реальной работе запускаются не с вашего ноутбука, а внутри CI/CD из модуля про автоматизацию, и токен туда приходит из защищенных переменных пайплайна, замаскированным, не из файла. Так замыкается вся картина модуля: инфраструктура описана кодом в Git, ее состояние и секреты лежат отдельно и под защитой, а применяет все это автоматика, доставая секреты из надежного места ровно в момент запуска.