dracaruss/STS-Based-Cross-Account-Role-Assumption-Pattern
GitHub: dracaruss/STS-Based-Cross-Account-Role-Assumption-Pattern
一个用 Terraform 构建的 AWS 跨账户角色代入架构演示,通过双向信任策略和 MFA 强制执行,帮助理解 Identity Center 底层机制和安全团队的多账户访问模式。
Stars: 0 | Forks: 0
# IAM 跨账户角色代入
构建 AWS Identity Center 在底层自动化的手动跨账户 IAM 架构。这是一个学习练习,旨在理解信任策略、STS AssumeRole 和基础设施层面的最小权限设计——而不仅仅是在控制台中点击操作。
## 这实际上做了什么
两个独立的 Terraform 配置模拟了一个多账户设置,其中一个 AWS 账户(“Security”身份账户)的安全工程师代入另一个账户(“Workload”账户)的临时角色,以执行审计或响应事件。
在实际企业中,这会是两个完全不同的 AWS 账户。在这个实验中,我使用单个账户来托管双方,但信任策略的机制是完全相同的。
**Workload 账户创建:**
- `SecurityAuditRole` — 使用 AWS 托管的 `SecurityAudit` 策略进行只读访问。需要 MFA。
- `IncidentResponderRole` — 用于遏制的 12 个特定 API 操作(隔离 EC2、创建卷快照、禁用受损密钥)。需要在一小时内使用过 MFA。
**Security 账户创建:**
- `SecurityEngineers` 组 — 成员只能代入审计角色。
- `IncidentResponders` 组 — 成员只能代入 IR 角色。
双方必须达成一致才能进行访问。Workload 账户信任策略表示“我信任此账户”,而 Security 账户组策略表示“这些成员可以代入该角色”。移除任何一方,AssumeRole 调用都会失败。这是 AWS 中所有跨账户访问的双向握手机制。
## 为什么构建这个
我想理解跨账户访问背后的实际机制,而不仅仅是知道如何使用 Identity Center 的门户。每个企业都在使用这种模式,无论他们是否知道——Identity Center、Control Tower 和 AWS SSO 都在底层生成信任策略和 STS 调用。如果你只知道门户,当出现问题时你将无法进行故障排除。
这也反映了安全团队的实际运作方式。他们是唯一需要查看组织中每个账户可见性的部门——生产、HR 系统、财务、数据平台。像 SOC 2、PCI-DSS 和 HIPAA 这样的合规框架要求具备独立的审计能力。安全团队通过设计获得到处都是只读信任策略,而 HR 只能看到 HR,财务只能看到财务。
## 架构
```
┌─────────────────────────┐ ┌─────────────────────────┐
│ SECURITY ACCOUNT │ │ WORKLOAD ACCOUNT │
│ (Identity Hub) │ │ (Where infra runs) │
│ │ │ │
│ ┌───────────────────┐ │ STS │ ┌───────────────────┐ │
│ │ SecurityEngineers │──┼────────>│ │ SecurityAuditRole │ │
│ │ (IAM Group) │ │ Assume │ │ (Read-only) │ │
│ └───────────────────┘ │ Role │ └───────────────────┘ │
│ │ + MFA │ │
│ ┌───────────────────┐ │ │ ┌───────────────────┐ │
│ │ IncidentResponders│──┼────────>│ │ IncidentResponder │ │
│ │ (IAM Group) │ │ Assume │ │ Role (Containment)│ │
│ └───────────────────┘ │ Role │ └───────────────────┘ │
│ │ + MFA │ │
│ │ < 1hr │ │
└─────────────────────────┘ └─────────────────────────┘
```
## 文件夹结构
```
iam-cross-account-access/
├── README.md
├── security-account/
│ ├── main.tf # Groups and assume-role policies
│ ├── variables.tf # Workload account ID input
│ ├── outputs.tf # Group names and account ID
│ └── providers.tf # AWS provider config
└── workload-account/
├── main.tf # Roles, trust policies, permissions
├── variables.tf # Security account ID input
├── outputs.tf # Role ARNs
└── providers.tf # AWS provider config
```
## 部署
先部署 Workload 账户——角色需要先存在,Security 账户才能引用它们。
```
# 认证
aws login
# Terraform 的 Bridge credentials(aws login 将凭证存储在 Terraform 无法找到的位置)
eval "$(aws configure export-credentials --format env)"
# 部署 workload account 角色
cd workload-account
terraform init
terraform apply -var='security_account_id=YOUR_ACCOUNT_ID'
# 部署 security account 组
cd ../security-account
terraform init
terraform apply -var='workload_account_id=YOUR_ACCOUNT_ID'
```
## 验证
```
# 担任 audit role(替换为您的实际 MFA serial 和实时 token code)
aws sts assume-role \
--role-arn arn:aws:iam::YOUR_ACCOUNT_ID:role/SecurityAuditRole \
--role-session-name test-session \
--serial-number arn:aws:iam::YOUR_ACCOUNT_ID:mfa/YOUR_MFA_DEVICE \
--token-code YOUR_6_DIGIT_CODE
# 从响应中导出临时凭证
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
# 验证您现在正以 audit role 身份操作
aws sts get-caller-identity
```
## 清理
```
eval "$(aws configure export-credentials --format env)"
cd workload-account && terraform destroy -var='security_account_id=YOUR_ACCOUNT_ID' -auto-approve
cd ../security-account && terraform destroy -var='workload_account_id=YOUR_ACCOUNT_ID' -auto-approve
```
## 设计决策与所学到的
**托管策略 vs 自定义策略。** 审计角色使用 AWS 托管的 `SecurityAudit` 策略,因为 AWS 会在新服务发布时维护它。IR 角色使用包含确切 12 个 API 操作的自定义内联策略,因为没有针对“隔离服务器并获取取证快照”的托管策略。我了解到大多数团队使用混合方式——通用模式使用托管策略,特定工作流使用自定义策略。
**MFA 强制执行差异。** 两个角色都需要 MFA,但事件响应角色增加了 `aws:MultiFactorAuthAge < 3600`——必须在过去一小时内使用过 MFA。更高的权限对应更严格的验证。这是我直到在信任策略条件块中看到才体会到的细节之一。
**`aws login` 凭证问题。** Terraform 的 AWS provider 原生不支持从 `aws login` 的基于浏览器的身份验证流中读取凭证。解决方法是在每个 Terraform 命令之前执行 `eval "$(aws configure export-credentials --format env)"`。凭证仍然是临时的和基于会话的——没有长期凭证被写入磁盘。这很难弄清楚,但值得记录下来,因为任何使用 `aws login` 配合 Terraform 的人都会遇到同样的障碍。
**为什么是两个目录而不是一个。** 在生产中,这些针对具有不同凭证的不同 AWS 账户。保持它们分离反映了现实。权衡是部署顺序变成了人为责任——跨目录没有 `depends_on`。在成熟的设置中,你会使用 Terragrunt 或带有分阶段作业的 CI/CD pipeline 来强制执行顺序。
**`:root` 主体并不意味着 root 用户。** 信任策略中的 `arn:aws:iam::ACCOUNT_ID:root` 意味着“该账户中拥有代入此角色自身权限的任何身份”。我最初以为它是授予 root 用户访问权限。它授予的是整个账户,而账户自身的 IAM 策略控制哪些特定用户可以实际代入。
**Outputs 不仅仅是注释。** 我最初认为 `outputs.tf` 只是为了向终端打印信息。对于这个项目确实如此,但 outputs 也通过 `terraform_remote_state` 充当 Terraform 配置之间的数据桥梁,通过 `terraform output -json` 被 CI/CD pipelines 消费,并在代码被封装在模块中时充当返回值。了解 outputs 何时是装饰性的 versus 基础设施的一部分很重要。
**资源命名:三个名字,三个目的。** `resource "aws_iam_role" "security_audit_role"` 有三个不同的标识符。`aws_iam_role` 是 AWS provider 资源类型(你不能更改它)。`security_audit_role` 是 Terraform 的内部标签(仅存在于你的代码中)。`name = "SecurityAuditRole"` 是在 AWS 中实际创建的名称。我早期经常混淆这些。
## 在生产中我会做哪些不同的事
- 使用 Terragrunt 或带有 provider aliases 的单个 Terraform 配置来强制执行部署顺序
- 将 IR 策略的 `Resource` 字段限定为特定 ARN,而不是 `"*"`(Checkov 会标记此问题)
- 在 CI/CD 预部署阶段运行 Checkov,部署后运行 IAM Access Analyzer
- 使用带有分阶段作业(`needs` 关键字)的 GitHub Actions 来链式执行 workload → security 部署
- 将 Terraform state 远程存储在带有 DynamoDB 锁定的 S3 中,而不是本地 state 文件
- 从 SSM Parameter Store 或 Terraform remote state 拉取账户 ID,而不是作为 `-var` 标志传递
## 工具
- Terraform >= 1.0
- AWS Provider ~> 5.0
- AWS CLI 配合 `aws login` 进行基于浏览器的身份验证
- Checkov 用于静态 IaC 分析(建议预部署使用)
- IAM Access Analyzer 用于策略验证(建议部署后使用)
标签:AssumeRole, AWS, DevSecOps, DPI, EC2, EC2隔离, ECS, IaC, IAM, MFA, STS, Terraform, 上游代理, 信任策略, 多云架构, 最小权限, 服务器监控, 权限管理, 模型越狱, 跨账户访问, 身份中心