terraform plan отвечает «no changes». В это же время в консоли облака у одной security group открыт SSH на весь мир. Plan не сломан и не врёт — он просто не может этого увидеть: правило создали руками, в state его нет, а plan сверяет state с конфигом, а не облако с намерением.
Это одно из четырёх слепых пятен, из-за которых plan -detailed-exitcode в одиночку детектором дрейфа не работает.
Что именно не видит plan
- Ресурсы вне state. Созданное мимо Terraform для него не существует.
- Раздельные state-файлы. Дрейф в одном не виден из другого; чем аккуратнее разбита инфраструктура, тем больше слепых зон между кусками.
- Изменения на стороне провайдера. Обновился провайдер, поменялись дефолты — plan показывает «no changes», а ресурс в облаке уже другой.
- Семантика. Plan сверяет желаемое с фактическим, но не проверяет, что желаемое вообще допустимо: публичный SSH и выключенное шифрование он покажет как штатный порядок вещей.
Четыре слоя, а не один инструмент
Каждое слепое пятно закрывается своим слоем. Ни один из них не заменяет остальные.
| Слой | Чем | Что закрывает |
|---|---|---|
| L1 | plan -detailed-exitcode (код 2 = есть diff) | дрейф в управляемых ресурсах |
| L2 | инвентаризация облака: AWS Config, Steampipe | ресурсы вне state, соответствие на весь аккаунт |
| L3 | policy engine: OPA, Conftest, Sentinel | семантика поверх plan-вывода |
| L4 | события: EventBridge → Lambda → уведомление | ручные правки в консоли, в момент правки |
L3 стоит отдельного слова: он работает не с облаком, а с планом. Пайплайн terraform show -json plan.tfplan | conftest test -p policies/ превращает policy-проверку в предапплайный гейт, и это тот же механизм, которым безопасность въезжает в конвейер на других его стадиях.
Половина причин дрейфа — не нарушения
Список причин обычно читают как перечень провинностей: правки в консоли, хотфиксы мимо CI, посторонняя автоматизация, чужие инструменты на тех же ресурсах. Но ещё две причины никто не нарушал.
Первая — дефолты провайдера: облако поменяло значение по умолчанию между версиями. Вторая — изменения по времени: ротация паролей, перевыпуск сертификатов, автоскейлинг ёмкости. Иногда это попадает в state, иногда дрейфует.
Отсюда практический вывод: система, которая на любой дрейф отвечает откатом, будет регулярно откатывать штатную жизнь инфраструктуры. Разделение «что чинить автоматически, а что показывать человеку» — не деталь настройки, а основное проектное решение.
Что давит на переход к автоисправлению
Опрос ControlMonkey даёт три цифры: 71% команд говорят, что генеративные инструменты увеличивают объём их IaC-кода, 63% — что такую инфраструктуру труднее управлять, чем написанную руками, 81% — что ручное ревью за этой скоростью не поспевает.
Оговорка обязательна: ControlMonkey продаёт IaC-платформу, и вывод «детекция без исправления в 2026 отомрёт» — их прогноз, а не нейтральный факт. Цифры про рост объёма правдоподобны и совпадают с тем, что видно вокруг; вывод из них делает продавец решения.
Осторожная формулировка того же наблюдения: чем больше изменений в единицу времени, тем дороже стоит очередь из алертов, которые никто не разбирает. Алерт без адресата — это не наблюдаемость, это отложенный инцидент.
Remediation-as-code: где проходит граница
Автоматическое исправление — не «откатывать всё подряд». Практически это три разных решения, и их стоит принимать заранее, а не в момент срабатывания.
Что откатывать автоматически. Узкий список, где правильное состояние известно и однозначно: публичный доступ, снятое шифрование, отсутствующие обязательные теги. Здесь автоматика уместна, потому что альтернатива — открытая дыра, ждущая ручного разбора.
Что вшивать в state. Легитимная ручная правка не должна вечно светиться дрейфом. Для этого есть plan -refresh-only: он синхронизирует state с реальностью и не планирует никаких действий над ресурсами. Дальше правка переносится в код обычным PR.
Что вести как инцидент. Всё остальное. Дрейф в проде — это P2: зафиксировать артефакт, поднять по журналу аудита, кто и когда изменил, решить — накатывать вперёд или откатывать, написать постмортем. Постмортем здесь не ритуал: он единственный способ понять, что дрейф повторяется по одной и той же причине.
Структурная защита сильнее детекции
Самый дешёвый дрейф — тот, который невозможен.
- Запретить мутации всем, кроме Terraform. IAM-политика, отбивающая изменяющие действия у всех, чей принципал не помечен как управляемый Terraform. Это не проверка, а стена: ручная правка не будет обнаружена, потому что не произойдёт.
- Проставлять
ManagedByчерезdefault_tagsпровайдера — один раз в провайдере, а не в каждом ресурсе. На этих тегах и держится предыдущий пункт. - Заводить существующее через
import-блоки, а не через историю shell-команд: импорт становится обычным изменением, которое видно в PR и можно обсудить.
Policy-as-code тут работает как ускоритель, а не как тормоз — но только если правила пишутся вместе с кодом, а не поверх него; об этом парадоксе есть отдельный разговор.
Инструменты: одна честная оговорка
driftctl часто советуют как независимый сканер ресурсов, которых нет в state. Инструмент рабочий, но с 29 июня 2023 года проект в maintenance mode: авторы прямо пишут, что не обещают рассматривать вклад. Для разового аудита это не проблема. Для постоянного слоя L2 — проблема: новые типы ресурсов в него не приезжают, а именно там и заводится незамеченное. Под постоянный слой надёжнее инвентаризация самого облака.
Отдельно про соблазн отдать дрейф GitOps-контроллеру. Паттерн «Argo CD запускает Job с terraform apply» выглядит красиво и разваливается на главном: Job отрабатывает один раз, непрерывной сверки нет. Для облачных ресурсов нужен либо честный CI-конвейер, либо control plane, который умеет реконсиляцию — но это уже другой инструмент и другой разговор про state.
С чего начать, если сейчас только L1
- Ночной
plan -detailed-exitcodeпо каждому state, код 2 заводит тикет с diff'ом в теле. Это дешевле всего и сразу показывает масштаб. default_tagsсManagedByи IAM-запрет мутаций мимо Terraform. Два шага, и поток нового дрейфа резко сужается.- Policy-гейт на плане до апплая — начать с двух-трёх правил, которые нельзя нарушать никогда.
- Инвентаризация облака для ресурсов вне state. К этому моменту находок будет мало, и разбирать их будет посильно.
Автоисправление ставится последним и на узкий список — когда уже понятно, какой дрейф в вашей инфраструктуре штатный, а какой нет. Иначе автоматика начнёт чинить то, что не сломано.