$npx -y skills add xwtro0tk1t-cloud/harness --skill security-review-skill-for-terraform审计 Terraform / IaC 代码安全(AWS 基础设施)。检测硬编码凭据、过宽 Security Group(0.0.0.0/0)、IAM 权限过大(Action/Resource *)、S3 公开访问、RDS 未加密/公开、State 文件泄露、ECS/EKS 容器特权、CloudTrail/VPC FlowLog 缺失、不安全 Provider/Module 引用等。当审计 Terraform 代码、IaC 安全评审、AWS 云基础设施配置检查、GitOps 安全审计时使用。支持 HCL(.tf)、Terraform JSON、tfvars
| 1 | # Terraform / AWS IaC Security Review |
| 2 | |
| 3 | ## 技术栈背景 |
| 4 | |
| 5 | Terraform (HCL) 基础设施即代码安全审计,**聚焦 AWS Provider**。 |
| 6 | |
| 7 | **审计范围**: |
| 8 | - `.tf` 文件(HCL 资源定义) |
| 9 | - `.tfvars` / `terraform.tfvars`(变量值文件) |
| 10 | - `backend.tf` / `provider.tf`(后端和 Provider 配置) |
| 11 | - `modules/`(自定义和第三方模块) |
| 12 | - `terragrunt.hcl`(如使用 Terragrunt) |
| 13 | - `.terraform.lock.hcl`(Provider 锁定文件) |
| 14 | - CI/CD pipeline 中的 Terraform 步骤 |
| 15 | |
| 16 | **关键审计维度**: |
| 17 | - D1: 凭据与密钥管理 |
| 18 | - D2: 网络安全(Security Group / NSG / Firewall) |
| 19 | - D3: IAM 与访问控制 |
| 20 | - D4: 加密(静态 + 传输) |
| 21 | - D5: 公开访问与暴露面 |
| 22 | - D6: State 文件安全 |
| 23 | - D7: Provider 与 Module 供应链 |
| 24 | - D8: 容器与计算资源安全 |
| 25 | - D9: 日志、监控与合规 |
| 26 | - D10: Terraform 运行时安全 |
| 27 | |
| 28 | ## 审计模式 |
| 29 | |
| 30 | 触发 skill 后,**首先**用 AskUserQuestion 询问用户审计模式: |
| 31 | |
| 32 | **问题**: "选择审计模式" |
| 33 | **选项**: |
| 34 | 1. **全量审计** — 扫描指定目录/模块的全部 .tf 文件 |
| 35 | 2. **PR/分支审计** — 只扫描 Terraform 变更(`git diff` 中的 .tf/.tfvars 文件) |
| 36 | 3. **最近变更审计** — 扫描最近 N 天/N 个 commit 的 .tf 变更 |
| 37 | |
| 38 | 如果用户 prompt 中已明确指定模式,跳过询问。 |
| 39 | |
| 40 | ### PR/分支模式 |
| 41 | |
| 42 | **Step 0: 确定 diff 范围** |
| 43 | ```bash |
| 44 | git diff --name-only <base>...<target> -- '*.tf' '*.tfvars' 'terragrunt.hcl' |
| 45 | ``` |
| 46 | |
| 47 | **Step 0.1: 范围分析** |
| 48 | 1. 将改动 .tf 文件按模块/目录分类 |
| 49 | 2. 对每个改动文件:Read 完整文件 + 识别新增/修改的 resource block |
| 50 | 3. 检查相关 variable/output/data source 引用链 |
| 51 | |
| 52 | --- |
| 53 | |
| 54 | ## 审计方法 |
| 55 | |
| 56 | **核心原则**:宁可漏过也不误报。所有发现必须基于实际代码。IaC 审计特点:**配置即代码**——缺失安全配置本身就是漏洞。 |
| 57 | |
| 58 | ### Step 1: 侦察阶段 |
| 59 | |
| 60 | 1. **识别 Provider**:`required_providers` block → AWS(主要)/ Kubernetes / Helm |
| 61 | 2. **识别 Backend**:`backend` block → S3(推荐)/ Consul / Local |
| 62 | 3. **资源清单**:列出所有 `resource` 和 `data` 类型,构建攻击面 |
| 63 | 4. **模块依赖**:`module` block 的 source 属性 → 本地/Registry/Git |
| 64 | 5. **变量流**:`variable` → `locals` → `resource` 属性的数据流 |
| 65 | |
| 66 | ### Step 2: 正则扫描(必须执行) |
| 67 | |
| 68 | 根据下方"审计正则速查"逐条 Grep。IaC 正则扫描是核心检测手段——Terraform 安全问题大多是**配置模式匹配**。 |
| 69 | |
| 70 | ### Step 3: 双轨审计 |
| 71 | |
| 72 | **Sink-driven(找危险配置)**: |
| 73 | - 过宽 CIDR(0.0.0.0/0)、通配符 IAM 权限(`*`)、公开存储桶 |
| 74 | - 硬编码凭据、明文密码、未加密资源 |
| 75 | |
| 76 | **Control-driven(找缺失的安全控制)**: |
| 77 | - 存储资源无加密?计算资源无 IAM role?日志未启用? |
| 78 | - **缺失即脆弱**:应有的安全属性未设置 → 漏洞 |
| 79 | |
| 80 | ### Step 4: 数据流分析 |
| 81 | |
| 82 | IaC 数据流 = **变量传播**: |
| 83 | ``` |
| 84 | variable "db_password" → local.config → resource.aws_db_instance.password |
| 85 | → tfvars 文件中是否明文? |
| 86 | → State 文件中是否存储? |
| 87 | ``` |
| 88 | |
| 89 | 追踪: |
| 90 | 1. `variable` 定义是否标记 `sensitive = true` |
| 91 | 2. 变量值来源:tfvars / 环境变量 / Vault / SSM |
| 92 | 3. 变量是否传入不安全的属性(如 `user_data` 脚本) |
| 93 | |
| 94 | ### Step 5: 跨模块分析 |
| 95 | |
| 96 | - 子模块 output 是否暴露敏感值? |
| 97 | - 父模块是否信任子模块输出用于安全决策? |
| 98 | - `terraform_remote_state` 读取是否暴露其他环境的敏感数据? |
| 99 | |
| 100 | ### Step 6: 攻防对抗验证 |
| 101 | |
| 102 | **攻击方**:如果获得对此基础设施的只读/读写权限,能做什么? |
| 103 | **防御方**:是否有 WAF/SecurityGroup/NACL/IAM boundary 阻止? |
| 104 | |
| 105 | ### Step 7: 覆盖评估 |
| 106 | - [ ] 凭据与密钥(硬编码/明文/State泄露) |
| 107 | - [ ] 网络安全(SG/NACL/防火墙规则) |
| 108 | - [ ] IAM 权限(最小权限/通配符/跨账户) |
| 109 | - [ ] 加密(存储/传输/密钥管理) |
| 110 | - [ ] 公开访问(S3/RDS/端点) |
| 111 | - [ ] State 文件(远程后端/加密/访问控制) |
| 112 | - [ ] Module 供应链(来源/版本/完整性) |
| 113 | - [ ] 容器/计算(特权/root/资源限制) |
| 114 | - [ ] 日志监控(CloudTrail/VPC FlowLog/审计) |
| 115 | - [ ] 运行时安全(Provider 认证/CI 权限) |
| 116 | |
| 117 | ### 误报识别 |
| 118 | - `0.0.0.0/0` 在 **egress** 规则中通常是合理的(出站全放行) |
| 119 | - `description` 字段中包含密码样例字符串不是凭据泄露 |
| 120 | - `terraform.tfvars.example` 中的占位值不是真实凭据 |
| 121 | - `data.aws_iam_policy_document` 中 `actions = ["s3:GetObject"]` + `resources = ["*"]` 对只读 S3 可能是合理的 |
| 122 | - `count = 0` 或 `for_each = {}` 的资源不会实际创建 |
| 123 | - `dynamic` block 中的 `content` 可能有条件控制 |
| 124 | |
| 125 | ## 优先检查 |
| 126 | |
| 127 | | 优先级 | 目标 | 原因 | |
| 128 | |--------|------|------| |
| 129 | | P0 | 硬编码凭据/密钥 | 直接泄露即可攻陷 | |
| 130 | | P0 | `0.0.0.0/0` ingress + 敏感端口 | 互联网直接暴露 | |
| 131 | | P0 | IAM `*:*` 权限 | 等同管理员,极度危险 | |
| 132 | | P1 | S3 公开访问 | 数据泄露 | |
| 133 | | P1 | 数据库/存储未加密 | 合规 + 数据保护 | |
| 134 | | P1 | State 文件无加密/无远程后端 | State 含所有密钥 | |
| 135 | | P2 | 模块来源未锁版本 | 供应链攻击 | |
| 136 | | P2 | 日志/监控缺失 | 无法检测攻击 | |
| 137 | | P2 | 容器特权/root | 容器逃逸 | |
| 138 | |
| 139 | ## 通用漏洞检查 |
| 140 | |
| 141 | ### D1: 凭据与密钥管理 |
| 142 | |
| 143 | **硬编码凭据**: |
| 144 | ```hcl |
| 145 | # 危险:明文密码 |
| 146 | resource "aws_db_instance" "main" { |
| 147 | password = "MyS3cretP@ss!" # 硬编码 |
| 148 | } |
| 149 | |
| 150 | resource "aws_iam_access_key" "user" { |
| 151 | user = aws_iam_user.example.name |
| 152 | # access_key/secret_key 会存入 State |
| 153 | } |
| 154 | |
| 155 | # 安全:引用 Secrets Manager |
| 156 | resource "aws_db_instance" "main" { |
| 157 | password = data.aws_secretsmanager_secret_version.db.secret_string |
| 158 | } |
| 159 | |
| 160 | # 安全:标记 sensitive |
| 161 | variable "db_password" { |
| 162 | type = string |
| 163 | sensitive = true |
| 164 | } |
| 165 | ``` |
| 166 | |
| 167 | **State 文件中的密钥**: |
| 168 | ```hcl |
| 169 | # 危险:本地 State(含所有资源属性,包括密码) |
| 170 | terraform { |
| 171 | backend "local" {} # State 文件存在本地磁盘 |
| 172 | } |
| 173 | |
| 174 | # 安全:远程 State + 加密 |
| 175 | terraform { |
| 176 | backend "s3" { |
| 177 | bucket = "my-tf-state" |
| 178 | key = "prod/terraform.tfstate" |
| 179 | encrypt = true |
| 180 | dynamodb_table = "tf-locks" |
| 181 | } |
| 182 | } |
| 183 | ``` |
| 184 | |
| 185 | ### D2: 网络安全 |
| 186 | |
| 187 | **过宽 Security Group**: |
| 188 | ```hcl |
| 189 | # 危险:全开入站 |
| 190 | resource "aws_security_group_rule" "bad" { |
| 191 | type = "ingress" |
| 192 | from_port = 0 |
| 193 | to_port = 65535 |
| 194 | protocol = "-1" |
| 195 | cidr_blocks = ["0.0.0.0/0"] |
| 196 | } |
| 197 | |
| 198 | # 危险:SSH/RDP 对公网开放 |
| 199 | resource "aws_security_group_rule" "ssh_open" { |
| 200 | type = "ingress" |
| 201 | from_port = 22 |
| 202 | to_port = 22 |
| 203 | protocol = "tcp" |
| 204 | cidr_blocks = ["0.0.0.0/0"] # SSH 对全互联网开放 |
| 205 | } |
| 206 | |
| 207 | # 安全:限制到 VPN/堡垒机 IP |
| 208 | resource "aws_security_group_rule" "ssh" { |
| 209 | type = "ingress" |
| 210 | from_port = 22 |
| 211 | to_port = 22 |
| 212 | protocol = "tcp" |
| 213 | cidr_blocks = ["10.0.0.0/8"] # 仅内网 |
| 214 | } |
| 215 | ``` |
| 216 | |
| 217 | **VPC Endpoint 缺失**: |
| 218 | ```h |