3. IaC安全编码规范设计

当团队从“个人写脚本”走向“组织级基础设施交付”时,IaC 代码就不再只是工程师的个人资产,而是承载生产环境安全基线的组织资产。此时如果没有统一的安全编码标准,同一个 Terraform 模块可能由不同人写出完全不同的安全姿态:有人默认开启存储加密,有人忘记关闭公网访问,有人把密钥硬编码进变量文件。IaC 安全编码规范要解决的,正是这种“同一类资源、不同安全结果”的离散化问题。

本节的核心任务是:把命名、加密、网络、IAM、日志、标签等关键规则,从零散经验沉淀为一份可检查、可评审、可自动化的组织级规范文档。规范不是安全愿望清单,而是能被代码审查、策略引擎和 CI 流水线直接消费的约束集合。

一、规范文档的结构设计

一份可落地的 IaC 安全编码规范,建议采用“规则域—规则条目—检查方式—违规示例—修复示例”五层结构。规则域对应命名、加密、网络、IAM、日志、标签等主题;每条规则条目必须包含唯一编号(如 IAC-ENC-001)、适用资源类型、约束描述、严重级别(阻断/警告/提示)、检查方式(人工评审/静态扫描/策略即代码)以及正反示例。缺少“检查方式”的规则,本质上只是建议,无法进入自动化门禁。

严重级别的划分直接影响流水线行为:阻断级规则在 CI 阶段直接失败,禁止合并;警告级规则允许合并但必须记录豁免理由;提示级规则仅输出报告。这样既保证关键安全底线不可绕过,又避免规范过于刚性导致团队抵触。

二、六大关键规则域的具体约束

命名规则要求资源名称可追溯、可分组。推荐格式为 {org}-{env}-{region}-{service}-{resource},例如 acme-prod-cn-north-payment-sg。命名规则的价值在于:安全事件响应时能快速定位资源归属,策略扫描时能按环境批量匹配。命名规则通常设为警告级,因为改名成本高,但新资源必须遵守。

加密规则是阻断级重点。对象存储必须启用服务端加密(SSE),数据库必须启用静态加密与传输加密,密钥必须使用 KMS 托管而非本地生成。以 Terraform 为例,S3 存储桶应显式声明加密配置,而不是依赖默认值:

resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
  bucket = aws_s3_bucket.example.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.example.arn
    }
    bucket_key_enabled = true
  }
}

网络规则要求默认拒绝、显式放行。安全组不得出现 0.0.0.0/0 开放 22/3389 等高危端口;数据库与缓存必须部署在私有子网;负载均衡到后端只允许必要端口。网络规则适合用策略即代码检查,例如 OPA/Rego 或 Checkov 自定义规则,对 CIDR 与端口组合做匹配。

IAM 规则要求最小权限与禁止通配。策略中不得出现 "Action": "*" 与 "Resource": "*" 同时存在;角色信任策略必须限定具体主体;长期访问密钥应禁止创建,优先使用角色与临时凭证。IAM 规则通常设为阻断级,因为权限扩散的后果最严重。

日志规则要求关键资源开启审计日志。云审计、VPC 流日志、对象存储访问日志、数据库审计日志必须启用并投递到集中日志账户。日志规则需要检查“是否启用”和“投递目标是否存在”两个条件,避免只声明资源却未真正生效。

标签规则要求所有资源携带 owner、env、cost-center、data-classification 四类标签。标签不仅是成本管理手段,更是安全分级依据:data-classification=confidential 的资源应自动触发更严格的加密与网络规则。

IaC 安全编码规范:规则域 → 检查方式 → 流水线门禁 规则域 命名 NAM 可追溯 · 可分组 加密 ENC SSE · KMS · TLS 网络 NET 默认拒绝 · 私有子网 IAM 最小权限 · 禁通配 日志 LOG 审计 · 流日志 · 集中投递 标签 TAG owner · env · 数据分级 检查方式 人工评审 命名 · 架构合理性 静态扫描 Checkov · tfsec · KICS 策略即代码 OPA/Rego · Sentinel 运行时校验 plan 输出 · 漂移检测 合规报告 豁免记录 · 趋势看板 CI 流水线门禁 ① 提交前本地扫描 pre-commit 钩子 ② PR 阶段策略检查 阻断级失败 → 禁止合并 ③ 计划阶段 plan 校验 实际变更与规则比对 ④ 部署后漂移检测 定时比对实际状态 ⑤ 豁免与整改闭环 记录理由 · 限期修复 规范文档版本化维护 规则变更 → 评审 → 发布

三、从规范到可检查文档的落地方法

规范文档如果只停留在 Wiki 页面,很快会与代码脱节。推荐把规范拆成两层:一层是面向人的说明文档,解释每条规则的背景、风险和修复方式;另一层是面向机器的规则文件,例如 Checkov 自定义策略、OPA Rego 策略或 Sentinel 策略。两层通过规则编号一一对应,保证“文档里写的”和“流水线查的”是同一件事。

以标签规则为例,Rego 策略可以这样表达:遍历 plan 中所有资源,检查 tags 是否包含 owner、env、cost-center、data-classification 四个键,缺失任一键则返回违规。策略输出中带上资源地址和缺失标签名,开发者在 PR 评论中就能直接看到问题位置,而不是只收到一句“标签不合规”。

规范还需要版本化维护。规则变更应走与代码相同的评审流程:提出变更、说明影响范围、更新正反示例、同步更新策略文件、在测试仓库验证后再发布。建议为规范文档打上语义化版本号,并在流水线中记录本次检查使用的规范版本,便于事后追溯“当时为什么允许这次变更”。

规范落地初期,建议先选取加密、IAM、网络三类阻断级规则接入流水线,稳定后再逐步加入日志与标签规则。一次性全量启用容易产生大量历史违规,反而削弱团队对规范的信任。

四、规范文档示例片段

下面给出一条可直接参考的规则条目写法,展示“规则—检查—示例”如何组织:

规则编号 规则域 约束描述 严重级别 检查方式
IAC-ENC-001 加密 对象存储必须启用 SSE-KMS 服务端加密,禁止使用明文或仅 SSE-S3 阻断 Checkov 自定义策略 + plan 校验
IAC-NET-003 网络 安全组不得对 0.0.0.0/0 开放 22、3389、3306、6379 端口 阻断 OPA/Rego 策略
IAC-IAM-002 IAM 策略语句中 Action 与 Resource 不得同时为通配符 阻断 tfsec + 人工评审
IAC-TAG-001 标签 所有可打标签资源必须包含 owner、env、cost-center、data-classification 警告 Rego 策略 + 合规报告

这份表格本身就是规范文档的核心骨架。每条规则都能被策略引擎消费,也能被人工评审引用。当规则数量增长到几十条时,建议按规则域拆分为多个策略文件,并在 CI 中并行执行,避免单次检查时间过长影响开发体验。

最后需要强调:IaC 安全编码规范的目标不是追求“零违规”的数字,而是让安全约束成为基础设施交付流程中默认存在的一部分。规范写清楚、检查自动化、豁免有记录、整改有闭环,组织才能在保持交付速度的同时,把安全基线稳定地固化到每一行 IaC 代码里。