1. IaC安全治理全景
基础设施即代码(Infrastructure as Code,IaC)把网络、计算、存储、权限等云资源的定义从控制台点击迁移到可版本化、可评审、可复用的代码文件中。它带来的直接收益是环境一致性与变更可追溯,但同时也把“配置错误”从一次性的操作失误,变成了可以被复制、被继承、被批量放大的代码缺陷。理解 IaC 安全治理,首先要理解这条从代码到真实资源的转化链路,以及链路上每一类工具各自引入的风险面。
一、IaC 的核心概念与转化链路
IaC 的本质是“声明式或命令式的资源描述 + 执行引擎”。以 Terraform 为例,工程师编写 .tf 文件声明资源,执行 terraform plan 生成执行计划,再由 terraform apply 调用云厂商 API 创建资源。CloudFormation 使用 YAML/JSON 模板,Pulumi 使用 TypeScript、Python 等通用语言,Ansible 则以任务(task)和模块(module)描述目标状态。四者的共同点是:代码是意图,状态文件或运行时是事实,二者之间的差异就是风险可能藏身的地方。
这条链路上有三个关键对象需要区分:源码(仓库中的模板与变量)、计划/状态(plan 输出、state 文件、inventory)、真实资源(云上已存在的实例、桶、策略)。安全治理不能只盯源码,因为变量文件、远程 state、动态 inventory 同样会改变最终结果。
二、主流工具的安全风险图谱
不同 IaC 工具的风险侧重点并不相同,治理策略也应有所区别。
Terraform 的风险集中在三处:一是 terraform.tfstate 默认以明文保存资源属性和部分敏感值,若被提交到 Git 或存放在无加密的远端后端,等同于泄露凭据;二是 provider 版本与模块来源不受约束时,可能引入被投毒的第三方模块;三是 local-exec、remote-exec 等 provisioner 会在资源创建后执行任意命令,是代码执行风险的入口。
CloudFormation 的风险更多来自模板表达能力:IAM Policy 中 "Action": "*" 与 "Resource": "*" 的组合、安全组 0.0.0.0/0 入站、S3 桶缺少 PublicAccessBlock,都是模板层面可静态识别的典型问题。此外,嵌套栈(nested stack)和 Transform 宏会隐藏真实资源,增加审计难度。
Pulumi 使用通用编程语言,风险从“配置错误”扩展到“代码缺陷”:循环中动态拼接的资源名可能导致策略绕过,密钥可能被写入普通变量而非加密配置,第三方包依赖也进入供应链风险范围。
Ansible 的风险在于其命令式与幂等性混合的特征:shell/command 模块可执行任意命令,become: yes 提升权限,inventory 中可能明文存放 ansible_password,而 ignore_errors: yes 会让失败被静默吞掉,导致实际状态与预期偏离。
三、安全治理总体框架与职责边界
把上述风险收敛为可执行的治理框架,可以按“预防—检测—响应”三层组织,并明确每层的责任主体。
| 层次 | 目标 | 典型手段 | 责任主体 |
|---|---|---|---|
| 预防 | 不让问题进入主干 | 代码扫描、策略即代码、模块基线、密钥扫描 | 平台工程 / 安全团队 |
| 检测 | 发现已合入或已上线的偏差 | plan 校验、CSPM、漂移检测、配置基线核查 | 安全运营 / SRE |
| 响应 | 阻断、修复、回写代码 | CI 门禁阻断、自动修复、工单与复盘 | 应用团队 / 平台团队 |
职责边界上有一条实用原则:安全团队定义“什么不允许”,平台团队提供“怎么检查”,应用团队负责“改自己的代码”。如果安全团队直接替业务改模板,既不可扩展,也会让责任模糊。策略应以代码形式存放在独立仓库,通过 CI 流水线统一注入,而不是靠人工评审记忆。
gitleaks 扫描密钥,合并前用 checkov -d . 扫描 Terraform/CloudFormation 模板,并设置 --soft-fail 先观察、再逐步收紧为阻断。这样既能看到真实问题分布,又不会一次性打断交付节奏。
四、一个最小示例:从模板到拦截
假设有一段 Terraform 代码创建安全组:
resource "aws_security_group" "web" {
name = "web-sg"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
执行 checkov -d . 后,会得到类似 CKV_AWS_24: Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 的失败项。此时的处理不是简单删除规则,而是判断该端口是否真的需要公网访问:若仅运维使用,应改为通过堡垒机或 VPN 的私有网段;若确需公网,则应在策略中登记例外并附加审批记录。这个判断过程,正是“工具发现问题、人做风险决策、代码承载修复”的治理闭环。