4. 基础设施即代码安全工程
基础设施即代码(IaC)把云资源的创建从控制台点击变成了可版本化、可评审、可复现的代码。Terraform 的 HCL、CloudFormation 的 YAML/JSON 模板、Pulumi 的多语言程序,本质上都是“期望状态的声明”。这带来一个关键安全机会:在资源真正被创建之前,就能对配置做策略检查。IaC 安全工程的核心,不是等云上出现一个公开的 S3 桶再去告警,而是在 terraform plan 或模板校验阶段就阻断它。
要理解 IaC 安全,先要理解 IaC 的执行链路。以 Terraform 为例,工程师编写 .tf 文件,执行 terraform init 拉取 provider,执行 terraform plan 生成执行计划,最后 terraform apply 调用云 API 创建资源。策略检查可以嵌入在多个位置:编辑时的 IDE 插件、提交时的 pre-commit 钩子、CI 中的静态扫描、plan 后的策略评估,以及 apply 前的准入控制。越靠前,修复成本越低;越靠后,越接近“最后一道闸门”。
图中把“执行链路”和“策略检查层”分开画,是为了强调一个工程事实:策略检查不是单一工具,而是一组分布在不同阶段的控制点。IDE 插件和 pre-commit 负责快速反馈,CI 静态扫描负责全量规则覆盖,plan 后的策略评估负责看真实变更,准入控制负责最后阻断。四层配合,才能既快又稳。
策略即代码:把合规要求写成可执行规则
IaC 安全的关键转变,是把“安全要求”从文档变成“策略即代码”。以 OPA(Open Policy Agent)的 Rego 为例,一条禁止 S3 桶公开访问的策略可以写成:
package terraform.s3
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket_acl"
resource.change.after.acl == "public-read"
msg := sprintf("S3 桶 %s 不允许 public-read ACL", [resource.address])
}
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket"
not resource.change.after.server_side_encryption_configuration
msg := sprintf("S3 桶 %s 未配置服务端加密", [resource.address])
}
这段策略的输入是 terraform plan 转换成的 JSON(通过 terraform show -json plan.out 得到),检查的是 resource_changes 中每个资源的 after 状态。注意它检查的是“变更后”的期望状态,而不是当前代码文本,因此能覆盖变量、模块和条件表达式展开后的真实结果。这正是 plan 阶段策略评估比纯文本扫描更强的地方。
Checkov 和 tfsec 则采用内置规则库加自定义规则的路线。以 Checkov 为例,一条自定义 YAML 策略可以检查 RDS 实例是否开启删除保护:
metadata:
name: "RDS 必须开启删除保护"
id: "CKV_CUSTOM_001"
definition:
cond_type: attribute
resource:
- aws_db_instance
attribute: deletion_protection
operator: equals
value: true
把这类规则放进 CI,配合 checkov -d . --framework terraform --external-checks-dir ./policies,就能在合并请求阶段给出通过或失败。失败时输出会指出具体文件、行号和规则 ID,工程师据此修改。
从“能扫”到“能阻断”:分级与豁免
实际落地时,最大的阻力往往不是工具不会用,而是“一上来全阻断”导致业务无法推进。合理的做法是按严重级别分级:高危规则(公开存储、无加密、宽泛 IAM)设为硬阻断,中危规则设为告警并记录,低危规则仅提示。同时必须提供带过期时间的豁免机制,例如在代码中标注:
# checkov:skip=CKV_AWS_20: 该桶用于静态网站托管,已通过 CloudFront 限制访问,豁免至 2025-12-31
resource "aws_s3_bucket" "site" {
bucket = "example-static-site"
}
豁免必须包含理由和到期时间,并纳入定期审计。没有到期时间的豁免,等同于永久关闭了这条规则。
一个可执行的检查闭环
把上述内容串成一个最小闭环:工程师提交 Terraform 代码 → CI 执行 terraform init 和 terraform plan -out=plan.out → terraform show -json plan.out > plan.json → OPA 用 opa eval -d policies/ -i plan.json "data.terraform.deny" 评估 → 若 deny 非空则 CI 失败并输出违规信息 → 工程师修改后重新提交。这个闭环的价值在于:违规配置在进入云环境之前就被拦住,而不是在运行态被扫描出来。
最后要强调,IaC 策略检查的规则不是越多越好,而是要与组织的实际风险对齐。建议从 10 到 20 条高危规则起步,覆盖存储公开、加密缺失、网络暴露、权限过宽、日志关闭这几类高频问题,稳定运行后再逐步扩展。规则本身也要版本化管理,和 IaC 代码一起评审、一起发布。