Заметка

Drift detection в 2026: от алерта к remediation-as-code

Plan говорит «no changes», а security group открыт в мир. Четыре слепых пятна одноуровневой детекции и то, где проходит граница автоматического исправления.

terraform plan отвечает «no changes». В это же время в консоли облака у одной security group открыт SSH на весь мир. Plan не сломан и не врёт — он просто не может этого увидеть: правило создали руками, в state его нет, а plan сверяет state с конфигом, а не облако с намерением.

Это одно из четырёх слепых пятен, из-за которых plan -detailed-exitcode в одиночку детектором дрейфа не работает.

Что именно не видит plan

  • Ресурсы вне state. Созданное мимо Terraform для него не существует.
  • Раздельные state-файлы. Дрейф в одном не виден из другого; чем аккуратнее разбита инфраструктура, тем больше слепых зон между кусками.
  • Изменения на стороне провайдера. Обновился провайдер, поменялись дефолты — plan показывает «no changes», а ресурс в облаке уже другой.
  • Семантика. Plan сверяет желаемое с фактическим, но не проверяет, что желаемое вообще допустимо: публичный SSH и выключенное шифрование он покажет как штатный порядок вещей.

Четыре слоя, а не один инструмент

Каждое слепое пятно закрывается своим слоем. Ни один из них не заменяет остальные.

СлойЧемЧто закрывает
L1plan -detailed-exitcode (код 2 = есть diff)дрейф в управляемых ресурсах
L2инвентаризация облака: AWS Config, Steampipeресурсы вне state, соответствие на весь аккаунт
L3policy 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

  1. Ночной plan -detailed-exitcode по каждому state, код 2 заводит тикет с diff'ом в теле. Это дешевле всего и сразу показывает масштаб.
  2. default_tags с ManagedBy и IAM-запрет мутаций мимо Terraform. Два шага, и поток нового дрейфа резко сужается.
  3. Policy-гейт на плане до апплая — начать с двух-трёх правил, которые нельзя нарушать никогда.
  4. Инвентаризация облака для ресурсов вне state. К этому моменту находок будет мало, и разбирать их будет посильно.

Автоисправление ставится последним и на узкий список — когда уже понятно, какой дрейф в вашей инфраструктуре штатный, а какой нет. Иначе автоматика начнёт чинить то, что не сломано.

© 2026 axyi.ru · CC BY 4.0