2. IaC代码安全威胁建模

基础设施即代码(IaC)把网络、计算、存储、身份与密钥策略都变成了可版本化、可复用的代码。这一转变带来可审计与可回滚的优势,同时也把传统运行时的攻击面前移到了代码仓库、模板参数、模块依赖和流水线执行环境。对IaC做威胁建模,核心不是罗列所有可能的漏洞,而是围绕“代码如何变成真实资源”这条链路,识别攻击者能在哪些位置施加影响、影响会沿什么路径放大、最终破坏哪一类安全属性。

本节采用STRIDE作为分类骨架。STRIDE的六类威胁分别是:Spoofing(仿冒)、Tampering(篡改)、Repudiation(抵赖)、Information Disclosure(信息泄露)、Denial of Service(拒绝服务)、Elevation of Privilege(权限提升)。在IaC语境下,它们并不抽象:仿冒对应伪造提交者身份或冒充可信模块来源;篡改对应修改模板、变量或状态文件;抵赖对应缺少不可否认的变更记录;信息泄露对应明文密钥、输出值或状态文件暴露;拒绝服务对应删除关键资源或制造配额耗尽;权限提升对应把过宽的角色、策略或信任关系写入代码。

结合基础设施代码的典型攻击面,可以归纳出四条主要威胁路径:配置漂移、权限提升、数据暴露、供应链投毒。配置漂移指代码声明的期望状态与真实环境状态发生偏离,攻击者可能利用漂移留下的“灰色地带”长期驻留;权限提升指IaC中定义的IAM策略、角色信任关系或Kubernetes RBAC被写成过宽授权,使低权限主体获得高权限;数据暴露指密钥、连接串、证书、状态文件或输出值以明文形式进入仓库、日志或制品;供应链投毒指第三方模块、Provider、镜像或CI插件被替换或注入恶意逻辑,在流水线执行时获得凭据与资源控制权。

IaC 攻击面 → STRIDE 威胁 → 安全属性破坏 典型攻击面 配置漂移 期望态 ≠ 真实态 权限提升 过宽 IAM / RBAC 数据暴露 密钥 / 状态 / 输出值 供应链投毒 模块 / Provider / 镜像 CI/CD 执行环境 STRIDE 威胁分类 S · 仿冒 伪造提交者、冒充可信模块来源 T · 篡改 修改模板、变量、状态文件 R · 抵赖 缺少不可否认的变更记录 I · 信息泄露 明文密钥、输出值、状态暴露 D · 拒绝服务 删除关键资源、配额耗尽 E · 权限提升 过宽角色、策略、信任关系 被破坏的安全属性 身份可信性 Authentication 完整性 Integrity 不可否认性 Non-repudiation 机密性 Confidentiality 可用性 / 授权边界 Availability / AuthZ

把四条攻击面与STRIDE对齐后,威胁清单就不再是泛泛而谈。下面给出一份可直接用于评审的威胁清单示例。清单中的“示例参数”均为教学假设,用于说明判断依据,不代表任何真实环境的实测结果。

威胁编号 攻击面 STRIDE 类别 典型场景 关键判断依据 建议缓解措施
T-01 配置漂移 篡改 / 抵赖 安全组被手工放通 0.0.0.0/0,代码中未记录 terraform plan 显示无差异,但云上实际规则与代码不一致 启用 drift detection,定期执行 plan 并告警;禁止控制台直改
T-02 权限提升 权限提升 IAM 策略使用 "Action": "*" 且 "Resource": "*" 策略模拟显示可执行 iam:CreateUser、iam:AttachUserPolicy 最小权限拆分,使用权限边界与 Access Analyzer 校验
T-03 数据暴露 信息泄露 数据库密码以明文写入 variables.tf 并提交 仓库扫描命中高熵字符串;state 文件中出现明文密码 接入密钥管理服务,使用动态凭据;state 加密并限制访问
T-04 供应链投毒 仿冒 / 篡改 引用未锁定版本的第三方模块,上游被替换 模块 source 未固定 commit,校验和不匹配 锁定版本与哈希,使用私有仓库镜像并做签名校验
T-05 CI/CD 执行环境 权限提升 / 信息泄露 流水线以长期高权限凭据执行不可信 PR 的代码 PR 触发即注入生产凭据;日志中打印环境变量 使用 OIDC 短期凭据,隔离 PR 与生产执行环境
T-06 配置漂移 拒绝服务 误删关键负载均衡或数据库实例,代码未做保护 资源缺少 prevent_destroy;删除操作无审批 关键资源加生命周期保护,删除走审批与备份

威胁清单的价值在于驱动具体动作。以T-02为例,判断一条IAM策略是否过宽,不能只看是否出现星号,而要看“谁能扮演该角色、该角色能对哪些资源做什么”。实际操作中,可以先导出策略JSON,再用策略模拟器验证:假设主体为低权限开发者,尝试执行 iam:CreateUser、iam:AttachUserPolicy、sts:AssumeRole,若返回 allowed,则说明存在权限提升路径。修复时把 "Action": "*" 拆成实际需要的动作集合,把 "Resource": "*" 收敛到具体资源ARN,并加上 Condition 限制来源VPC或MFA。

再以T-03为例,数据暴露往往不是单一位置,而是沿“变量 → 计划 → 状态 → 输出 → 日志”扩散。一个可执行的检查顺序是:先用 gitleaks detect --source . --verbose 扫描仓库历史;再检查 terraform.tfstate 是否包含明文敏感值;然后确认 output 是否标记了 sensitive = true;最后检查CI日志是否打印了 TF_VAR_ 环境变量。若state必须保留敏感值,应使用加密后端并限制读取权限,而不是把state提交到仓库。

常见误区:把 sensitive = true 当作加密。它只控制CLI输出显示,不改变state中的存储形态。真正的机密性依赖加密后端、访问控制与密钥轮换。

供应链投毒的判断重点在“来源是否可验证、版本是否可复现”。例如模块声明 source = "git::https://example.com/modules/network.git?ref=v1.2",其中 ref 指向可变标签,上游可移动该标签指向恶意提交。更稳妥的做法是固定到commit SHA,并记录校验和;对Provider和镜像同样锁定版本与摘要。流水线中还应限制第三方代码能接触的凭据范围,避免“一个PR就能拿到生产密钥”。

完成威胁清单后,需要把它落到可复查的节奏上:每次IaC变更评审时对照清单检查对应威胁项;每周执行一次漂移检测与密钥扫描;每月复核一次高权限角色与信任关系。这样STRIDE就不再是一次性的建模练习,而是持续治理IaC安全的具体抓手。