aws-samples/sample-automated-iam-access-keys-lifecycle
GitHub: aws-samples/sample-automated-iam-access-keys-lifecycle
基于 AWS 原生服务构建的组织级 IAM 访问密钥自动化生命周期管理方案,通过人工审批流程安全地识别、禁用和删除未使用的访问密钥。
Stars: 0 | Forks: 0
# AWS IAM Access Key 生命周期管理与人工审批
一个组织级的自动化解决方案,用于使用 AWS Step Functions、IAM Access Analyzer、API Gateway、Lambda 和 CloudFormation StackSets 管理未使用的 IAM 访问密钥。此解决方案在永久删除前包含了一个人工参与的审批步骤。
## 目录
1. [概述](#overview)
2. [架构](#architecture)
3. [工作流程](#workflow)
4. [前置条件](#prerequisites)
5. [部署](#deployment)
6. [配置参数](#configuration-parameters)
7. [安全](#security)
8. [成本](#cost)
9. [故障排除](#troubleshooting)
## 概述
此解决方案可自动识别、禁用和删除您的 AWS 组织中所有账户下未使用的 IAM 用户访问密钥。在永久删除之前,需要通过安全的电子邮件链接进行人工审批。
### 主要功能
- **组织级覆盖**:管理所有 AWS 账户的访问密钥
- **人工参与**:删除前需要通过安全链接进行明确审批
- **安全第一**:在删除前禁用密钥,具有可配置的保留期
- **审批超时**:如果未获批准,执行将在 7 天后过期(密钥保持禁用状态,不会被删除)
- **安全审批链接**:具有加密令牌验证的一次性使用 URL
- **电子邮件通知**:接收禁用通知和审批请求
- **自动调度**:可通过 EventBridge 进行可选的定期执行
- **完整的审计跟踪**:X-Ray 跟踪和 CloudWatch 日志记录
### 此解决方案的功能
1. 使用 Access Analyzer 监控未使用的 IAM 访问密钥
2. 自动禁用所有账户中未使用的密钥
3. 发送密钥已被禁用的通知
4. 等待一个可配置的保留期(默认:1 天)
5. 发送带有安全一次性链接的审批请求电子邮件
6. 等待人工审批(或在 7 天后超时)
7. 仅在审批后永久删除密钥
8. 提供完整的审计跟踪
## 架构
### 组件
**管理账户堆栈** (`management-account-template.yaml`):
- **Step Functions 状态机**:通过人工审批编排工作流程
- **Lambda 函数**:处理审批请求和回调
- **API Gateway**:为审批链接提供 REST endpoint
- **SNS 主题**:发送电子邮件通知
- **CloudWatch 告警**:监控执行失败情况
- **EventBridge 规则**:调度自动执行(可选)
**目标账户堆栈集** (`target-account-template.yaml`):
- **AccessKeyManagementRole**:用于密钥管理操作的跨账户 IAM 角色
### 架构图
```
Management Account
├─ Step Functions (orchestration)
│ ├─ List unused keys (Access Analyzer)
│ ├─ Disable keys (cross-account)
│ ├─ Wait (hold period)
│ ├─ Request approval (Lambda + task token) ⏸️ PAUSED
│ └─ Delete keys (if approved)
├─ Lambda Functions
│ ├─ Approval Request (sends email)
│ └─ Approval Callback (handles link click)
├─ API Gateway (/approve endpoint)
└─ SNS Topic (email notifications)
Member Accounts
└─ AccessKeyManagementRole (IAM permissions)
Approval Flow:
Email → Human clicks link → API Gateway → Lambda → Step Functions resumes → Keys deleted
```
## 工作流程
### 执行流程
1. **列出发现项**:查询 Access Analyzer 以获取未使用的访问密钥
2. **过滤密钥**:排除管理账户密钥(仅限成员账户)
3. **禁用密钥**:将所有账户的状态设置为 "Inactive"
4. **发送通知**:确认密钥已被禁用的电子邮件
5. **等待期**:可配置的保留期(默认:1 天)
6. **请求审批**:Lambda 发送带有安全一次性审批链接的电子邮件
- Step Functions 使用任务令牌模式在此处**暂停**
- 等待审批期间不产生成本
7. **人工决定**:
- **批准**:点击链接 → 密钥被删除
- **忽略**:7 天后超时 → 密钥保持禁用状态(不被删除)
8. **删除密钥**:永久移除访问密钥(仅在批准后)
9. **报告结果**:已处理密钥的摘要
### 审批机制
该解决方案使用 Step Functions 的 `.waitForTaskToken` 模式:
- Step Functions 生成加密安全的任务令牌
- 令牌嵌入在通过电子邮件发送的审批 URL 中
- 执行暂停(等待期间无成本)
- 人工点击链接 → API Gateway → Lambda → `SendTaskSuccess()`
- Step Functions 恢复并删除密钥
**令牌安全性**:一次性使用,7 天后自动过期,无法重复使用或被猜测
## 前置条件
在部署此解决方案之前,请确保您具备:
### 必要条件
1. **AWS Organization**:具有多个账户的活跃 AWS Organization
2. **IAM Access Analyzer**:已配置组织级别的 Access Analyzer
- 必须正在分析未使用的 IAM 用户访问密钥
- 记下 Analyzer ARN(格式:`arn:aws:access-analyzer:region:account:analyzer/name`)
3. **CloudFormation StackSets**:在您的组织中已启用
4. **管理员访问权限**:用于管理账户
5. **AWS CLI**:已安装并配置了适当的凭证
### 需收集的信息
部署前,请收集以下内容:
```
# 获取你的 Organization ID
aws organizations describe-organization --query 'Organization.Id' --output text
# 示例输出: o-abc1234567
# 获取你的 Management Account ID
aws sts get-caller-identity --query 'Account' --output text
# 示例输出: 123456789012
# 获取你的 Root OU ID
aws organizations list-roots --query 'Roots[0].Id' --output text
# 示例输出: r-a1b2
# 列出 Access Analyzers
aws accessanalyzer list-analyzers --query 'analyzers[*].[name,arn]' --output table
```
记录这些值:
- **组织 ID**:`o-__________`
- **管理账户 ID**:`____________`
- **根 OU ID**:`r-____`
- **Access Analyzer ARN**:`arn:aws:access-analyzer:______:______:analyzer/______`
- **部署区域**:`______`
- **通知电子邮件**:`______@______`
## 部署
### Lambda 函数
Lambda 函数代码直接嵌入在 CloudFormation 模板中,以便于部署。`lambda/` 目录中也提供了独立的 Python 文件,以供参考和本地测试:
- `lambda/approval-request-handler.py` - 发送审批请求电子邮件
- `lambda/approval-callback-handler.py` - 处理审批链接回调
### 部署过程
#### 阶段 1:目标账户角色 (StackSet)
这会将跨账户 IAM 角色部署到您组织中的所有账户。
**创建 StackSet:**
```
aws cloudformation create-stack-set \
--stack-set-name AccessKeyManagementRoles \
--template-body file://cloudformation-templates/target-account-stackset-template.yaml \
--parameters \
ParameterKey=ManagementAccountId,ParameterValue= \
ParameterKey=StepFunctionsExecutionRoleName,ParameterValue=StepFunctionsAccessKeyManagementRole \
ParameterKey=OrganizationId,ParameterValue= \
--capabilities CAPABILITY_NAMED_IAM \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false
```
**部署堆栈实例:**
```
aws cloudformation create-stack-instances \
--stack-set-name AccessKeyManagementRoles \
--deployment-targets OrganizationalUnitIds= \
--regions
```
**验证部署:**
```
# 检查操作状态
aws cloudformation describe-stack-set-operation \
--stack-set-name AccessKeyManagementRoles \
--operation-id
# 列出所有 stack instances
aws cloudformation list-stack-instances \
--stack-set-name AccessKeyManagementRoles
```
#### 阶段 2:管理账户堆栈
这将部署 Step Functions 状态机、Lambda 函数和 API Gateway。
**创建堆栈:**
```
aws cloudformation create-stack \
--stack-name AccessKeyManagementStateMachine \
--template-body file://cloudformation-templates/management-account-template.yaml \
--parameters \
ParameterKey=AnalyzerArn,ParameterValue= \
ParameterKey=NotificationEmail,ParameterValue= \
ParameterKey=OrganizationId,ParameterValue= \
ParameterKey=HoldPeriod,ParameterValue=1 \
ParameterKey=ApprovalTimeout,ParameterValue=7 \
ParameterKey=ScheduleIntervalDays,ParameterValue=7 \
ParameterKey=EnableScheduler,ParameterValue=true \
--capabilities CAPABILITY_NAMED_IAM
```
**监控堆栈创建:**
```
# 检查 stack 状态
aws cloudformation describe-stacks \
--stack-name AccessKeyManagementStateMachine \
--query 'Stacks[0].StackStatus'
# 查看 stack 事件
aws cloudformation describe-stack-events \
--stack-name AccessKeyManagementStateMachine \
--max-items 20
```
**获取堆栈输出:**
```
aws cloudformation describe-stacks \
--stack-name AccessKeyManagementStateMachine \
--query 'Stacks[0].Outputs'
```
关键输出:
- `StateMachineArn`:Step Functions 状态机的 ARN
- `ApprovalApiUrl`:审批 API endpoint 的 URL
- `NotificationTopicArn`:SNS 主题的 ARN
- `ApprovalRequestFunctionArn`:审批请求 Lambda 的 ARN
- `ApprovalCallbackFunctionArn`:审批回调 Lambda 的 ARN
#### 阶段 3:SNS 订阅确认
1. 检查您的电子邮件以获取 AWS SNS 订阅确认
2. 点击 "Confirm subscription" 链接
3. 验证您看到了确认页面
## 配置参数
### 管理账户模板参数
| 参数 | 描述 | 默认值 | 有效范围 | 必填 |
|-----------|-------------|---------|-------------|----------|
| `AnalyzerArn` | 您的 Access Analyzer 的 ARN | - | 有效的 analyzer ARN | 是 |
| `NotificationEmail` | 用于通知和审批的电子邮件 | - | 有效的电子邮件地址 | 是 |
| `OrganizationId` | 您的 AWS Organization ID | - | 格式:o-xxxxxxxxxx | 是 |
| `HoldPeriod` | 禁用与请求审批之间的天数 | 1 | 1-90 天 | 否 |
| `ApprovalTimeout` | 等待审批直到过期前的天数 | 7 | 1-30 天 | 否 |
| `ScheduleIntervalDays` | 自动运行间隔天数 | 7 | 1-365 天 | 否 |
| `EnableScheduler` | 启用自动调度 | true | true/false | 否 |
| `StateMachineName` | 状态机名称 | AccessKeyManagementStateMachine | - | 否 |
| `ExecutionRoleName` | 执行角色名称 | StepFunctionsAccessKeyManagementRole | - | 否 |
### 目标账户模板参数
| 参数 | 描述 | 默认值 | 必填 |
|-----------|-------------|---------|----------|
| `ManagementAccountId` | 管理账户 ID | - | 是 |
| `StepFunctionsExecutionRoleName` | 执行角色名称 | StepFunctionsAccessKeyManagementRole | 否 |
| `AccessKeyManagementRoleName` | 目标角色名称 | AccessKeyManagementRole | 否 |
### 参数详情
**AnalyzerArn**
- 格式:`arn:aws:access-analyzer:region:account-id:analyzer/analyzer-name`
- 必须是组织级别的 analyzer
- 必须配置为分析未使用的 IAM 用户访问密钥
- 查找您的 analyzer:`aws accessanalyzer list-analyzers`
**NotificationEmail**
- 必须是有效的电子邮件地址
- 将同时接收禁用通知和审批请求
- 确保您可以访问此电子邮件
- 如果未收到,请检查垃圾邮件/垃圾箱文件夹
**OrganizationId**
- 格式:`o-` 后跟 10 个字母数字字符
- 查找您的 ID:`aws organizations describe-organization --query 'Organization.Id'`
- 用于安全边界强制执行
**HoldPeriod**
- 禁用密钥与请求审批之间的时间
- 给用户提供时间报告是否仍需要这些密钥
- 建议:1-7 天
- 较长的期限会延迟修复,但可提供更多的审查时间
**ApprovalTimeout**
- 等待人工审批的最长时间
- 此时间过后,执行将过期(密钥不会被删除)
- 在当前实现中固定为 7 天(604800 秒)
- 不能超过 Step Functions 的最大执行时间
**ScheduleIntervalDays**
- 工作流自动运行的频率
- 建议:7-30 天
- 越频繁 = 检测越快,电子邮件越多
- 越不频繁 = 电子邮件越少,检测越慢
**EnableScheduler**
- 设置为 `true` 以启用自动调度
- 设置为 `false` 仅进行手动执行
- 可在部署后更改
## 成本
请注意,您将因部署此解决方案以及消耗的任何 AWS 服务而被收费。决定确切定价的因素如下-
### 成本因素
**执行频率:**
- 执行越频繁 = 成本越高
- 默认值:每 7 天
- 建议:7-30 天
**发现项数量:**
- 未使用的密钥越多 = 状态转换越多
- Lambda 调用越多
- API 调用越多
**执行持续时间:**
- Step Functions 按状态转换收费,而不是按持续时间收费
- 等待审批期间不收费(任务令牌模式)
- 较长的保留期不会增加成本
**免费套餐权益:**
- Lambda:每月 100 万次请求免费
- API Gateway:每月 100 万次请求免费(前 12 个月)
- CloudWatch:10 个自定义指标免费
- X-Ray:每月 100,000 个跟踪免费
## 安全
### 安全最佳实践
1. **保护审批电子邮件**
- 使用安全的电子邮件提供商
- 启用电子邮件加密
- 不要转发审批链接
- 使用后删除电子邮件
2. **限制访问权限**
- 限制谁可以修改 CloudFormation 堆栈
- 限制对 Step Functions 控制台的访问
- 控制 Lambda 函数的修改
- 保护 SNS 主题订阅
## 故障排除
### 常见问题及解决方案
#### 未处理任何发现项
**症状:**
- 执行立即完成
- 输出:“未找到未使用的 IAM 访问密钥”
- 未收到任何电子邮件
**解决方案:**
1. 验证 Access Analyzer 是否已配置:
aws accessanalyzer list-analyzers
2. 检查 analyzer 是否正在分析您的组织
3. 确保 analyzer 已完成初始扫描(可能需要数小时)
4. 验证参数中的 analyzer ARN 是否正确
5. 在控制台中检查 Access Analyzer 的发现项
#### 跨账户访问失败
**症状:**
- 在 "UpdateAccessKey" 或 "DeleteAccessKey" 状态下执行失败
- 错误:“AccessDenied”或“AssumeRole failed”
**解决方案:**
1. 验证 StackSet 是否部署成功:
aws cloudformation list-stack-instances \
--stack-set-name AccessKeyManagementRoles
2. 检查目标账户中是否存在 `AccessKeyManagementRole`
3. 验证信任策略是否包含管理账户
4. 确认组织 ID 是否正确
5. 检查外部 ID 是否匹配
6. 验证角色是否具有所需的权限
#### 未收到电子邮件通知
**症状:**
- 未收到任何电子邮件
- SNS 订阅未确认
**解决方案:**
1. 检查垃圾邮件/垃圾箱文件夹
2. 验证参数中的电子邮件地址
3. 确认 SNS 订阅:
aws sns list-subscriptions-by-topic \
--topic-arn
4. 检查 SNS 主题是否存在
5. 验证 Lambda 是否有权发布到 S
6. 查看 Lambda 日志是否有错误
#### 审批链接无效
**症状:**
- 点击链接显示错误页面
- 错误:“Invalid or expired approval token”
**解决方案:**
1. 检查链接是否已使用过(一次性使用)
2. 验证执行未超时(7 天限制)
3. 检查 API Gateway 部署:
aws apigateway get-deployments \
--rest-api-id
4. 查看 Lambda 回调函数日志:
aws logs tail /aws/lambda/AccessKeyManagementStateMachine-ApprovalCallback
5. 验证 Lambda 是否具有调用 SendTaskSuccess 的权限
6. 检查 Step Functions 执行是否仍在运行
#### Step Functions 执行失败
**症状:**
- 执行状态:“Failed”
- 触发了 CloudWatch 告警
**解决方案:**
1. 在 Step Functions 控制台中查看执行详情
2. 检查执行事件历史记录以获取错误详情
3. 查看 CloudWatch Logs:
aws logs filter-log-events \
--log-group-name /aws/lambda/AccessKeyManagementStateMachine-ApprovalRequest \
--filter-pattern "ERROR"
4. 检查 X-Ray 跟踪以获取详细的错误信息
5. 验证所有 IAM 权限是否正确
6. 确保 Access Analyzer ARN 有效
#### Lambda 函数错误
**症状:**
- Lambda 调用失败
- CloudWatch Logs 中出现错误
**解决方案:**
1. 检查 Lambda 函数日志:
aws logs tail /aws/lambda/ --follow
2. 验证环境变量是否设置正确
3. 检查 Lambda 执行角色权限
4. 确保 Lambda 具有网络连接(如果在 VPC 中)
5. 验证 Python 运行时版本兼容性
#### API Gateway 错误
**症状:**
- 点击审批链接时出现 4xx 或 5xx 错误
- API Gateway 指标显示错误
**解决方案:**
1. 检查 API Gateway 日志(如果已启用)
2. 验证 Lambda 集成配置是否正确
3. 测试 API Gateway endpoint:
curl -v "https://.execute-api..amazonaws.com/prod/approve?token=test"
4. 检查用于 API Gateway 调用的 Lambda 权限
5. 验证 API Gateway 部署是否处于活动状态
#### 执行超时问题
**症状:**
- 在审批前执行超时
- 状态:“Succeeded”并带有超时消息
**解决方案:**
1. 如果在 7 天内未给出审批,这是预期行为
2. 密钥保持禁用状态但未被删除
3. 要更改超时时间,请修改状态机定义中的 `TimeoutSeconds`
4. 注意:不能超过 Step Functions 的最大值(1 年)
5. 考虑 7 天是否适合您的组织
### 获取帮助
如果您仍然遇到问题:
1. **查看 AWS 文档**
- [Step Functions 故障排除](https://docs.aws.amazon.com/step-functions/latest/dg/troubleshooting.html)
- [Lambda 故障排除](https://docs.aws.amazon.com/lambda/latest/dg/lambda-troubleshooting.html)
- [API Gateway 故障排除](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-troubleshooting.html)
2. **检查 CloudWatch Logs**
- 所有 Lambda 函数都记录到 CloudWatch
- 查找 ERROR 或 WARN 消息
- 检查时间戳是否与您的执行匹配
3. **验证配置**
- 仔细检查所有参数
- 确保 ARN 正确
- 验证组织 ID
- 确认电子邮件地址
标签:Access Analyzer, API Gateway, AWS, CloudFormation, CloudWatch, DPI, EventBridge, Human-in-the-Loop, IAM, Lambda, Serverless, StackSets, Step Functions, Streamlit, X-Ray, 人机协同, 安全合规, 安全基线, 审批工作流, 密钥轮换, 教学环境, 未使用密钥清理, 生命周期管理, 网络代理, 网络调试, 自动化, 访问控制, 身份与访问管理, 逆向工具