Недавно одна команда Terraform, запущенная ИИ-агентом, снесла продакшен-инфраструктуру платформы курсов. В этой статье расскажу, как это произошло и как удалось восстановить базу данных.
Ситуация: я работал над расширением сайта https://aishippinglabs.com/ и хотел перенести его текущую версию со статических GitHub Pages в AWS. А позже заменить исходную версию на Next.js вариантом на Django.
План постепенной миграции был таким:
перенести текущий статический сайт с GitHub Pages в AWS S3;
перенести DNS в AWS, чтобы домен полностью управлялся там;
развернуть новую Django-версию на поддомене;
когда всё заработает, переключить основной домен на Django.
Так вся инфраструктура уже была бы внутри AWS, а финальное переключение прошло бы безболезненно.
Сама стратегия миграции была нормальной. Проблемы начались из-за того, как я её выполнял.
Я слишком сильно положился на своего агента Claude Code, и он случайно снёс всю продакшен-инфраструктуру платформы управления курсами. На этой платформе хранились данные за 2,5 года по разным процессам: домашние задания, проекты, записи в лидербордах — по каждому запуску курсов, проходившему через платформу.
Хуже того, вместе с этим удалились все автоматические снапшоты. Мне пришлось перейти на AWS Business Support, который стоит мне дополнительные 10% обычных расходов, для доступа к более быстрой поддержке. К счастью, поддержка помогла восстановить базу данных, а полное восстановление заняло около 24 часов.
В этой статье я расскажу, как допустил такую ситуацию и что сделал, чтобы она не повторилась.
Хронология инцидента
Четверг, 26 февраля
22:00: начал выкатывать изменения сайта через Terraform, но забыл использовать state-файл: он остался на старом компьютере.
23:00: команда Terraform с auto-approve случайно снесла всю продакшен-инфраструктуру, включая Amazon Relational Database Service (RDS). Позже я обнаружил, что все снапшоты тоже удалены, и создал тикет в поддержку AWS.
Пятница, 27 февраля
00:00: перешёл на AWS Business Support, чтобы получить более быстрый ответ.
00:30: поддержка AWS подтвердила, что на их стороне есть снапшот.
01:00–02:00: созвонился с поддержкой AWS; обращение передали внутренней команде для восстановления.
В течение дня: внедрил меры защиты — настроил Lambda-функцию для бэкапов, включил защиту от удаления, сделал бэкапы в S3 и перенёс Terraform state в S3.
22:00: база данных была полностью восстановлена. Только в одной таблице courses_answer оказалось 1 943 200 строк. Платформу снова подняли.
Как случилась катастрофа
Повторное использование существующей Terraform-конфигурации
У меня уже был Terraform, который управлял продакшен-инфраструктурой другого проекта — платформы управления курсами. Вместо того чтобы создать отдельную конфигурацию для AI Shipping Labs, я добавил его в существующую, чтобы немного сэкономить.
Claude пытался меня отговорить и говорил, что инфраструктуру лучше держать отдельно. Но я хотел чуть снизить расходы: у меня была схема, где всё находится внутри Virtual Private Cloud (VPC), все ресурсы размещены в приватной сети, а для доступа к машинам используется бастион.
Экономия там не такая уж большая, может быть $5–10 в месяц. Но я подумал: зачем мне ещё один VPC? И сказал агенту сделать всё там же. Это повысило сложность и риск, потому что изменения для этого сайта теперь оказались смешаны с изменениями другой инфраструктуры.
Первый тревожный сигнал
Вместо того чтобы вручную пройтись по плану, я позволил Claude Code запустить terraform plan, а затем terraform apply. Первым признаком, что что-то не так, стал длинный список создаваемых ресурсов. Это не имело смысла: инфраструктура уже существовала. Мы не поднимали новое окружение.
Я остановил Claude и спросил: «Почему создаётся так много ресурсов?» Ответ агента был простым и одновременно пугающим: Terraform считал, что ничего не существует.
Но почему? Я недавно переехал на новый компьютер и не перенёс Terraform. Когда я запустил terraform plan, он решил, что существующей инфраструктуры нет и мы начинаем с нуля.
Я быстро отменил terraform apply, но часть ресурсов уже успела создаться.
Анализ и удаление дублирующихся ресурсов через AWS CLI
Следующим шагом нужно было понять, что именно было создано. Я поручил Claude проанализировать окружение через AWS CLI и определить, какие ресурсы были созданы только что, а какие относятся к продакшену. Я хотел удалить только новые дубликаты и не трогать существующую инфраструктуру.
Ассистент сообщил, что нашёл дублирующиеся ресурсы через AWS CLI и удаляет их. Звучало правильно.
Пока шла эта очистка, я пошёл к старому компьютеру, заархивировал папку Terraform вместе со state-файлом и перенёс её на новую машину. Я решил, что очистка уже тоже закончилась, и указал агенту на архив Terraform, чтобы он мог сравнить новые ресурсы с заархивированными.
Удаление через terraform destroy
Агент продолжал удалять файлы, и в какой-то момент вывел: «Я не могу это сделать. Запущу terraform destroy. Раз ресурсы были созданы через Terraform, удалить их через Terraform будет чище и проще, чем через AWS CLI».
Это выглядело логично: если ресурсы создал Terraform, Terraform же должен их и удалить. Поэтому я не стал останавливать агента, когда он запускал terraform destroy. Команда завершилась успешно. В тот момент я всё ещё думал, что мы чистим только свежесозданные ресурсы.
Потом я проверил платформу управления курсами, и она лежала. Я подумал: «Что происходит?» — и открыл AWS Console, чтобы разобраться.
База данных, VPC, ECS-кластер, балансировщики нагрузки и бастион исчезли. Вся продакшен-инфраструктура была уничтожена.

Когда я спросил Claude, где база данных, ответ был прямой: она удалена.
Что произошло на самом деле
Проблема была в том, что я не заметил, как Claude распаковал мой архив с Terraform. Он заменил текущий state-файл старым, где была вся информация о платформе управления курсами.
Когда Claude запустил terraform destroy, он снёс не только временные дубликаты. Фактически он уничтожил реальную инфраструктуру платформы курсов — ту самую, которая была описана в state-файле.
Поиск решения
1. Ищем бэкапы
Когда я понял, что продакшен-инфраструктура исчезла, я начал искать бэкапы. Они должны были создаваться ежедневно.
Было около 23:00, и я знал, что снапшот создаётся каждую ночь в 02:00. Я зашёл в консоль RDS и проверил доступные снапшоты, но ничего не увидел. Проверил консоль ещё раз — всё равно пусто.

События RDS в четверг. Бэкап был создан в 00:24 и отображался в AWS Console в разделе событий, но сам бэкап исчез.
Затем я открыл раздел RDS Events и увидел, что бэкап действительно был создан в 02:00, как и ожидалось. Событие было в списке, но при клике ничего не открывалось, а сам снапшот был недоступен.
В тот момент я не понимал, удалён бэкап или просто не отображается.
2. Обращение в поддержку AWS
Около полуночи я создал тикет в поддержку по поводу удалённой базы данных и пропавших бэкапов. Я также написал коллеге в AWS, но не рассчитывал на ответ так поздно.
Не получив ответа, я заметил, что Business Support обещает ответ в течение часа в случае инцидентов в продакшене. Поэтому я повысил уровень поддержки, и это добавило примерно 10% к моим облачным расходам.
Затем я создал ещё один тикет со всеми нужными деталями. Поддержка ответила примерно через 40 минут.
3. Что нашла поддержка AWS
Поддержка AWS подтвердила, что моя база данных и все снапшоты были удалены. Этого я совсем не ожидал. API-запрос явно сказал AWS удалить всё.

На своей стороне они нашли снапшот, который я не видел в консоли. Когда я указал на это, они предложили созвониться.
4. Созвон с AWS
Мы созвонились и вместе разобрали ситуацию.
Они попробовали выполнить восстановление со своей стороны. Через какое-то время инженер поддержки сказал, что ему нужно эскалировать обращение внутри AWS. Мы оставались на линии, пока они разбирались.
Пока продакшен уже лежал, я начал заново собирать остальные части инфраструктуры через Terraform. Это получилось довольно быстро. Заодно я упростил некоторые вещи: например, свёл несколько балансировщиков нагрузки к одному.
Я создал новый пустой экземпляр базы данных, чтобы подготовиться к возможному восстановлению.
Звонок длился примерно 40–60 минут. В итоге они сказали, что им нужно больше времени и они вернутся с ответом, когда прояснят ситуацию.
5. Спустя 24 часа
Ровно через 24 часа после удаления базы данных AWS восстановила снапшот.
Я получил письмо с подтверждением, что восстановление снапшота завершено и он готов к использованию:

Снапшот, который раньше был невидимым, теперь появился в консоли.

6. Восстановление базы данных
Я пересоздал базу данных из восстановленного снапшота через Terraform.
На этом этапе я изменил подход к работе с Terraform через Claude Code. Все разрешения отключены. Никакого автоматического выполнения. Никакой записи в файлы.
Теперь процесс простой:
сгенерировать план;
вручную его проверить;
самому выполнить команды.
После восстановления базы данных я проверил данные. В таблице courses_answer было 1 943 200 строк:

Платформа управления курсами снова заработала. Все домашние задания были видны.

Последний шаг — настроить бэкапы для нового экземпляра базы данных и аккуратно удалить временную пустую базу, созданную во время инцидента, не перепутав её с восстановленной.
Что я сделал, чтобы это не повторилось
Пока я ждал, когда AWS решит проблему со снапшотом, я начал внедрять защитные меры. Я не хотел, чтобы одна команда destroy когда-нибудь снова могла снести всё.
Вот что я изменил.
1. Бэкапы вне Terraform state
Я настроил бэкапы, которыми не управляет Terraform.
Я не ожидал, что снапшоты исчезнут вместе с базой данных. Чтобы избежать такого риска, я позаботился о том, чтобы были бэкапы, независимые от жизненного цикла Terraform.
Также я добавил бэкапы в S3. Они хранятся отдельно от базы данных и не привязаны к состоянию инфраструктуры.
2. Ежедневная проверка восстановления через Lambda и Step Functions
Я собрал автоматизированный процесс резервного копирования.
Каждую ночь в 02:00 AWS создаёт обычный автоматический бэкап. Примерно в 03:00 просыпается Lambda-функция и создаёт новый экземпляр базы данных из этого автоматического бэкапа. Так каждый день у меня появляется свежая копия продакшена. Это занимает около 20–30 минут.
Когда база создана, запускается ещё одна Lambda-функция, оркестрированная через Step Functions. Она проверяет, что базой действительно можно пользоваться: выполняет простой запрос на чтение, например SELECT COUNT(*) FROM email. После успешной проверки база останавливается, а не удаляется. Так я плачу только за хранилище, а не за вычисления.
После этого восстановленная вчера база удаляется. В любой момент времени у меня есть одна недавно восстановленная реплика.
Я сделал это по двум причинам:
хочу регулярно проверять, что бэкапы действительно можно восстановить;
если продакшен упадёт, я смогу переключить трафик на реплику, которую уже можно запустить.
Возможно, я не всегда буду использовать её именно так, но хочу иметь такую возможность.
3. Защита от удаления в Terraform и AWS
Я включил защиту от удаления на двух уровнях:
в конфигурации Terraform;
в самой AWS.
Оба уровня защищают от случайного удаления.

Технически эти защиты всё ещё можно снять через CLI, если кто-то явно их отключит. Но они добавляют трение и помогают предотвратить случайные разрушительные действия.
4. Защита бэкапов в S3
Для бэкапов в S3 я включил версионирование. Если что-то удалят, предыдущие версии останутся доступны. Чтобы удалить бакет, сначала нужно удалить его содержимое, а это добавляет ещё один барьер.

5. Перенос Terraform state в S3
Самое важное: я перенёс Terraform state в S3.
State больше не хранится локально на одной машине. Теперь у Terraform есть единое и согласованное представление об инфраструктуре. Это убирает исходную проблему: я думал, что state уже лежит удалённо, хотя на самом деле он оставался локально на старом компьютере. Из-за этого и начали создаваться дублирующиеся ресурсы.
Когда state хранится в S3:
он не привязан к одному ноутбуку;
он не может тихо пропасть при переходе на другую машину;
у Terraform всегда есть согласованное представление об инфраструктуре.
Выводы
Этот инцидент — моя ошибка:
Я слишком сильно положился на ИИ-агента при запуске команд Terraform. Я отнёсся к plan, apply и destroy как к тому, что можно делегировать. Так я убрал последний защитный слой.
Я также слишком сильно положился на бэкапы, которые, как я предполагал, существуют. Автоматические бэкапы удалились вместе с базой данных. Я не проверил весь путь восстановления от начала до конца.
Базу данных было слишком легко удалить. Не хватало защитных механизмов, которые замедлили бы разрушительные действия.
Пока я ждал ответа поддержки AWS, мне пришлось всерьёз допустить, что данные могли исчезнуть навсегда.
Для активных курсов, где участники проходили финальные модули, я уже продумывал план восстановления. Для старых курсов это была бы безвозвратная потеря.
К счастью, поддержка AWS нашла снапшот и всё восстановила.
Что меняется теперь
Внедрённые защитные меры остаются.
Для Terraform:
агенты больше не выполняют команды;
каждый план проверяется вручную;
каждое разрушительное действие запускаю я сам.
Для AI Shipping Labs я думаю использовать отдельный AWS-аккаунт для дева и прода, чтобы нормально изолировать окружения до запуска.
Инструменты

nao: open-source-фреймворк для создания и развёртывания аналитических агентов, которые позволяют пользователям запрашивать данные на естественном языке, сохраняя при этом инженерный уровень контроля и надёжности. Data-команды задают структурированный версионируемый контекст через CLI, интегрируют его с любым data stack, покрывают качество модульным тестами и безопасно хостят всё у себя с собственными LLM-ключами. Бизнес-пользователи получают чат-интерфейс со встроенными визуализациями, прозрачной логикой рассуждений и встроенными циклами обратной связи.
Pilot Shell: профессиональная среда разработки для Claude Code, которая встраивает инженерные защитные механизмы прямо в рабочий процесс. Вместо сложной многоагентной обвязки она принудительно запускает тесты, линтинг, форматирование и проверку типов при каждом изменении, сохраняя контекст между сессиями. В результате получается агентный кодинг со встроенными продакшен-стандартами: разработчики могут делегировать задачи, отойти, а затем вернуться к проверенному коду, который соответствует соглашениям проекта и готов к отправке.
rtk (Rust Token Killer): производительный CLI-прокси, который снижает расход токенов LLM за счёт фильтрации и сжатия вывода команд до попадания в контекст модели. В типичных сессиях Claude Code он сокращает расход токенов на 60–90% для обычных операций: git, тестов, чтения файлов и поисковых команд. Это заметно снижает стоимость и повышает эффективность использования контекста. Инструмент специально сделан для разработки с участием AI, где большие выводы терминала иначе быстро забивают бюджет токенов.
Ещё три материала о том, как автоматизировать разработку и инфраструктуру, не теряя контроль над системой:
Почему AI-агенты ломаются на длинных задачах — и как обвязка помогает им дописывать приложения
Self‑service деплой: как перестать ждать DevOps и ускорить команду

Одна команда может снести прод за минуты, а восстановление занять сутки. Поэтому важно заранее понимать, где заканчивается удобная автоматизация и начинается риск для инфраструктуры.
На бесплатных открытых уроках преподаватели-практики покажут, как выстраивать устойчивые процессы, разбирать сбои и безопаснее работать с AI-инструментами:
22 июня, 20:00. «Роль и задачи DevOps в современном IT». Записаться
24 июня, 20:00. «Инцидент-менеджмент в SRE. Как быстро находить, устранять и предотвращать сбои в системе». Записаться
21 июля, 20:00. «Разработка ИИ-приложений с Claude Code». Записаться
На занятиях можно познакомиться с экспертами, оценить формат обучения и задать вопросы по своим рабочим кейсам.
Больше бесплатных уроков смотрите в дайджесте.























