一次看似普通的 Terraform 部署让 DataTalks.Club 的 200 万条课程数据瞬间消失网站停摆 24 小时。这是创始人 Alexey Grigorev 在复盘里写下的真实事故他让 Claude Code 直接执行完整部署流程跳过 terraform plan 的人工确认最后 AI 的一条terraform destroy命令清空了整个生产环境。如果你也在用 Claude Code 辅助基础设施变更接入通道和权限控制必须同时解决。先通过 TaoTokenhttps://taotoken.net/?utm_sourcetaotoken_aicg_blog_end创建 API Key再把 Base URL 指到统一兼容通道同时关闭 Claude Code 的自动执行权限让 AI 只生成 terraform plan由人核对完资源变更再手动 apply/destroy。1. 复盘事故链条一条 destroy 指令如何清掉两年半数据1.1 两个项目塞进同一份 Terraform 配置Alexey 当时正在把 AI Shipping Labs 从 GitHub Pages 迁到 AWS。按照他的计划静态站先放到 S3DNS 迁过去再在子域名部署 Django 版本。这个迁移方案的架构本身没毛病问题出在「基础设施放哪」这个决定上。他为省每月 5 到 10 美元的 VPC 费用没有给新项目建独立环境而是直接把它加进 DataTalks.Club 现有的 Terraform 配置里。两个项目的资源开始共享同一套 VPC、ECS 集群、负载均衡器和 bastion 主机。Claude Code 当时其实提醒过最好创建独立环境但 Alexey 认为不划算坚持复用。这一步让两个项目的基础设施变更混在同一个state 文件里为后面的灾难埋了雷。这给我们的第一个教训是Terraform 的 state 文件就是基础设施的账本。只要两个项目写进同一份配置任何针对这份配置的批量操作都会同时影响两边。省下的 5-10 美元最终换来了 24 小时的网站停摆。1.2 新电脑少了 state 文件Terraform 把生产环境当成空目录2 月 26 日晚上Alexey 通过 Terraform 部署网站更新。正常的 Terraform 流程会先执行terraform plan把要创建、修改、删除的资源列出来给工程师确认。但他直接让 Claude Code 跑完整流程跳过了人工审核这一步。终端开始不断输出「创建资源」的日志。注意生产环境早就运行几个月了正常情况下不应该出现大量创建动作。Alexey 察觉不对暂停执行后问 Claude Code「为什么要创建这么多资源」。答案出人意料Terraform 认为当前环境是空的。原因是他的 state 文件没跟上。Alexey 最近换了台新电脑记录云基础设施真实状态的terraform.tfstate文件还留在旧设备上。Terraform 没有这个文件就不知道 AWS 上已经存在哪些资源自然把这次部署当成从零搭建全新环境。他中断部署时已经有一部分重复资源被创建出来了。这里值得多想一层Claude Code 执行的命令基于它当时拿到的状态做判断它并不知道你换了电脑、state 文件在另一台机器上。AI 不掌握你的环境元信息凡是「应该知道但没写进上下文」的信息缺失都会让它做出和现实脱节的决策。1.3 旧 state 替换当前 statedestroy 把生产环境连根拔起发现重复资源后Alexey 让 Claude 用 AWS CLI 分析环境区分「刚才新建的」和「原有生产环境的」然后删除重复资源。Claude 删了一会儿告诉他已经识别出重复资源并开始清理。Alexey 觉得一切正常就把旧电脑里的项目目录打包传回新电脑。这个归档目录里装着完整的 Terraform state 文件。他把归档文件交给 Claude Code让它继续清理。Claude Code 解压归档用里面的旧 state 文件替换了当前 state 文件。那个旧 state 记录的不是临时资源而是 DataTalks.Club 课程平台的全部基础设施。接着 Claude Code 表示既然这些资源由 Terraform 创建用 Terraform 删除会更干净所以它将执行terraform destroy。从命令执行的角度看这句话挑不出毛病但它的前提错了。被 destroy 的资源清单来自一个被旧 state 替换过的文件。于是terraform destroy把数据库实例、VPC、ECS 集群、负载均衡器、bastion 主机全部删光。打开课程平台时网站已经无法访问过去两年半的作业、项目、排行榜记录全没了。2. 拿 Key在 TaoToken 创建 API Key 并确认模型 ID2.1 注册、创建 API Key在复现「Claude Code 辅助 Terraform」这个工作流之前先要解决模型调用通道的问题。Claude Code 默认连接 Anthropic 官方入口而国内开发者在网络连通性、额度管理、多模型切换上会遇到不少额外限制。这里我用的是 TaoToken 提供的统一 API 兼容通道它做的事情是把各种模型接口收敛成一个标准的https://taotoken.net/api端点Claude Code 只要改一下 Base URL 和 Key 就能用。第一步打开 TaoToken 注册账号登录后进入控制台的 API Keys 页面创建一把 Key。创建成功后把 Key 复制下来它的形式接近YOUR_API_KEY后续要填进 Claude Code 的环境变量。注意这个 Key 只在创建时完整显示一次关掉页面就看不到了。这里有一个容易混淆的点TaoToken 的官网落地页和接口地址是两回事。注册、创建 Key、查看用量、浏览模型广场都走 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 要填进 Claude Code 的 Base URL 则是https://taotoken.net/api末尾不需要再加/v1。官网负责管账号接口负责跑请求两件事别串在一起。2.2 在模型广场确认模型 IDClaude Code 的ANTHROPIC_MODEL环境变量需要填一个具体的模型 ID。这个 ID 不要凭印象编打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的模型广场看当时列出的模型列表。每个模型卡片上会标注模型 ID、上下文长度、价格等信息以那里的标注为准。确认模型 ID 的原因在于Claude Code 会把默认模型 ID 发给服务端如果通道里没有对应 ID请求会直接 404。把模型广场上实际存在的 ID 填进去请求才能命中正确的模型。3. 把 Claude Code 指向 TaoToken 的 Base URL3.1 环境变量方式配好 Key 和模型 ID 后最直接的接法是用环境变量。在终端里执行export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKENYOUR_API_KEY export ANTHROPIC_MODEL从模型广场复制的模型ID export ANTHROPIC_MODEL_PROVIDERanthropicANTHROPIC_BASE_URL填入的是https://taotoken.net/api末尾不要加/v1。官网落地页只承担注册、创建 Key、看模型广场、看用量这类控制台功能填进工具的是接口地址两者不要混用。如果不想每次开终端都 export 一遍可以把这三行写进 shell 的配置文件.zshrc或.bashrcecho export ANTHROPIC_BASE_URLhttps://taotoken.net/api ~/.zshrc echo export ANTHROPIC_AUTH_TOKENYOUR_API_KEY ~/.zshrc echo export ANTHROPIC_MODEL从模型广场复制的模型ID ~/.zshrc source ~/.zshrc3.2 settings.json 方式更推荐的做法是直接写进 Claude Code 的项目配置。Claude Code 启动时会读取~/.claude/settings.json把环境变量和权限规则一起放进去。配置文件里这样写{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: 从模型广场复制的模型ID } }保存后重启 Claude Code输入/status查看当前生效的模型、Base URL 和账号。如果/status里显示的 Base URL 仍是官方地址说明settings.json没被正确加载检查文件路径是否在~/.claude/settings.json。这个文件里写入的 env 会覆盖终端里 export 的同一变量。4. 用 permissions 配置给 Terraform 加一道人工审核闸门4.1 禁止 AI 直接执行 apply/destroy接入通道只是让 Claude Code 能调用模型真正防止删库要靠权限配置。Alexey 在事后复盘里改成关闭 Claude Code 的所有自动执行权限不允许它直接写文件或运行命令。落到 Claude Code 的配置就是 settings.json 里的 permissions 块{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: 从模型广场复制的模型ID }, permissions: { defaultMode: plan, allow: [ Bash(terraform plan:*), Bash(terraform validate:*), Bash(terraform fmt:*) ], deny: [ Bash(terraform apply:*), Bash(terraform destroy:*), Bash(aws s3 rm:*), Bash(rm -rf:*) ] } }这里defaultMode: plan让 Claude Code 默认只输出计划不执行操作allow只放行terraform plan、terraform validate、terraform fmt这类只读命令deny把terraform apply、terraform destroy、aws s3 rm和rm -rf全部挡死。这样就算模型想删资源手里也没有可执行的命令。4.2 让 AI 只生成 plan人来执行变更权限配置完工作流就变了。以前是「说一句部署更新Claude Code 自动跑 plan apply」现在是向 Claude Code 描述要做的变更例如把 AI Shipping Labs 的静态站迁到 S3。Claude Code 只运行terraform plan把资源变更清单输出到终端。你逐条看变更清单确认没有意外的删除动作。确认无误后自己手动执行terraform apply或terraform destroy。把执行结果贴回对话让 Claude Code 根据输出结果继续解释或排查。原文事故里Alexey 就是把第 4 步也交给了 Claude CodeAI 才拿到了terraform destroy的执行权。现在权限被 deny 掉之后模型再怎么觉得应该删也只能停在生成 plan 的阶段。依赖对话约束「你不要执行 destroy」也能挡住大部分情况但不可靠。模型在长对话里会把之前的上下文逐渐淡忘也可能在你多次追问后改变主意。把命令写进permissions.deny是文件层面的硬约束和模型状态无关。这也是原文复盘里「关闭所有自动执行权限」的思路不要依赖 AI 自觉要依赖配置拦截。5. 安全的 Terraform 变更流程state 核对、plan 审查、本地执行5.1 先核对 state 文件再让 AI 碰基础设施开始变更前确认当前机器的terraform.tfstate就是生产环境的真实状态。原文事故的直接导火索就是旧电脑的 state 文件被传回来后替换了当前 state。如果 state 不对后面所有 plan 和 apply 都是在错误的地基上盖楼。可以在让 Claude Code 工作前先跑一遍terraform state list把当前 state 里管理的资源拉出来看一眼。如果列表和自己预期的不一样比如少了数据库实例说明 state 文件有问题先把它修好再继续不要直接terraform plan。要让 AI 分析变更影响时明确告诉它「只运行 plan把将要创建和删除的资源分类列出来不要执行 apply 或 destroy。」把这句话写进每次对话的上下文Claude Code 就不会自作主张切到执行模式。5.2 plan 审查时重点看几类资源人工审核terraform plan的输出时优先关注这几类资源数据库实例aws_db_instance、存储桶aws_s3_bucket、网络资源aws_vpc、aws_subnet和负载均衡器aws_lb。这几类一旦被删除对业务的影响是全局性的。如果 plan 输出显示要 destroy 一个你没打算动的资源立即中断。像原文里那种「为什么创建这么多资源」的异常就是最典型的信号。plan 是一次低成本的安全检查apply 之后想后悔就晚了。对于数据库除了代码层面的保护还得在 AWS 控制台侧打开deletion_protection。Terraform 配置里对应的写法是resource aws_db_instance production { # 其他参数不变 deletion_protection true }deletion_protection开启后即使有人执行terraform destroyRDS 也会拒绝删除数据库。这是 Terraform 权限之外的第二道保险。5.3 演练恢复而不是假设有备份就行原文里另一个教训是Alexey 以为每天凌晨 2 点有自动备份但生产环境被删后打开 RDS 快照列表是空的后来 AWS 支持团队找到了一份用户不可见的隐藏快照才把数据找回来。这个隐藏快照不是每次都有的不能拿运气当方案。建议做一个低成本恢复演练每天备份任务执行完后自动创建一个数据库副本对这张副本跑一条查询验证数据可读。恢复链路走不通备份形同虚设。Terraform 只管基础设施的创建和删除真正到了恢复阶段拼的是备份是否在 Terraform 生命周期之外独立存活。如果真遇到数据被删的紧急情况第一时间联系云厂商支持并升级支持计划响应速度会快很多。但这不是常规手段只是最后一根救命稻草。6. 验证调用与常见排障6.1 在控制台核对这次调用是否记账配置全部完成后先在 Claude Code 里发一条测试消息看看请求是否正常返回。如果返回正常打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的用量页面确认这次调用已经被记录。用量页会显示每次请求的时间戳、模型 ID 和 token 数。跑一次 terraform plan 的对话通常会产生几千到几万 token 的消耗和模型上下文长度有关。如果用量页里看不到刚发出的测试请求优先怀疑 Key 是否填错或者请求是否真的走到了 TaoToken 的接口。如果打算长期用 Claude Code 写 Terraform建议在 Coding Plan 页面选择一个适合自己的套餐按量付费和包月套餐在长期跑自动化任务时的成本差别不小。当前 Key 不够用或者想换一个模型回 控制台 API Keys 创建或管理即可。6.2 常见报错401 和 404接入过程中最常见的两个报错一个和 Key 有关一个和模型 ID 有关并且都能在用量页或错误信息里定位到原因。401 UnauthorizedKey 不对。检查ANTHROPIC_AUTH_TOKEN是否复制完整有没有多复制空格或换行。Key 要从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的 API Keys 页面重新复制后再试一次。404 Not Found模型 ID 不存在或 Base URL 路径写错。在模型广场重新复制正在使用的模型 ID覆盖到ANTHROPIC_MODEL。同时检查 Base URL 是不是被写成了https://taotoken.net/api/v1/多了/v1会直接 404正确写法是https://taotoken.net/api。把terraform destroy的权限交给 AI省下的只是几秒钟手动输入风险却是整个生产环境。TaoToken 解决的是「模型调用走统一兼容通道」这件事人工审核解决的是「危险命令谁来扣扳机」。先在 模型对话 页面用同一把 Key 发一条测试消息再回 Claude Code 跑一个terraform plan试试完整链路。环境变量的对应关系也可以直接查 Claude Code 接入文档对照着改不容易漏项。