Планирование и безопасность: policy, secrets, drift и импорт
Зачем эта тема нужна после модулей и state
В предыдущих статьях вы научились описывать инфраструктуру на HCL, понимать жизненный цикл ресурсов, работать с состоянием (state), удалёнными backend, блокировками и модулями. Следующий шаг к практике — сделать работу с Terraform безопасной и управляемой в команде.
В этой статье разберём четыре больших направления:
Планирование как основной механизм контроля изменений
Policy as code — правила, которые автоматически запрещают опасные изменения
Secrets — как не утечь секретам через код, логи и state
Drift — как находить и исправлять расхождение между описанием и реальностью
Импорт — как аккуратно «подхватывать» уже существующую инфраструктуру!Типовой безопасный процесс: plan в PR, проверки политик, apply после одобрения
Планирование как основа контроля изменений
Что именно даёт terraform plan
terraform plan — это не просто «посмотреть разницу». Это механизм, который позволяет:
увидеть предложенные действия до реальных изменений
поймать ошибки типа зависимостей, пересозданий, удаления критичных ресурсов
запустить проверки безопасности и политик на планируемые измененияДокументация:
Команда terraform planPlanfile: фиксируем план, который будет применён
Ключевой практический приём для CI/CD и командной работы — сохранять план в файл и применять именно его:
Почему это важно:
apply без planfile пересчитает план заново, и результат может отличаться (например, из-за параллельных изменений или изменений данных)
planfile даёт возможность прогнать политики и сканеры до примененияПолезные флаги планирования
-var и -var-file — управление входными параметрами
-destroy — план на уничтожение (используйте осторожно)
-refresh-only — план, который только обновляет state по факту реальности, не меняя инфраструктуруДокументация:
Команда terraform applyПочему -target — почти всегда плохая идея
Флаг -target заставляет Terraform «прицелиться» в конкретные ресурсы и может обходить нормальный граф зависимостей. Это полезно в аварийных ситуациях, но опасно как регулярная практика.
Практическое правило:
используйте -target только для точечных аварийных действий и с полным пониманием последствий
после применения обязательно делайте обычный terraform plan, чтобы убедиться, что система снова консистентнаPolicy as code: как запрещать опасные изменения автоматически
Что такое policy и где она живёт
Policy as code — это формализованные правила, которые проверяют:
конфигурацию (static checks)
или план изменений (plan-time checks)И решают: можно ли применять изменения.
Типовые политики:
запрет публичного доступа к хранилищам
запрет ресурсов без обязательных тегов
запрет слишком широких прав доступа
запрет удаления определённых классов ресурсовВарианты enforcement: где именно «остановить» изменения
В Git-процессе
- проверка на PR: если политика не проходит, PR нельзя смержить
В CI/CD пайплайне
- даже если PR смёржен, пайплайн не выполнит apply
На уровне платформы
- Terraform Cloud/Enterprise могут централизованно запрещать apply
Terraform Cloud и Sentinel
Sentinel — язык политик, встроенный в Terraform Cloud/Enterprise.
Документация:
Sentinel в Terraform CloudИдея:
Terraform Cloud получает план
Sentinel оценивает его по правилам
если политика нарушена, apply запрещёнOPA и Conftest: политики поверх plan в JSON
В open-source среде частый подход:
Сгенерировать план
Преобразовать его в JSON
Проверить правилами OPA (Rego) через ConftestСсылки:
Open Policy Agent
Conftest
Команда terraform showПример потока:
Пример очень упрощённой идеи правила (не «боевой» пример, только чтобы понять механику): запретить удаление ресурсов.
Ключевой принцип:
политики должны проверять то, что реально будет сделано, то есть планСтатические сканеры: tfsec, Checkov, TFLint
Эти инструменты не заменяют policy enforcement, но сильно повышают качество.
| Инструмент | Что проверяет | Где применяют |
|---|---|---|
| TFLint | стиль, ошибки, специфичные правила для провайдеров | локально и в CI |
| tfsec | security misconfigurations в Terraform | CI, PR checks |
| Checkov | политики безопасности для IaC (Terraform и не только) | CI, PR checks |
Практическая связка:
terraform fmt и terraform validate как минимальный барьер
сканеры как второй барьер
policy enforcement по plan как финальный барьер перед applySecrets: как не утекать секретам через код и state
Где «живут» секреты в Terraform
Секреты — это любые данные, утечка которых опасна:
API-токены
пароли
приватные ключи
строки подключенияТиповые места утечек:
*.tfvars в репозитории
вывод terraform plan и terraform apply в CI логах
outputs
terraform.tfstate и удалённый backendВажно: sensitive скрывает вывод, но не делает секрет «невидимым»
Terraform умеет помечать значения как sensitive:
Что это даёт:
Terraform постарается не печатать значение в консолиЧего это не даёт:
секрет всё равно может попасть в state
любой, кто читает state, потенциально может получить секретДокументация:
Sensitive данные в Terraform
Sensitive outputsПрактики хранения и передачи секретов
Не хранить секреты в Git
- добавляйте
*.tfvars с секретами в
.gitignore
Передавать секреты через окружение
- переменные вида
TF_VAR_<name>
Использовать секрет-хранилища
- например, HashiCorp Vault
Ссылки:
HashiCorp VaultSOPS и шифрованные tfvars
Если вам нужно хранить значения рядом с кодом (например, для GitOps), часто используют шифрование файлов с секретами.
Один из популярных инструментов:
Mozilla SOPSПрактический смысл:
в репозитории лежат только зашифрованные данные
дешифрование происходит в CI/CD при наличии ключейДоступ к state — это доступ к секретам
Если в вашей инфраструктуре есть секреты, то:
доступ на чтение к backend со state фактически равен доступу к чувствительным даннымПрактические меры:
минимизируйте права на чтение state
используйте отдельные backends и ключи state для prod
включайте шифрование на хранилище (на стороне S3/GCS/Azure или Terraform Cloud)Drift: как обнаружить и лечить расхождение с реальностью
Что такое drift
Drift — это ситуация, когда:
в конфигурации Terraform описано одно
в реальной платформе получилось другоеТиповые причины:
ручные изменения в консоли облака
действия внешних систем (autoscalers, оператор Kubernetes, политики организации)
изменение параметров по умолчанию у провайдера/платформы!Цикл обнаружения drift и варианты реакции
Как проверять drift безопасно
Terraform позволяет обновить state, не меняя инфраструктуру:
Если нужно обновить state по факту реальности (например, после ручного изменения, которое вы решили принять):
Документация:
Флаг -refresh-only для terraform plan
Флаг -refresh-only для terraform applyКак правильно реагировать на drift
Есть два корректных сценария:
Drift недопустим
- вы исправляете реальность через
terraform apply, возвращаясь к описанному состоянию
Drift допустим и это новое требование
- вы меняете конфигурацию Terraform, чтобы она отражала реальность, и затем применяете
Плохой сценарий:
скрывать drift через lifecycle { ignore_changes = ... } без строгой причиныignore_changes полезен, когда атрибут обязан управляться внешней системой, но это должно быть архитектурно обосновано.
Документация:
ignore_changesИмпорт: как взять под управление уже существующие ресурсы
Зачем нужен импорт
Импорт нужен, когда ресурс уже существует, но Terraform о нём «не знает». Частые ситуации:
инфраструктуру создали вручную до внедрения Terraform
ресурс создал другой процесс, но теперь вы хотите управлять им декларативноВажно:
импорт не «угадывает» конфигурацию автоматически
импорт только связывает адрес ресурса в Terraform с реальным объектом в stateБазовый подход: terraform import
Высокоуровневый процесс:
Написать конфигурацию ресурса в .tf
Выполнить импорт в state
Запустить terraform plan и довести конфигурацию до совпадения с реальностьюДокументация:
Команда terraform importПример формы команды:
Где:
<АДРЕС_РЕСУРСА> — адрес вида aws_instance.web или module.app.aws_instance.web
<ID_ОБЪЕКТА> — идентификатор в платформе (его формат зависит от провайдера)Import blocks: импорт как часть кода
Начиная с новых версий Terraform, можно описывать импорт декларативно через import блоки.
Документация:
Import blocksИдея:
импорт становится частью PR
меньше ручных команд
проще повторять процесс в предсказуемом видеИмпорт и for_each: важность адресов
Если ресурс создаётся через for_each, адрес в state включает ключ:
aws_s3_bucket.this["logs"]Это влияет на импорт: вы должны импортировать конкретный экземпляр по правильному адресу.
Как не сломать инфраструктуру при импорте
Практический чек-лист:
делайте импорт маленькими шагами
после каждого шага запускайте terraform plan
не пытайтесь «сразу импортировать всё» без понимания зависимостей
заранее продумайте структуру модулей, чтобы не делать массовые миграции адресов сразу после импортаЕсли нужно перестать управлять ресурсом через Terraform:
используется удаление объекта из state без удаления в платформеДокументация:
Команда terraform state rmРекомендуемый безопасный процесс для команды
Ниже практическая схема, которая обычно хорошо масштабируется.
Локально разработчик делает изменения
Запускаются базовые проверки
-
terraform fmt
-
terraform validate
- линтеры и сканеры
В PR пайплайн строит plan -out=tfplan
План проверяют политики
- Sentinel в Terraform Cloud или OPA/Conftest в CI
Apply запускается только после одобрения и только из доверенной среды
- с удалённым backend
- с locking
- с секретами из секрет-хранилища
Drift-check по расписанию
-
terraform plan -refresh-only как регулярный контроль
Итоги
Вы научились смотреть на Terraform не только как на инструмент создания ресурсов, но как на контролируемый процесс изменений:
terraform plan и planfile — основа воспроизводимых и проверяемых изменений
policy as code позволяет автоматически запрещать опасные действия
secrets требуют дисциплины: чувствительные значения могут оказаться в state и логах
drift нужно регулярно обнаруживать и осознанно либо исправлять, либо принимать через изменение кода
импорт помогает постепенно перевести существующую инфраструктуру под управление Terraform, но требует аккуратной работы с адресами и планом