Короткий ответ
Нужно настроить отдельный CI-джоб по расписанию (cron), который выполняет только terraform plan -detailed-exitcode (без apply) для каждого важного окружения, разбирает код выхода (0 — нет изменений, 2 — есть расхождения, 1 — ошибка) и при коде 2 отправляет уведомление команде с содержимым плана, оставляя решение о применении человеку, а не автоматизируя apply на обнаруженный drift.
Как это работает подробнее
terraform plan -detailed-exitcode сравнивает текущее реальное состояние ресурсов (через обращение к API провайдера) с тем, что записано в state и описано в конфигурации, и возвращает отличающийся от обычного plan код выхода, который легко разобрать скриптом в CI; сам факт расхождения между желаемым (конфигурация) и фактическим состоянием — это и есть drift, независимо от того, кто и как его внёс.
Пример кода
#!/usr/bin/env bash
set -euo pipefail
terraform init -input=false
set +e
terraform plan -detailed-exitcode -input=false -out=plan.out
code=$?
set -e
if [ "$code" -eq 2 ]; then
terraform show -no-color plan.out | tee drift.txt
./notify_slack.sh "#infra-alerts" "Drift detected in prod" drift.txt
elif [ "$code" -eq 1 ]; then
exit 1
fiЧто использовать на практике
- Практика. план с обнаруженным drift стоит отправлять в Slack/почту/issue-трекер с диффом и ссылкой на job, а не просто логировать «где-то в CI»; для критичных ресурсов можно добавить политику, что любое ручное изменение через консоль обязано сопровождаться последующим PR с обновлением Terraform-кода (например, через
terraform import/moved) в течение фиксированного времени, чтобы state и реальность не расходились постоянно.
Подводные камни
- Ошибка. частая ошибка — настраивать автоматический
terraform applyсразу после обнаружения drift без участия человека, из-за чего намеренное экстренное ручное исправление на проде может быть откатано автоматизацией в худший момент; другая ошибка — запускать drift-detection слишком редко (например, раз в неделю) для часто меняющейся инфраструктуры, из-за чего накопленный drift сложнее анализировать построчно.