跳到主要内容

为什么 AI 生成的 Terraform 和 Kubernetes 配置在潜移默化中出错

· 阅读需 13 分钟
Tian Pan
Software Engineer

大多数平台工程师都有过类似的故事:他们让 AI 助手生成一个 Terraform 模块或 Kubernetes 部署清单,结果看起来非常合理,CI 流水线也顺利通过了,但几周后坏事发生了。一个带有通配符权限的 IAM 角色。一个本不该公开的 S3 存储桶。一个因为没人检查安全上下文(security context)而以 root 身份运行的 Kubernetes pod。

核心问题不在于 LLM 写错了语法 —— 它们很少犯这种错。问题在于 IaC 的正确性与语法几乎无关。一个 terraform validate 允许通过的 Terraform 文件仍可能部署出一个安全灾难。一个 kubectl apply --dry-run=client 允许通过的 Kubernetes 清单仍可能调度具有危险能力的 pod。你的 CI 流水线用来检查代码的工具大多检查错了重点。

这篇文章是一份实战指南,旨在剖析 LLM 生成的 IaC 失败的具体方式、为什么这些失败能在团队现有的检查中存活下来,以及究竟什么才能捕捉到它们。

准确率数据不容乐观

在深入分类讨论之前,了解基准数据会有所帮助。IaC-Eval 基准测试 —— 在 NeurIPS 2024 上评估的 458 个由人类策划的 AWS 场景 —— 发现当时表现最好的模型在现实的 IaC 任务中仅达到了 19.36% 的 pass@1 准确率。以部署为中心的 DPIaC-Eval 基准测试衡量代码是否能真正正确部署(而不仅仅是通过语法验证),结果显示六大主流 LLM 的初次尝试成功率仅为 20–30%。

这些不是非主流模型。这些是在现实云基础设施任务上评估的最先进工具。 “语法有效” 与 “实际可用且安全” 之间的差距是巨大的。

不知道这些数字的团队往往会根据 “AI 生成的代码基本正确,只需要轻微检查” 的假设来调整他们的评审流程。实际的基准应该是:AI 生成的 IaC 代码经常以不明显的方式出错,你的评审人员需要知道该看哪里。

失败模式 1:幻觉依赖和幽灵属性

最常见的 LLM IaC 失败是引用了不存在的输出、属性或资源类型 —— 或者其存在方式与模型想象的不同。

常见例子:

  • Lambda 函数引用了一个并未从创建存储桶的模块中导出的 S3 存储桶 ARN
  • IAM 策略引用了一个 aws_s3_bucket 属性 (bucket_regional_domain_name),而该属性在提供商版本更新中已被重命名或删除
  • Terraform 模块到处使用 count 而不是 for_each,这会导致在列表中间添加或删除项时破坏资源寻址
  • 在重构过程中完全缺失了 moved 块,导致 Terraform 销毁并重建资源,而不是重命名它们

最后两点很微妙。countfor_each 的选择不是幻觉 —— 它是模型从旧示例中学到的一种模式,过去有效,但现在被认为是坑。缺失 moved 块意味着重命名变成了销毁并重建,在生产环境中,这对应着停机时间和数据风险。

这些失败不会出现在 terraform validate 中,因为该命令只检查语法和模块结构。它们也不会出现在 terraform plan 中 —— plan 会告诉你它将销毁那个数据库实例,但它不会告诉你那其实是个意外。

失败模式 2:绕过 Plan 检查的安全误配置

这一类别是最危险的,因为在每个自动化检查点,一切看起来都是正确的。

LLM 生成的 Terraform 经常引入的安全漏洞:

过于宽泛的 IAM 策略。 模型默认使用 Action: "*"Resource: "*" 的频率超出了应有的范围,特别是当你的提示词对角色需要访问哪些资源表述模糊时。最小权限 IAM 需要知道确切的操作列表和资源 ARN —— 这是模型通用推断出来的,而不是根据实际使用情况计算出来的。

公开的 S3 存储桶。 如果提示词提到某些内容需要被访问,模型可能会添加公共读取 ACL,或者忘记包含 aws_s3_bucket_public_access_block。这能通过 plan 检查,因为公共访问是一种有效的配置。

HCL 中硬编码的机密信息。 数据库密码和 API 密钥最终以字面量字符串的形式出现在 .tf 文件中,随后被提交到版本控制系统并写入 Terraform 状态文件。两者都会导致凭据持久泄露。

未加密的存储。 创建 EBS 卷、RDS 实例和 S3 存储桶时没有设置 encrypted = true 或等效项。云提供商的默认设置通常不开启加密 —— 模型生成的是它在训练示例中看到的内容,而这些内容往往偏向于编写示例时的流行做法。

敏感端口开放 0.0.0.0/0 的安全组。 在基于教程代码训练的模型中,对互联网开放 22 端口是一个持续存在的模式。这在技术上是有效的基础设施,本应由安全扫描器捕捉。

共同点是:terraform plan 将这些报告为成功的、无错误的资源配置。误配置是语义上的,而不是语法上的。

失败模式 3:过时的 Provider 模式

Terraform provider API 会发生变化。AWS 会发布破坏性更新。Kubernetes API 版本会弃用。模型的训练数据代表了过去某个时间点的文档和社区示例快照,而该快照并不能保持实时更新。

这表现为:

  • Terraform AWS provider v4 中被重命名或在 v5 中删除的属性(v4 到 v5 的迁移在 S3、DynamoDB 和 EC2 资源方面有重大的破坏性变更)
  • 使用 apps/v1beta1 而非 apps/v1 的 Kubernetes 清单(manifests),前者在 Kubernetes 1.16 中已被移除
  • 引用了在后续版本中重构的 L2 模式的 CDK construct
  • 在编写训练示例时与当前版本之间 schema 发生变化的 CloudFormation 资源属性

运行效果:代码在运行旧版本 provider 的环境中部署成功,但在另一个环境中失败或表现不一。或者,它在今天运行正常,但在一次没人意识到会影响现有代码的 provider 升级后发生故障。

失败模式 4:特定于 Kubernetes 的 RBAC 和 Security Context 漏洞

Kubernetes 清单具有独特的故障面。针对 LLM 生成的 Kubernetes YAML 的研究发现,35.8% 的清单包含质量问题 —— 而 Kubernetes 安全扫描器的数据显示,这些问题在开源清单中普遍存在。

在 AI 生成的配置中最常出现的类别:

缺失资源限制(Missing resource limits)。 未设置 resources.limits 的容器可能会消耗无限制的 CPU 和内存,导致“吵闹邻居”(noisy-neighbor)效应,在最坏的情况下会导致节点压力并驱逐其他工作负载。大约 58% 的开源 Kubernetes 清单缺少资源限制 —— 基础比率很高,而 AI 生成的代码并没有改善这一点。

不安全的 Security Context 默认设置。 以 root 身份运行的容器、在不需要时设置 privileged: true、缺少 allowPrivilegeEscalation: false 以及缺少 readOnlyRootFilesystem,这些模式都会出现在训练示例中,并被原封不动地复制。模型生成的是它所学到的内容,而它学到的内容通常没有经过加固。

权限过大的 RBAC。 为只需要命名空间范围访问的工作负载设置 ClusterRole 绑定。为只需要列出 pod 的服务账户设置 cluster-admin 绑定。模型对于“给予该工作负载 API 访问权限”的默认思维模型往往过于宽泛。

已弃用的 API 版本。 Kubernetes 有严格的弃用周期,模型的训练数据可能无法反映这一点。当 API 组被移除时,在一个集群版本上运行良好的清单在另一个版本上就会失败。

缺失 Liveness 和 Readiness 探针。 如果没有探针,Kubernetes 就没有信号来判断 pod 是否健康。流量会路由到正在运行但未提供服务的 pod。即使新 pod 已损坏,部署也会完成。

为什么你现有的检查会忽略大部分此类问题

使用 AI 生成 IaC 的团队通常已经运行了 terraform validateterraform plan 和一些 linting 工具。但这能捕获的问题比人们想象的要少:

  • terraform validate 检查语法和模块结构。它不会检查 IAM 语义、资源属性在远程 API 中的有效性或安全态势。
  • terraform plan 显示将要创建、修改或销毁的内容。它不会评估这些资源是否针对安全进行了正确配置。一个带有 "Action": "*" 的 IAM 策略在 plan 中显示为一个有效的资源 —— 它既是 plan 阶段的成功,也是安全方面的失败。
  • kubectl apply --dry-run=client 根据本地 schema 进行验证。它不会检查与实际集群服务器版本的 API 版本兼容性、资源限制、Security Context 设置或 RBAC 范围。

这些工具验证的内容与实际正确性要求之间的差距,正是 AI 生成的 IaC 故障潜伏的地方。

究竟什么能捕获这些故障

填补这些空白的工具链:

具有安全语义的静态分析。 Checkov 和 tfsec/Trivy 根据安全规则库分析 Terraform 和 Kubernetes 配置 —— Checkov 拥有 2,000 多个内置策略。它们能捕获 terraform plan 忽略的 IAM 通配符、公共 S3 配置、未加密的存储以及缺失的 Kubernetes Security Context。这些应该在每次 PR 的 CI 中运行,而不是可选的。

带有强制执行阈值的策略即代码(Policy-as-code)。 带有 conftest 的 OPA (Open Policy Agent) 允许团队将特定于组织的安全性要求编码为 Rego 策略,并针对 terraform plan 的 JSON 输出进行评估。HashiCorp Sentinel 在 HashiCorp 生态系统中发挥同样的作用。关键细节:策略应具有“强制执行”(hard-mandatory)模式以阻止应用(apply),而不是仅报告没人阅读的警告的“咨询”(advisory)模式。

特定于 Kubernetes 的 Linter。 kube-linter 和 kube-score 对 Kubernetes YAML 执行静态分析,标记缺失的资源限制、不安全的 Security Context、缺失的探针和权限过大的 RBAC。kubectl apply --dry-run=server(注意:是服务端,而非客户端)针对实际集群 API 进行验证,并能捕获已弃用的 API 版本。

Provider 版本锁定和漂移检测。required_providers 中锁定 Terraform provider 版本,可以防止由于训练数据版本不匹配导致的静默行为变化。漂移检测工具持续比较声明状态与实际状态,捕获已部署基础设施何时偏离了代码描述。

强制性的安全视角 Plan 审查。 自动化网关可以捕获已知的模式类别。它们无法捕获虽然是有效配置但在特定上下文中错误的语义错误 —— 例如,一个安全组正确地允许了 443 端口入站,但也允许了某人忘记移除的 22 端口。对 plan diff 的人工审核需要包括明确的 IAM、网络和加密抽查,而不仅仅是对创建正确资源类型的结构性验证。

理解鸿沟问题

存在一个更难防范的二阶风险:将 IaC 编写委托给 AI 助手的团队虽然提升了开发速度,但却失去了对基础设施的心智模型。

你接受的每一个没有完全追踪的建议,都是你对已部署内容理解上的一个鸿沟。这些鸿沟会不断累积。逐行编写 Terraform 的工程师会对每个资源的作用及其相互关系建立直觉。而仅在结构层面审查 AI 生成模块的工程师,其建立这种直觉的速度则慢得多。

这在出问题时至关重要。应对突发事件需要人员对基础设施有足够深入的理解,以便快速推断故障模式。如果一个团队在将 IaC 编写外包给 AI 助手的同时,没有通过刻意的评审实践来补偿,他们会在最糟糕的时机发现,没有人能清晰地掌握系统运行的全貌。

解决方法不是停止使用 AI 辅助,而是要清醒地意识到理解鸿沟存在于何处。要求评审人员在批准之前必须能解释每个资源的安全性态。定期对 AI 生成的模块进行架构评审。不要让心智模型退化。

你的评审流程需要哪些改变

由此产生的实际调整如下:

  • 在 CI 中运行 Checkov 和 kube-linter,并将其作为阻断性检查,而不仅仅是建议。对待失败的安全扫描应像对待失败的测试一样。
  • 针对组织内不可逾越的安全要求添加 OPA 或 Sentinel 策略——例如禁止使用 IAM 通配符、必须加密、特定的 CIDR 限制等。将这些设为硬性强制要求。
  • 对 Kubernetes manifest 使用 --dry-run=server(而非客户端 dry-run),这样可以根据你实际的集群版本捕获已弃用的 API 版本。
  • 在评审 AI 生成的 IaC 时,重点检查:IAM 权限(是否符合最小权限原则?)、网络暴露(哪些端口对互联网开放?)、加密设置、硬编码的机密信息。这些是 LLM 最容易出错的类别。
  • 不要将 terraform plan 的绿色通过视为配置正确的验证。Plan 是必要的,但不是充分的。

结论

LLM 生成的 IaC 在搭建骨架和编写样板代码方面确实非常有用。但如果无法理解它在哪些地方会出错,以及现有的检查手段无法捕获哪些问题,这种工具价值就会演变成生产事故。

这些失效模式是可预测的:幻觉产生的依赖关系、能通过 plan 检查的安全误配置、过时的 provider 模式,以及 Kubernetes 中关于 RBAC 和安全上下文(security context)的漏洞。缓解措施也是明确的:具有安全语义的静态分析、硬性执行的策略即代码(Policy-as-Code)、服务端 dry-run,以及专门针对自动化遗漏类别进行的评审流程。

较少被意识到的是“理解鸿沟”——当编写工作被过度委托给 AI 时,团队对基础设施心智模型的侵蚀。这是一个较慢发生且更难防范的问题,但它正是长期风险的集中所在。

References:Let's stay in touch and Follow me for more thoughts and updates