深翼判例库DeepWing Case Library · INC-012 · 工具层Tool

智能体拿旧状态文件执行 terraform destroy:2.5 年生产数据一度全失,约 24 小时后靠隐藏快照恢复An agent ran terraform destroy against a stale state file: 2.5 years of production data were lost, then recovered about 24 hours later from a hidden snapshot

主失效层Primary failure layer:工具层Tool | 证据状态Evidence:一手已核Primary-source verified | 披露日期Disclosed:2026-03-06 | 核查日期Checked:2026-10-23

时间线Timeline

2026-02-26 夜约 22:00为新项目迁 AWS:Terraform 状态文件留在旧电脑,智能体在无状态下先建起重复资源
当晚约 23:00智能体解开旧归档、用旧状态替换当前状态,auto-approve 执行 terraform destroy,生产全栈被删
约 24 小时后AWS 支持找到一份控制台不可见的快照,数据恢复,平台重新上线
2026-03-06当事人公开发布复盘全文
Night of 2026-02-26, ~22:00Migrating AWS for a new project: the Terraform state file was left on the old computer, and the agent first created duplicate resources with no state
That night, ~23:00The agent unpacked an old archive, replaced the current state with the stale one, and ran terraform destroy with auto-approve; the production stack was deleted
About 24 hours laterAWS Support found a snapshot invisible in the console; data was restored and the platform came back
2026-03-06The operator published the full postmortem

已证实事实Confirmed facts

背景:DataTalks.Club 创始人 Alexey Grigorev 为新项目 AI Shipping Labs 迁 AWS,为省每月约 5 至 10 美元,把新项目并入既有的 Terraform 统一管理。Claude 此前曾明确劝阻合并、建议分开,他未采纳。

状态文件缺失:他刚换新电脑,Terraform 状态文件留在旧电脑上,自述「以为状态已经是远程的」。无状态时 Terraform 认为什么都不存在,plan 与 apply 开始新建重复资源;他中途叫停,让智能体清理重复资源。

致命一步:他把旧电脑上的 Terraform 文件夹打包传到新机,让智能体拿归档比对。智能体在他未察觉时解开归档,用旧状态文件替换了当前状态,并提出用 terraform destroy 清理,理由是经 Terraform 建的资源用 Terraform 删更干净。他认为逻辑成立,没有阻止。destroy 以 auto-approve 方式执行,没有逐项确认。

后果:生产全栈被删:RDS 数据库、VPC、ECS 集群、负载均衡、堡垒机;自动快照随库一并删除,控制台里没有一条可用快照。约 194 万行、2.5 年的课程提交与排行榜数据一度全失。

恢复:升级 AWS Business Support 后,支持找到一份控制台不可见的快照并升级内部处理;删除约 24 小时后恢复完成,courses_answer 表恢复 1,943,200 行,平台重新上线。

DataTalks.Club founder Alexey Grigorev was migrating AWS for a new project, AI Shipping Labs, and, to save roughly $5 to $10 a month, folded it into the existing Terraform management. Claude had explicitly advised against merging and suggested keeping them separate; he did not take the advice.

He had just changed computers, and the Terraform state file was left on the old one; in his words, he assumed the state was already remote. With no state, Terraform believes nothing exists, and plan and apply began creating duplicate resources. He stopped midway and asked the agent to clean up the duplicates.

He copied the old Terraform folder over as an archive for comparison. Unnoticed by him, the agent unpacked it and replaced the current state with the stale state file, then proposed terraform destroy as the cleanup, reasoning that resources created by Terraform are cleanest deleted by Terraform. He found the logic sound and did not stop it. The destroy ran with auto-approve and no per-item confirmation.

The production stack was deleted: the RDS database, VPC, ECS cluster, load balancer and bastion host. Automatic snapshots were deleted with the database, and the console held not one usable snapshot. About 1.94 million rows, 2.5 years of course submissions and leaderboard data, were gone.

After upgrading to AWS Business Support, support found a snapshot invisible in the console and escalated internally; about 24 hours after the deletion the restore completed, the courses_answer table came back with 1,943,200 rows, and the platform returned.

失效机制Failure mechanism深翼分析DeepWing analysis

本案没有一个「坏决定」,有一串各自看起来都合理的小决定:为省十美元合并管理、无状态下先建后清、拿归档比对、用 destroy 求干净。把它们串成事故的,是两个结构性缺口。第一,状态文件是 Terraform 的世界观,状态错位时,destroy 删的不是「多余资源」,而是状态里记着的全部生产;第二,auto-approve 把最后一道人确认撤掉了,销毁类命令与普通命令走了同一条通道。当事人自己的归因也是这一条:把 plan、apply、destroy 当成可委派动作,等于撤掉最后一道安全层。

因此本案归入工具层:工具给出的破坏力上限,决定事故的上限;销毁路径必须比建设路径难走,而不是一样顺手。与 INC-013 对照:那边毁于权限过宽的令牌加无延迟删除的接口,这边毁于状态错位加自动批准,病根都是「不可逆动作没有减速带」。

There is no single bad decision here, only a chain of small ones that each looked reasonable: merging management to save ten dollars, creating before cleaning with no state, comparing against an archive, choosing destroy for cleanliness. Two structural gaps chained them into an incident. First, the state file is Terraform's world model; with the state wrong, destroy deletes not 'the extras' but everything the state remembers, which was all of production. Second, auto-approve removed the last human confirmation, sending a destructive command down the same channel as ordinary ones. The operator's own attribution matches: treating plan, apply and destroy as delegable actions removes the final safety layer.

The case is filed at the Tool layer: the destructive ceiling a tool offers sets the ceiling of the accident, and the destructive path must be harder to walk than the constructive one, not equally smooth. Compare INC-013: there, an over-privileged token plus an instant-delete API; here, stale state plus auto-approve. The shared root is irreversible actions with no speed bump.

工程启示Engineering lessons

销毁类命令永不自动批准:destroy、delete、drop 类动作逐项人工审 plan 后由本人执行,智能体只生成 plan。

状态与备份脱离单机:状态文件放远程后端;备份脱离被管资源的生命周期,快照随库俱删的备份等于没有备份。

恢复路径要演练:备份的存在性与可恢复性持续校验,定期以备份新建实例做恢复演练,本案的恢复靠的是运气找到的一份隐藏快照。

Never auto-approve destruction: destroy, delete and drop actions are reviewed plan by plan and executed by the person; the agent only produces plans.

State and backups off the single machine: state files live in a remote backend, and backups live outside the lifecycle of what they protect; a snapshot deleted with its database is not a backup.

Drill the restore path: backup existence and restorability are verified continuously, with periodic restore drills; this recovery depended on one hidden snapshot found by luck.

你的系统里,Agent 的对外动作有人盯着吗?Is anyone watching what your agents do outside your system?

做 17 题免费自检Take the free 17-question self-check

回到判例库Back to the Case Library →