使用 conftest 安全地自动应用 Terraform
摘要
本文介绍了如何使用 conftest(一个基于 Open Policy Agent 的策略即代码工具)安全地自动化 Terraform 自动应用,通过使用 Rego 策略确定性评估 Terraform 计划,从而消除人工审核瓶颈,同时保持可审计性。
<p><a href="https://lobste.rs/s/yapgzf/safe_terraform_auto_apply_with_conftest">评论</a></p>
查看缓存全文
缓存时间: 2026/06/09 10:43
# 使用 conftest 实现安全的 Terraform 自动部署
来源:https://www.bejarano.io/terraform-autoapply/
你熟悉这个流程:有人做了变更,Terraform 执行 plan,有人审核、批准,然后 apply。在变更速度较低时,这套流程能正常工作。审核者能发现偶发错误,大家都能安心睡觉。
但超过某个临界点后,**审核者就成了瓶颈**。Plan 堆积成山,工程师要么匆忙扫一眼,要么干脆放着不管,审核效率或质量总有一个会下降——往往两者同时下降。
我们立刻想到的下一件事是**把审核交给 AI**。虽然你可以用 AI **辅助** plan 审核——目前我看到的最有趣的方案是 Overmind↗ (https://overmind.tech/)——但你无法完全把 plan 审核委托给 AI,尤其是在生产基础设施上:
- 它是**非确定性的**:同一个 plan 今天可能通过,明天可能失败;
- 它经常**违反审计/合规要求**,这些要求强制需要人工签核并明确责任归属;关键是
- 它**将责任从反馈循环中剥离**,没有人最终为决策负责,而这正是出问题时你最不希望看到的。
还有第三种选择:**用策略即代码以编程方式、确定性地评估 Terraform plan**。这正是我们用 conftest↗ (https://www.conftest.dev/) 所做的事情。
conftest↗ (https://www.conftest.dev/) 是一个基于 Open Policy Agent↗ (https://www.openpolicyagent.org/) 构建的策略即代码工具。你用 Rego↗ (https://www.openpolicyagent.org/docs/latest/policy-language/) 编写策略,输入 JSON 数据,它会告诉你数据是否符合策略。
关键洞察是:**Terraform 可以将 plan 导出为 JSON**:
```
terraform plan -out=plan.tfplan
terraform show -json plan.tfplan > plan.json
```
这个 JSON 文件包含了 **Terraform 打算执行的每一个资源变更**:哪些资源被创建、更新、删除,以及每个属性的 before/after 值。这些信息与人工审核者查看的信息完全相同,只不过是以结构化格式呈现,可供 conftest 这样的策略引擎评估:
```
conftest test plan.json
```
如果 plan 符合你的策略,就通过;否则失败并给出明确原因。**这个决策是可审计、可测试且可复现的。**
## 一个例子策略
下面是一个 Rego 策略,它只允许每个变更都是 no-op、资源创建或数据源读取的 plan。任何更新或删除都会导致策略失败:
```
package main
import rego.v1
safe_actions := {"no-op", "create", "read"}
deny contains msg if {
some resource_change in input.resource_changes
some action in resource_change.change.actions
not action in safe_actions
msg := sprintf(
"resource %q has action %q, which is not in the safe set %v",
[resource_change.address, action, safe_actions],
)
}
```
这个策略遍历 JSON 格式 Terraform plan 中的每个 `resource_changes` 条目,检查其所有动作是否都在 `safe_actions` 集合中。如果有任何动作不在该集合内(一个 `update` 或 `delete`),策略就会发出拒绝信息,指出违规的资源及其动作。
就这么简单。**如果这个策略通过了,说明该 plan 只创建新资源、读取数据源或什么都不做,因此可以安全地自动应用。** 如果失败,则流水线停止,由人工审核。
***注意:** 取决于你使用的 Terraform provider,创建新资源也可能并非完全无害。这里的重点是,你可以根据自己的组织对“可以安全自动应用的 plan”的定义来制定策略,下面我们还会看到更多例子。*
## 将其集成到流水线中
CI/CD 集成很简单。在 Terraform 执行 plan 之后,将 plan 导出为 JSON,运行 `conftest`,然后根据结果进行分支:
```
terraform plan -out=plan.tfplan
terraform show -json plan.tfplan > plan.json
if conftest test plan.json; then
terraform apply plan.tfplan
else
# 等待人工审批
fi
```
这种方法之所以有效,是因为决策边界是**明确的**。你不是在要求某人(或某物)判断一个 plan 是否“看起来安全”,而是在检查它是否符合你定义、测试并随基础设施代码一起版本化的一系列规则。
## 扩展策略
上面的例子故意保持最小化:它只允许创建、数据源读取和 no-op。在实际中,你会需要更丰富的策略,而 JSON 格式的 Terraform plan 提供了丰富的可用信息:
**资源类型。** 并非所有资源都带有相同的风险。你可能允许 CloudWatch 报警自动应用,但 RDS 实例或 IAM 策略则必须人工审核。每个 `resource_changes` 条目中的 `type` 字段可以帮你实现这一点:
```
safe_resource_types := {"aws_cloudwatch_metric_alarm"}
deny contains msg if {
some resource_change in input.resource_changes
not resource_change.type in safe_resource_types
some action in resource_change.change.actions
action not in {"no-op", "read"}
msg := sprintf("resource %q has type %q, which is not in the auto-apply safe set", [resource_change.address, resource_change.type])
}
```
**资源字段。** 有时仅靠资源类型还不够——你可能希望只自动应用那些只修改某些特定属性的变更。JSON plan 中的 `change` 对象允许你对比各个字段。以下策略拒绝任何修改了除 `tags` 之外的字段的更新:
```
deny contains msg if {
some resource_change in input.resource_changes
some action in resource_change.change.actions
action == "update"
changed_keys := {key |
some key in object.keys(resource_change.change.after)
resource_change.change.before[key] != resource_change.change.after[key]
}
changed_keys != {"tags", "tags_all"}
msg := sprintf("resource %q changes fields other than tags: %v", [resource_change.address, changed_keys])
}
```
**影响范围。** 一个影响 2 个资源的 plan 与影响 200 个资源的 plan 完全不同。你可以统计有实际变更的资源数量,并在超过某个阈值时要求人工审核:
```
max_auto_apply_changes := 10
deny contains msg if {
changed := {resource_change.address |
some resource_change in input.resource_changes
some action in resource_change.change.actions
action not in {"no-op", "read"}
}
count(changed) > max_auto_apply_changes
msg := sprintf("plan affects %d resources, which exceeds the auto-apply limit of %d", [count(changed), max_auto_apply_changes])
}
```
**环境。** 在 staging 环境自动应用,在生产环境需要人工审核。如果你的资源带有环境标签,你可以从 plan 中读取。以下策略拒绝任何非 trivial 的变更,除非其 `Environment` 标签值为 `staging`:
```
deny contains msg if {
some resource_change in input.resource_changes
some action in resource_change.change.actions
action not in {"no-op", "read"}
resource_change.change.after.tags.Environment != "staging"
msg := sprintf("resource %q is not in staging, requires human review", [resource_change.address])
}
```
这些规则可以组合使用。你可以将它们放在同一个策略文件中,`conftest` 会评估所有规则。一个 plan 必须通过 **每一条** 规则才能自动应用,任何一条拒绝都足以使策略失败。策略会随着你的信心增长而发展,并且因为它是代码,你可以像对待其他代码一样对其进行版本控制和测试。
当你开始在软件开发流程中引入 AI agent,并让它们提议并执行对生产基础设施的变更时,这种机制就变得更加重要。如果没有一种确定性的方式来证明 plan 的安全性,**你要么牺牲信心,要么牺牲效率,或者两者兼失**。
相似文章
实证软件工程TerraProbe:一种用于检测LLM辅助Terraform中欺骗性修复的分层预言框架
TerraProbe引入了一个五层预言评估框架,用于检测LLM辅助Terraform安全修复中的欺骗性修复,揭示此类修复在Gemini、GPT-4o和Claude等模型中具有系统性。本文提供了欺骗性修复的分类法以及一个用于评估IaC安全修复的复现包。
hashicorp/terraform
Terraform 是 HashiCorp 提供的一款基础设施即代码工具,用于安全高效地构建、变更和版本化管理基础设施。
@ethanolivertroy: 昨晚想到了 @cursor_ai bugpot 的合规版本,并开始用 cu… 将各部分拼凑在一起。
ControlBot 是一个开源工具,使用 Checkov 和 Cursor SDK 审查 Terraform PR 是否符合 NIST 800-53 合规标准,并提供内联注释和合并门控。
面向企业AI智能体的部署前保障:基于本体论的仿真与信任认证
研究人员提出了一种基于本体论的企业AI智能体部署前验证框架,结合了智能体操作包络、自动化场景生成以及可机器验证的信任证书与分级部署判定。在四个受监管行业开展的试点研究共生成1,800个测试场景,结果显示基于本体论的生成方法在监管覆盖率上显著优于基于角色的基线方法。
自动化审批流程:如果由AI代理管理部署门禁?
探讨了使用AI代理自动化部署门禁审批的概念,可能提高CI/CD流水线效率。