Когда облачная консоль и IaC-код расходятся: автоматическое обнаружение дрейфа инфраструктуры
Вы уже несколько месяцев управляете инфраструктурой через Terraform. Всё описано в коде, проходит ревью через pull request и разворачивается через пайплайны. В один прекрасный день коллеге нужно быстро поправить конфигурацию. Вместо того чтобы гонять пайплайн, он заходит в облачную консоль, вручную меняет правило security group и идет дальше. Изменение работает. Никто больше о нем не вспоминает.
Через несколько недель вы запускаете новый деплой. Terraform планирует откатить то самое изменение в security group, потому что в коде всё еще старая версия. Если применить — целенаправленное изменение будет перезаписано. Если пропустить — код перестанет соответствовать реальности. Поздравляю, у вас дрейф инфраструктуры.
Дрейф — это расхождение между тем, что должно быть по коду инфраструктуры, и тем, что на самом деле существует в вашем облачном окружении. Это не теоретическая проблема. Она возникает в каждой команде, которая управляет инфраструктурой в масштабе. Вопрос не в том, случится ли дрейф, а в том, как быстро вы его обнаружите.
Почему ручное обнаружение дрейфа не работает
Технически вы можете обнаружить дрейф, открыв облачную консоль, проверив каждый ресурс и сравнив его с IaC-кодом. Это работает, когда у вас пять ресурсов. Перестает работать, когда их пятьдесят, пятьсот или пять тысяч.
У ручного обнаружения три проблемы. Первая — медлительность. Одно сравнение может занять минуты. Умножьте на сотни ресурсов — и вы тратите часы на то, что должно быть автоматизировано. Вторая — ненадежность. Человеческий глаз пропускает мелкие различия, особенно когда у ресурсов десятки полей конфигурации. Третья — непостоянство. Разные члены команды могут проверять разные вещи или вообще забыть проверить.
Главная проблема — время. Дрейф может возникнуть в любой момент. Ручная проверка раз в неделю означает, что вы можете жить с незамеченным изменением днями. Если это изменение создает уязвимость в безопасности или ломает зависимость, вы узнаете об этом жестким способом — во время следующего инцидента.
Как работает автоматическое обнаружение дрейфа
Автоматическое обнаружение дрейфа следует простому принципу: запускать сравнение между фактическим состоянием инфраструктуры и IaC-определениями по расписанию. Этот процесс называется сканированием дрейфа (drift scan). Сканирование дрейфа ничего не меняет. Оно только находит различия и сообщает о них.
Самый распространенный подход использует те же инструменты, которыми вы уже управляете инфраструктурой. Например, у Terraform есть команда plan, которая сравнивает ваш state-файл с реальными облачными ресурсами. State-файл — это запись, которую Terraform хранит локально или удаленно, содержащая информацию о созданных ресурсах и их текущей конфигурации. Когда вы запускаете terraform plan без изменения кода, инструмент проверяет, соответствует ли state-файл тому, что на самом деле существует в облаке. Если кто-то изменил ресурс напрямую в консоли, план покажет это как изменение, которое Terraform хочет внести.
Это основа обнаружения дрейфа: периодически запускать plan и проверять наличие неожиданных изменений.
Вот минимальный bash-скрипт, который запускает сканирование дрейфа и оповещает команду при его обнаружении:
#!/bin/bash
# drift-scan.sh - Запуск сканирования дрейфа Terraform и уведомление об изменениях
set -euo pipefail
cd /path/to/terraform/project
terraform init -input=false
# Обновляем state из реальных ресурсов, затем планируем с детальным кодом возврата
terraform plan -refresh-only -detailed-exitcode -out=drift.tfplan
PLAN_EXIT_CODE=$?
if [ $PLAN_EXIT_CODE -eq 2 ]; then
# Код 2 означает, что есть изменения (обнаружен дрейф)
echo "Drift detected in $(date)"
# Генерируем читаемое описание
terraform show drift.tfplan > drift-summary.txt
# Отправляем уведомление в Slack (укажите свой webhook URL)
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"🚨 Drift detected in production!\n$(cat drift-summary.txt)\"}" \
https://hooks.slack.com/services/YOUR/WEBHOOK/URL
elif [ $PLAN_EXIT_CODE -eq 1 ]; then
echo "Error during plan execution"
exit 1
else
echo "No drift detected"
fi
Этот скрипт можно запускать через cron или по расписанию в CI/CD-пайплайне каждые несколько часов.
Следующая диаграмма показывает полный цикл обнаружения дрейфа:
Больше, чем просто plan: получение точных результатов
Здесь есть тонкий, но важный момент. Обычный terraform plan сравнивает state-файл с реальными ресурсами. Но что, если сам state-файл устарел? Если кто-то сделал изменение в консоли, state-файл может этого не отражать. План не обнаружит дрейф, потому что сравнивает две сущности, которые обе рассинхронизированы.
Некоторые инструменты справляются с этим лучше. Terraform Cloud и OpenTofu предлагают обнаружение дрейфа, которое идет глубже. Вместо простого сравнения state с ресурсами они сначала обновляют state, загружая актуальную конфигурацию из облака, а затем сравнивают обновленный state с вашим кодом. Это дает сравнение от кода к реальным ресурсам, а не от state к ресурсам. Результат точнее, потому что он ловит изменения, произошедшие вообще вне state-файла.
Это различие важно. Если вы полагаетесь только на базовый вывод plan, вы можете пропустить дрейф, который появился до последнего обновления state-файла. Правильное сканирование дрейфа всегда должно начинаться с обновления state из реального окружения.
Расписание и уведомления
Сканирование дрейфа должно запускаться по расписанию. Как часто — зависит от того, как часто изменения происходят вне вашего пайплайна. Команды, управляющие критичной продакшн-инфраструктурой, часто запускают сканирование каждые несколько часов. Команды с меньшей активностью — раз в день. Ключевое — постоянство: сканирование должно запускаться автоматически, без участия человека.
Вы можете настроить расписание через cron на вашем CI/CD-сервере, триггер пайплайна по расписанию или встроенный планировщик вашего IaC-инструмента. Важно, чтобы расписание было надежным и не зависело от того, что кто-то вспомнит его запустить.
Когда дрейф обнаружен, следующий шаг — уведомление. Автоматические оповещения должны приходить в канал связи вашей команды: Slack, email или тикет-систему. Хорошее уведомление содержит три вещи: какой ресурс дрейфует, что именно изменилось и когда это было обнаружено. Если ваш облачный провайдер логирует, кто сделал изменение, добавьте и эту информацию. Это значительно ускоряет расследование.
Что делать после обнаружения
Найти дрейф — только первый шаг. Как только вы знаете о нем, у вас есть два варианта.
Первый вариант — реконсилиация: вернуть ресурс в состояние, определенное в коде. Это стандартный ответ для большинства команд. Вы запускаете terraform apply или его аналог, и инструмент откатывает ручное изменение. Это хорошо работает, когда дрейф был случайным или несанкционированным.
Второй вариант — принятие: ручное изменение было намеренным и должно остаться. В этом случае вы обновляете IaC-код, чтобы он соответствовал фактическому состоянию. Это правильный выбор, когда изменение было легитимным исправлением, сделанным быстро в консоли, и коду нужно догнать реальность. Опасность в том, что если делать так слишком часто, ваш код перестает быть источником истины и становится просто исторической записью.
Выбор между реконсилиацией и принятием зависит от политики вашей команды. Некоторые команды всегда делают реконсилиацию, если нет документально оформленного исключения. Другие разрешают принятие, но требуют последующий pull request в течение определенного времени. Важно, чтобы решение было осознанным, а не случайным.
Практический чек-лист для автоматического обнаружения дрейфа
Если вы настраиваете обнаружение дрейфа впервые, вот краткий чек-лист для начала:
- Выберите инструмент обнаружения: используйте встроенное обнаружение дрейфа вашего IaC-инструмента или выделенный инструмент вроде Terraform Cloud, OpenTofu или собственный скрипт, который периодически запускает plan.
- Настройте расписание сканирования: начните с одного раза в день для некритичных окружений и каждые несколько часов для продакшна. Корректируйте в зависимости от того, как часто происходят ручные изменения.
- Настройте уведомления: отправляйте оповещения в командный чат или тикет-систему. Включайте имя ресурса, конкретное изменение и временную метку.
- Определите политику реагирования: решите, будете ли вы делать реконсилиацию или принимать дрейф. Документируйте процесс, чтобы вся команда следовала одному подходу.
- Протестируйте процесс: внесите намеренное ручное изменение в стейджинг-окружении, дайте сканированию его обнаружить и проверьте, что уведомление и реакция работают как ожидается.
Конкретный вывод
Дрейф инфраструктуры — это не признак плохой команды. Это признак того, что ваша команда движется быстро и иногда срезает углы. Проблема не в самом сокращении пути. Проблема в том, что вы не знаете о нем, пока он не вызовет инцидент.
Автоматическое обнаружение дрейфа превращает невидимую проблему в видимую. Оно не мешает людям вносить изменения в консоли. Оно гарантирует, что когда они это делают, остальная команда узнает об этом быстро и сможет решить, что делать дальше. Эта видимость — то, что поддерживает надежность вашей инфраструктуры, даже когда код и облако расходятся.