3. 策略即代码基础

在 Terraform 变更治理中,“策略即代码”(Policy as Code,PaC)意味着把原本写在文档、口头约定或人工评审清单里的规则,转写成可版本化、可测试、可自动执行的代码。Terraform 本身只负责“把基础设施变成声明的样子”,它并不判断这个声明是否合规。策略引擎补上的正是这一层:在 terraform plan 之后、terraform apply 之前,对计划(plan)或配置(HCL)做静态判断,决定放行、告警还是阻断。

理解策略引擎,关键不是记住工具名字,而是分清它们各自“看什么、在哪看、能看多深”。下面这张图把三类主流引擎放在同一条 Terraform 工作流上,标出它们的介入位置与判断对象。

Terraform 工作流与策略引擎介入点 编写 HCL .tf 配置 terraform plan 生成执行计划 策略校验 放行 / 告警 / 阻断 terraform apply 落地资源 合规基础设施 可审计、可追溯 Sentinel(HashiCorp) 介入点:plan / apply 之间 判断对象:plan JSON、state 语言:Sentinel DSL(专用) 能力:细粒度、可访问资源属性 边界:仅 Terraform 生态 典型:Terraform Cloud/Enterprise 适合:平台团队统一管控 OPA / Conftest 介入点:plan JSON、YAML、JSON 判断对象:任意结构化数据 语言:Rego(通用声明式) 能力:跨工具、跨云统一策略 边界:需自行转换 plan 为 JSON 典型:conftest test plan.json 适合:多云、多工具统一治理 Checkov(Bridgecrew) 介入点:HCL 源码、plan 判断对象:配置本身 语言:Python 规则 + 内置策略 能力:开箱即用、规则库丰富 边界:自定义深度有限 典型:checkov -d ./terraform 适合:快速建立基线合规

三类引擎的定位差异

Sentinel 是 HashiCorp 自研的策略语言,深度嵌入 Terraform Cloud/Enterprise 的 run 流程。它的优势在于能直接读取 plan 中的资源属性,例如判断某个 aws_s3_bucket 是否开启了版本控制、某个安全组是否对 0.0.0.0/0 开放了 22 端口。Sentinel 的策略以 main 规则返回 true 或 false,配合 enforcement_level 可设为 advisory(仅告警)、soft-mandatory(可覆盖阻断)或 hard-mandatory(强制阻断)。它的边界也很明确:只服务于 Terraform 生态,离开 HashiCorp 平台就无法运行。

OPA(Open Policy Agent)与 Conftest 走的是通用路线。OPA 用 Rego 语言描述策略,输入是任意 JSON 数据;Conftest 则是 OPA 的封装,专门用于测试配置文件。在 Terraform 场景中,通常先用 terraform show -json plan.out > plan.json 把计划转成 JSON,再执行 conftest test plan.json。Rego 的表达能力很强,可以写循环、集合运算和复杂条件,因此适合多云、多工具(Terraform、Kubernetes、Dockerfile)统一治理。代价是学习曲线较陡,且需要自己维护 plan 到 JSON 的转换链路。

Checkov 是静态扫描工具,直接读取 HCL 源码或 plan 文件,内置数百条针对 AWS、Azure、GCP 的合规规则。它最大的价值是“开箱即用”:安装后执行 checkov -d ./terraform,就能得到一份带严重级别的检查报告。对于想快速建立安全基线的团队,Checkov 的投入产出比最高。但它的自定义规则需要用 Python 编写,灵活性和表达力不如 Rego,深度定制场景下会受限。

选型对比与决策依据

维度SentinelOPA / ConftestCheckov
策略语言Sentinel DSLRegoPython + 内置规则
判断对象plan / state任意 JSON/YAMLHCL / plan
跨工具能力弱(仅 Terraform)强中(多云配置)
上手成本中高低
自定义深度高很高中
运行位置Terraform Cloud/Enterprise本地 / CI 任意位置本地 / CI 任意位置
典型命令sentinel testconftest testcheckov -d

选型时先问三个问题:第一,策略要跑在哪里?如果团队已经使用 Terraform Cloud/Enterprise,Sentinel 是原生选择,无需额外搭建执行环境;如果策略要在本地和 CI 中自由运行,OPA/Conftest 和 Checkov 更合适。第二,策略需要多深?只需要检查“S3 是否加密”“安全组是否开放 22 端口”这类常见基线,Checkov 内置规则即可覆盖;需要跨资源关联判断(例如“所有带 env=prod 标签的 RDS 必须开启多可用区”),Rego 或 Sentinel 更合适。第三,团队愿意投入多少学习成本?Rego 功能最强但最难学,Checkov 最易上手但定制受限,Sentinel 介于两者之间且与平台绑定。

实践中常见组合是:用 Checkov 做第一道快速基线扫描,用 Conftest/OPA 做跨工具的统一策略层,用 Sentinel 在 Terraform Cloud 中做最终强制阻断。三者并不互斥,而是分层协作。

一个可执行的 Conftest 策略示例

下面用 Rego 写一条真实可用的策略:禁止任何 S3 存储桶缺少 server_side_encryption_configuration。假设 plan JSON 中资源类型为 aws_s3_bucket,策略文件保存为 policy/s3_encryption.rego。

package main

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_s3_bucket"
  resource.change.actions[_] == "create"
  not resource.change.after.server_side_encryption_configuration
  msg := sprintf("S3 桶 %s 未配置服务端加密", [resource.address])
}

执行流程为:先生成计划文件 terraform plan -out=tfplan,再转换为 JSON terraform show -json tfplan > plan.json,最后运行 conftest test plan.json --policy policy/。如果输出中包含 FAIL - plan.json - main - S3 桶 aws_s3_bucket.logs 未配置服务端加密,说明策略命中,CI 应返回非零退出码阻断合并。若输出 PASS,则放行。这条链路把“加密要求”从文档变成了可执行、可回归的代码。

策略引擎只能判断“配置是否符合规则”,不能替代运行时安全扫描和渗透测试。例如策略可以要求安全组不开放 22 端口,但无法发现应用层漏洞。策略即代码是治理的一环,不是全部。

最后需要明确能力边界:Sentinel 和 OPA 都基于“计划数据”做判断,因此无法感知 apply 之后资源的真实漂移;Checkov 扫描的是源码,可能漏掉变量在运行时才确定的值。要覆盖漂移,需要配合 terraform plan -refresh-only 或运行时合规工具。选型的本质,是在“平台绑定程度、策略表达力、上手成本、跨工具范围”四个维度上找到与团队现状匹配的平衡点。