PontoPe/AwLZ
GitHub: PontoPe/AwLZ
一个用 Terraform 构建的多账户 AWS Landing Zone 基础设施即代码项目,通过 SCP 防护机制、集中式日志检测和零静态凭证 CI 管道,交付可复现的云安全治理基线及其合规证据。
Stars: 0 | Forks: 0
# AwLZ — AWS Landing Zone
使用 Terraform 构建的多账户 AWS Landing Zone:默认开启防护机制、零长期凭证,以及生成而非空谈的合规证据。
## 为什么
大多数“AWS 安全”方案旨在加固单一账户。真实的组织往往在边界处失守——无人监管的账户、无人监控的区域、遗留在 CI runner 中的访问密钥。本仓库构建了边界本身:Organizations、SCP、全组织范围的日志记录、检测,均为可复现的代码。
交付成果不是可运行的基础设施。它是可复现的基础设施,**外加控制措施确实如文档所述般运作的证据**。参见 [`docs/evidence/`](docs/evidence/)。
## 架构
```
flowchart TB
subgraph ORG["AWS Organization (all features, SCPs enabled)"]
MGMT["Management account
Organizations, SCPs, Identity Center
Terraform state"] subgraph OU_SEC["OU: Security"] LOG["awlz-log-archive
org trail destination"] SEC["awlz-security
detection delegated admin"] end subgraph OU_WL["OU: Workloads"] DEV["awlz-dev"] LAB["awlz-lab"] end end GHA["GitHub Actions"] -->|OIDC AssumeRole
no static keys| MGMT MGMT -->|"SCPs: region allow-list,
protect detection,
protect guardrail roles"| OU_WL MGMT --> OU_SEC DEV & LAB -->|org trail| TRAIL["CloudTrail org trail"] TRAIL --> LOG DEV & LAB --> GD["GuardDuty"] --> SHUB["Security Hub
CIS benchmark"] SHUB -.-> EVID["docs/evidence/
CIS score pending"] classDef todo stroke-dasharray: 5 5 class EVID todo ``` 虚线 = 尚未生成。决策及其后果:[docs/architecture.md](docs/architecture.md)。当前状态、待办事项以及已踩过的坑:[docs/AwLZ-handbook.md](docs/AwLZ-handbook.md)。 ## 威胁模型 摘要 — 包含可能性、影响和残余风险的完整版本详见 [docs/threat-model.md](docs/threat-model.md)。 | # | 威胁 | 控制措施 | 状态 | |---|--------|---------|--------| | T1 | CI 凭证被盗 → 账户接管 | GitHub OIDC,无静态密钥,角色信任锁定到精确的 `sub` 声明 | **已应用**,`live/ci-oidc` | | T2 | 攻击者禁用日志以隐藏活动 | SCP 拒绝销毁 CloudTrail/Config/GuardDuty/Security Hub | **已应用**,`live/guardrails` | | T3 | 未受监控区域中的资源蔓延 | SCP 区域允许列表 | **已应用 + 已验证** | | T4 | 日志篡改或删除 | 专用日志归档账户、保存在该处的 CMK、Object Lock COMPLIANCE | **已应用 + 已验证** | | T5 | 通过成员账户中的 IAM 提权 | SCP 拒绝对防护机制的 IAM 写入 | **部分** — 仍然缺少权限边界 | | T6 | Terraform state 泄露 | S3 + 客户管理的 KMS 密钥、仅限 TLS 的策略、原生 S3 锁定 | **已应用** | | T6b | State 对象被读取或无痕覆盖 | 限定于 state bucket 的 CloudTrail S3 数据事件 | **已关闭** | | T7 | 恶意或拼写错误的 Terraform 代码被合并 | `tflint` + `trivy config` + `checkov`,PR 上的真实 plan,门控 apply | **已应用** — 规则集要求具有 PR 且 `main` 分支通过检查 | | T8 | 防护机制锁定紧急访问通道 | 破窗角色,已记录并设置警报 | **部分** — 路径已演练,无警报 | | T9 | 在 Identity Center 之外使用成员账户 root | Root 凭证已从成员账户**删除** | **已消除**,`live/org-root` | ## 布局 ``` live/bootstrap/ remote state: S3 + KMS CMK, native locking applied live/org-root/ OUs, member accounts, centralized root access applied live/guardrails/ creates and attaches the SCPs applied policies/scp/ the SCP documents live/logging/ org trail into an object-locked archive account applied live/detection/ GuardDuty, Security Hub, Config, Access Analyzer applied live/ci-oidc/ GitHub OIDC provider + plan and apply roles applied modules/ logging, detection, config-recorder, iam-oidc docs/ architecture, threat model, cost, evidence ``` `live/` 下的每个 stack 都是一个根模块,具有固定的 provider 版本、部分 S3 backend,并设置了 `allowed_account_ids`,这样配置错误会直接失败,而不会继续执行 apply。 ## 运行它 本地认证使用 IAM Identity Center。根据设计,此仓库中没有任何地方存在静态访问密钥。 ``` aws sso login --profile mgmt cd live/
cp example.tfvars terraform.tfvars # account id, profile
cp example.backend.hcl backend.hcl # state bucket, KMS key
terraform init -backend-config=backend.hcl
terraform plan -var-file=terraform.tfvars -out=tfplan
terraform apply tfplan
```
`live/bootstrap` 是个例外——它会创建一个稍后用于存储自身状态的 bucket,因此它的首次运行使用本地 backend,然后再进行迁移。操作流程详见 [live/bootstrap/README.md](live/bootstrap/README.md)。
State 存在于**管理**账户中,而不是安全账户中。这是一个经过深思熟虑的权衡,记录为 ADR-004。
## CI 门控
| 门控 | 工具 | 状态 |
|------|------|--------|
| 格式化 + lint | `terraform fmt -check`, `tflint --recursive` | 运行中 |
| 静态安全 | `trivy config`, `checkov` | 运行中 |
| 验证 | `terraform init -backend=false` + `validate`,每个 stack | 运行中 |
| PR 上的 Plan | 针对真实 AWS 的 `terraform plan`,只读 OIDC 角色 | 运行中 |
| 门控 apply | `production` 环境,仅限 `main` | 角色已存在;工作流步骤尚未接入 |
所有 stack 目前的门控基线为:**0 发现** — checkov 376 通过 / 0 失败 / 21 跳过,trivy 和 tflint 无异常。每次抑制都带有其内联原因,如果发现是真实的,还会带有一个威胁模型 ID 和关闭该发现的 stack。
第三方 action 被固定到 commit SHA 而非 tag。Tag 是可变的——控制 action 仓库的人可以将其重新指向新代码,这就是 T7 从后门侵入的途径。
plan 任务假定使用一个**只读**角色,其信任策略使用 `StringEquals` 而非 `StringLike` 来锁定 `sub` 声明。`repo:owner/name:*` 也会匹配到 fork 的 pull request,而这是唯一一条绝不能持有凭证的路径。它被拒绝进行 state 写入,并使用 `-lock=false` 运行,因此运行失败不会留下锁,从而避免需要他人强制解锁。
## 证据
[docs/evidence/scp-verification.md](docs/evidence/scp-verification.md) — 每一个 SCP 都是在成员账户内部以账户管理员的身份进行探测的,因为 SCP 是唯一可以拒绝该管理员的机制。包括一项展示角色策略是受限而非全面的负面控制,以及一个防护机制正确阻止了清理失误的真实事件。
[docs/evidence/logging-verification.md](docs/evidence/logging-verification.md) — 组织 trail 正在交付:组织前缀下的真实日志对象,以及来自多个账户的 CloudWatch 流。
[docs/evidence/detection-verification.md](docs/evidence/detection-verification.md) — 五个 Config recorder 报告 `SUCCESS`,这证明了整个跨账户、CMK 加密的交付路径运行正常。同时也明确指出了哪些内容*尚未*得到验证。
**待定,而非空谈:** CIS 分数和实际成本数据。检测于 2026-07-28 应用;Security Hub 需要约 24 小时来配置控制措施,且 Cost Explorer 没有新组织的数据。现在生成的数字只会是时间点的产物。
**关于“之前 vs 之后”:** 防护机制是在 Security Hub 之前启用的,因此已经没有真实的全组织“之前”状态了。替代方案是使用 `awlz-lab` 作为控制组——分离其 SCP、评分、重新附加、再次评分——以此来衡量防护机制的实际价值。推理过程详见检测证据。
## 成本
[docs/cost.md](docs/cost.md)。在 20 美元/月的硬性预算下的纯治理资源占用,并在达到 85% 和 100% 时发出警报。所属区域 `sa-east-1` 的运行成本比 `us-east-1` 高 30–50%;这是出于数据驻留的刻意考量。
## 路线图
- [x] `live/bootstrap` — 远程 state,KMS CMK,原生 S3 锁定
- [x] `live/org-root` — OU、成员账户、集中式 root 访问权限
- [x] `policies/scp` + `live/guardrails` — 区域允许列表,保护检测机制,保护防护机制角色
- [x] CI:fmt / tflint / trivy / checkov
- [x] `live/logging` — 组织 trail → 位于日志归档账户中带有 CMK + Object Lock 的 S3
- [x] `live/ci-oidc` — GitHub OIDC provider + plan 和 apply 角色
- [x] CI:针对 AWS 的 PR 上的真实 `terraform plan`
- [x] `live/detection` — GuardDuty、Config、Security Hub + CIS,委派给 `awlz-security`
- [ ] 将门控 apply 任务接入 `production` 环境
- [ ] 针对 T5 的权限边界 + Config 规则
- [ ] 破窗角色启用警报 (T8)
- [ ] 通过 `awlz-lab` 控制组获取 CIS 分数;计费周期后的实际成本数据
- [ ] 演示录像
## 工具链
terraform 1.15.8,tflint 0.64.0,trivy 0.72.0,checkov 3.3.8,aws-cli 2.36.9。通过已提交的 lock 文件将 provider 固定为 `hashicorp/aws` 6.56.0。配置笔记:[docs/toolchain.md](docs/toolchain.md)。
Organizations, SCPs, Identity Center
Terraform state"] subgraph OU_SEC["OU: Security"] LOG["awlz-log-archive
org trail destination"] SEC["awlz-security
detection delegated admin"] end subgraph OU_WL["OU: Workloads"] DEV["awlz-dev"] LAB["awlz-lab"] end end GHA["GitHub Actions"] -->|OIDC AssumeRole
no static keys| MGMT MGMT -->|"SCPs: region allow-list,
protect detection,
protect guardrail roles"| OU_WL MGMT --> OU_SEC DEV & LAB -->|org trail| TRAIL["CloudTrail org trail"] TRAIL --> LOG DEV & LAB --> GD["GuardDuty"] --> SHUB["Security Hub
CIS benchmark"] SHUB -.-> EVID["docs/evidence/
CIS score pending"] classDef todo stroke-dasharray: 5 5 class EVID todo ``` 虚线 = 尚未生成。决策及其后果:[docs/architecture.md](docs/architecture.md)。当前状态、待办事项以及已踩过的坑:[docs/AwLZ-handbook.md](docs/AwLZ-handbook.md)。 ## 威胁模型 摘要 — 包含可能性、影响和残余风险的完整版本详见 [docs/threat-model.md](docs/threat-model.md)。 | # | 威胁 | 控制措施 | 状态 | |---|--------|---------|--------| | T1 | CI 凭证被盗 → 账户接管 | GitHub OIDC,无静态密钥,角色信任锁定到精确的 `sub` 声明 | **已应用**,`live/ci-oidc` | | T2 | 攻击者禁用日志以隐藏活动 | SCP 拒绝销毁 CloudTrail/Config/GuardDuty/Security Hub | **已应用**,`live/guardrails` | | T3 | 未受监控区域中的资源蔓延 | SCP 区域允许列表 | **已应用 + 已验证** | | T4 | 日志篡改或删除 | 专用日志归档账户、保存在该处的 CMK、Object Lock COMPLIANCE | **已应用 + 已验证** | | T5 | 通过成员账户中的 IAM 提权 | SCP 拒绝对防护机制的 IAM 写入 | **部分** — 仍然缺少权限边界 | | T6 | Terraform state 泄露 | S3 + 客户管理的 KMS 密钥、仅限 TLS 的策略、原生 S3 锁定 | **已应用** | | T6b | State 对象被读取或无痕覆盖 | 限定于 state bucket 的 CloudTrail S3 数据事件 | **已关闭** | | T7 | 恶意或拼写错误的 Terraform 代码被合并 | `tflint` + `trivy config` + `checkov`,PR 上的真实 plan,门控 apply | **已应用** — 规则集要求具有 PR 且 `main` 分支通过检查 | | T8 | 防护机制锁定紧急访问通道 | 破窗角色,已记录并设置警报 | **部分** — 路径已演练,无警报 | | T9 | 在 Identity Center 之外使用成员账户 root | Root 凭证已从成员账户**删除** | **已消除**,`live/org-root` | ## 布局 ``` live/bootstrap/ remote state: S3 + KMS CMK, native locking applied live/org-root/ OUs, member accounts, centralized root access applied live/guardrails/ creates and attaches the SCPs applied policies/scp/ the SCP documents live/logging/ org trail into an object-locked archive account applied live/detection/ GuardDuty, Security Hub, Config, Access Analyzer applied live/ci-oidc/ GitHub OIDC provider + plan and apply roles applied modules/ logging, detection, config-recorder, iam-oidc docs/ architecture, threat model, cost, evidence ``` `live/` 下的每个 stack 都是一个根模块,具有固定的 provider 版本、部分 S3 backend,并设置了 `allowed_account_ids`,这样配置错误会直接失败,而不会继续执行 apply。 ## 运行它 本地认证使用 IAM Identity Center。根据设计,此仓库中没有任何地方存在静态访问密钥。 ``` aws sso login --profile mgmt cd live/
标签:AWS, DPI, ECS, Landing Zone, Terraform, 多云环境管理, 安全合规, 服务控制策略, 漏洞探索, 网络代理