ELMBoukhriss/Automated-IAM-Incident-Response-on-AWS
GitHub: ELMBoukhriss/Automated-IAM-Incident-Response-on-AWS
该项目通过 AWS GuardDuty、Lambda 与 EventBridge 实现凭证泄露后的自动化 IAM 遏制,将事件响应时间从数小时压缩至约一分钟。
Stars: 0 | Forks: 0
# AWS 上的自动化 IAM 事件响应
## 背景与业务影响
iCorp 是一家虚构的 B2B SaaS 公司,负责为企业客户处理付款。其 AWS 环境(S3 存储桶)保存着客户 PII、交易记录和合同文档,所有这些都可以通过 IAM 服务账户凭证进行访问。
最近,一名威胁行为者通过网络钓鱼活动获取了有效的访问密钥。该密钥从一个已知的恶意 IP 地址被用于枚举 S3 存储桶并开始数据外泄。由于 SOC 没有实施任何自动化,警报在 GuardDuty 中一直未被注意到,直到第二天早上一名分析师打开控制台,导致暴露窗口长达 10 到 16 个小时。
该项目的目标是实现响应流程自动化,要求在遏制阶段零人工干预,并将平均响应时间 (MTTR) 缩短至大约一分钟。这将使暴露窗口减少约 99%。请注意,虽然整体响应几乎是瞬时的,但总检测时间仍然取决于 GuardDuty 识别并发布检测结果的速度。
一旦通过 GuardDuty 检测到受损的 IAM 凭证,自动化工作流程将立即撤销该访问密钥,通过 AWS Lambda 函数使用明确的“拒绝所有” (Deny-All) 策略锁定身份,在 DynamoDB 中记录结构化的事件案例,并通过电子邮件向安全团队发出警报。所有这些编排工作都在 GuardDuty 发布检测结果的同一分钟内完成。
## 架构
## 威胁建模 (STRIDE)
为了构建安全设计结构,我使用了 STRIDE 框架——这是一种在云环境中思考威胁的简单而强大的方法。
| 类别 | 威胁 | 控制 |
|---|---|---|
| **欺骗** | 从恶意 IP 使用被盗的长期访问密钥来冒充 `icorp-app-service-account` | GuardDuty 的 `MaliciousIPCaller` 检测会在发布检测结果后的 60 秒内触发自动密钥撤销 |
| **篡改** | 攻击者在被遏制之前通过 `iam:AttachUserPolicy` 提升权限以获取更广泛的访问权限 | 将 `IREmergencyDenyAll` 内联 Deny-All 策略应用于身份——无论附加了什么权限,所有后续的 API 调用都会被阻止 |
| **否认** | 攻击者禁用 CloudTrail 以抹除 API 活动的证据并掩盖横向移动 | 启用 CloudTrail 日志文件验证 + 在日志存储桶上启用 S3 MFA 删除,防止篡改审计跟踪 |
| **信息泄露** | 攻击者在 GuardDuty 发布检测结果之前枚举 S3 存储桶并外泄客户 PII | 启用了 GuardDuty S3 Protection;约 5-10 分钟的检测窗口限制了数据外泄量 |
| **拒绝服务** | 使用被盗密钥大规模终止 EC2 实例或删除 RDS 快照,导致生产环境停机 | 密钥撤销和 Deny-All 策略可在 Lambda 执行后的几秒钟内阻止所有破坏性的 API 调用 |
| **权限提升** | 调用 `sts:AssumeRole` 从受损的服务账户跳转到权限更高的管理员角色 | Deny-All 策略会在遏制后阻止 `AssumeRole`;5-10 分钟的 GuardDuty 检测窗口是主要的风险面 |
## 技术步骤
### 1. 实验环境设置
对于本实验,我将使用一个免费套餐 AWS 账户,并配置一个用于 CLI 和控制台的 IAM 用户,在区域方面我选择了 eu-west-1(爱尔兰),因为它在摩洛哥的延迟较低。
/!\ 如果您想重现此实验,请务必设置预算警报并在完成后销毁实验环境,以避免产生任何意外费用。
```
# 验证 CLI 已配置
aws sts get-caller-identity
# 为整个会话设置 region 和 account ID
export AWS_DEFAULT_REGION=eu-west-1
export ACCOUNT_ID=123456789
```
### 2. 启用 GuardDuty 并生成示例检测结果
```
# 我已经启用了 GuardDuty,首次使用请运行以下命令
aws guardduty create-detector --enable --finding-publishing-frequency FIFTEEN_MINUTES
# 保存 detector ID
export DETECTOR_ID=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text)
# 确认已启用
aws guardduty get-detector --detector-id $DETECTOR_ID --query '{Status: Status}'
```
GuardDuty 提供了生成安全示例检测结果的功能,这些结果类似于真实攻击,我们可以用它们来测试事件响应流程。
对于这种情况,我选择使用 "UnauthorizedAccess:IAMUser/MaliciousIPCaller" 检测结果来模拟用户访问密钥泄露以及被已知恶意 IP 使用的情况。
```
# 生成示例 findings
aws guardduty create-sample-findings --detector-id $DETECTOR_ID --finding-types "UnauthorizedAccess:IAMUser/MaliciousIPCaller"
# 列出 MaliciousIPCaller finding ID
aws guardduty list-findings --detector-id $DETECTOR_ID --finding-criteria '{"Criterion":{"type":{"Eq":["UnauthorizedAccess:IAMUser/MaliciousIPCaller"]}}}' --query 'FindingIds'
# 保存 finding ID
export FINDING_ID={Replace_with_FINDING_ID}
# 可视化查看 finding JSON 详情
aws guardduty get-findings --detector-id $DETECTOR_ID --finding-ids $FINDING_ID --query 'Findings[0]'
```
我们还可以通过 GUI 控制台查看该检测结果。
### 3. 创建 IAM 受害者用户账户
该受害者用户将是一个有权访问 S3 存储桶的应用程序服务账户。
```
# 创建受害服务账户
aws iam create-user --user-name icorp-app-service-account
# 附加 S3 scoped policy
aws iam attach-user-policy --user-name icorp-app-service-account --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# 创建 access key(这是在遏制期间将被撤销的内容)
aws iam create-access-key --user-name icorp-app-service-account > victim_key.json
cat victim_key.json
# 保存 key ID 以供整个实验使用
export VICTIM_KEY_ID={Replace_by_VICTIM_KEY_ID}
```
### 4. 创建 Lambda 执行角色
为了使 Lambda 函数能够自动化执行 IR 操作,我们需要为其授予 IAM 用户遏制(密钥撤销和附加 Deny-All 策略)、SNS 和 DynamoDB 所需的权限。
```
# Trust policy(此 policy 将允许 lambda service assume 该 role)
cat > lambda-trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
EOF
# 创建 role
aws iam create-role --role-name icorp-IR-lambda-role --assume-role-policy-document file://lambda-trust-policy.json --description "Execution role for iCorp IR containment lambda"
# 保存 role ARN
export LAMBDA_ROLE_ARN={Replace_with_ROLE_ARN}
# 附加 managed policies
for policy in \
"IAMFullAccess" \
"AmazonDynamoDBFullAccess" \
"AmazonSNSFullAccess" \
"service-role/AWSLambdaBasicExecutionRole"; do
aws iam attach-role-policy \
--role-name icorp-IR-lambda-role \
--policy-arn arn:aws:iam::aws:policy/$policy
echo "Attached: $policy"
done
# 确认已附加全部四个
aws iam list-attached-role-policies --role-name icorp-IR-lambda-role --query 'AttachedPolicies[].PolicyName'
```
### 5. 创建 DynamoDB 案例记录表
该 DynamoDB 表将作为案例记录,供 SOC 分析师/安全工程师查看受影响的用户和密钥。
```
# 创建 table
aws dynamodb create-table --table-name icorp-IR-cases \
--attribute-definitions AttributeName=case_id,AttributeType=S \
--key-schema AttributeName=case_id,KeyType=HASH --billing-mode PAY_PER_REQUEST
# 等待 active 状态
aws dynamodb wait table-exists --table-name icorp-IR-cases
# 确认 table 创建
aws dynamodb describe-table --table-name icorp-IR-cases --query 'Table.{Name:TableName, Status:TableStatus}'
```
### 6. 创建 SNS 电子邮件并订阅邮件
为了在触发自动化 IR 时能够接收即时电子邮件,我们将创建一个 SNS 主题并使用我们的电子邮件地址进行订阅。
```
# 创建 topic
aws sns create-topic --name icorp-IR-alets
# 保存 ARN
export SNS_TOPIC_ARN={Replace_with_SNS_TOPIC_ARN}
# Subscribe
aws sns subscribe --topic-arn $SNS_TOPIC_ARN --protocol email --notification-endpoint {email address}
```
We will receive an email from aws to confirm our subscription to the topic.
```
# 确认后 — 验证 subscription 是否已生效
aws sns list-subscriptions-by-topic --topic-arn $SNS_TOPIC_ARN \
--query 'Subscriptions[0].{Protocol:Protocol,Endpoint:Endpoint,Status:SubscriptionArn}'
```
### 7. 打包并部署 Lambda
Lambda 函数将负责在接收到 GuardDuty 的触发后执行遏制流程。
完整函数代码 -> [handler.py](https://github.com/ELMBoukhriss/Automated-IAM-Incident-Response-on-AWS/blob/main/lambda/handler.py)
```
# 创建 lambda handler.py 并将其 zip
nano handler.py
zip -r icorp-ir-containment.zip
# 部署 Lambda
aws lambda create-function --function-name icorp-IR-containment --runtime python3.12 --role $LAMBDA_ROLE_ARN --handler handler.lambda_handler \
--zip-file fileb://icorp-ir-containment.zip --timeout 30 --memory-size 128 --environment "Variables={DYNAMODB_TABLE=icorp-IR-cases,SNS_TOPIC_ARN=$SNS_TOPIC_ARN}" \
--description "iCorp IR: automated IAM containment on GuardDuty MaliciousIPCaller finding"
# 等待 active 状态
aws lambda wait function-active --function-name icorp-IR-containment
# 确认已使用 env vars 部署
aws lambda get-function-configuration --function-name icorp-IR-containment --query '{Name:FunctionName, State:State, Runtime:Runtime, Env:Environment.Variables}'
```
### 8. 创建 EventBridge 规则并连接到 Lambda
EventBridge 是将 GuardDuty 检测结果连接到 Lambda 函数的中间件。
```
# 编写 event pattern 文件(如果你注意到的话,我将 "aws.guardduty" 替换为了 "icorp.guardduty",我将在下一节 Testing 中解释原因。
cat > ir-event-pattern.json << 'EOF'{
"source": ["icorp.guardduty"],
"detail-type": ["GuardDuty Finding"],
"detail": {
"type": [
"UnauthorizedAccess:IAMUser/MaliciousIPCaller"
]
}
}
EOF
# 创建 Rule
aws events put-rule --name icorp-IR-iam-compromise --event-pattern file://ir-event-pattern.json \--state ENABLED --description "iCorp IR: route Guardduty IAM findings to containment Lambda"
# 保存 rule ARN
export RULE_ARN={Replace_with_Rule_ARN}
# 保存 Lambda ARN
export LAMBDA_ARN={Replace_with_Rule_ARN}
# 将 Lambda 添加为 target
aws events put-targets --rule icorp-IR-iam-compromise --targets "Id=IRContainmentLambda,Arn=$LAMBDA_ARN"
# 授予 EventBridge 调用 Lambda 的权限
aws lambda add-permission --function-name icorp-IR-containment --statement-id EventBridgeIRInvoke --action lambda:InvokeFunction --principal events.amazonaws.com --source-arn $RULE_ARN
# 验证完整设置
aws events describe-rule --name icorp-IR-iam-compromise --query '{Name:Name, State:State}'
aws lambda get-policy --function-name icorp-IR-containment --query 'Policy' --output text | python3 -m json.tool
```
### 9. 通过 EventBridge put-events 进行测试
GuardDuty 的 "create-sample-findings" 总是注入 "GeneratedFindingAccessKeyId" 作为一个硬编码的占位符,您无法用真实的密钥 ID 覆盖它。"put-events" 完全绕过了这一限制,允许您将一个完全定制的、符合 GuardDuty 格式的事件(包含真实的受害者密钥 ID)直接注入到 EventBridge 中。这样 Lambda 就能够通过密钥 ID 对受害者用户执行遏制步骤,这就是为什么在上一步中我将 "aws.guardduty" 替换为了自定义的 "icorp.guardduty"。
```
# 在测试前确认受害 key 仍然为 Active
aws iam list-access-keys --user-name icorp-app-service-account --query 'AccessKeyMetadata[0].[AccessKeyId,Status]'
# 构建经过构造的 GuardDuty 形状 event payload
cat > ir-putevents-payload.json << EOF
[
{
"Source": "icorp.guardduty",
"DetailType": "GuardDuty Finding",
"EventBusName": "default",
"Detail": "{\"type\": \"UnauthorizedAccess:IAMUser/MaliciousIPCaller\", \"severity\": 7, \"accountId\": \"$ACCOUNT_ID\", \"region\": \"$AWS_DEFAULT_REGION\", \"id\": \"ir-test-$(date +%s)\", \"resource\": {\"resourceType\": \"AccessKey\", \"accessKeyDetails\": {\"accessKeyId\": \"$VICTIM_KEY_ID\", \"userName\": \"$PROJECT-app-service-account\", \"userType\": \"IAMUser\", \"principalId\": \"AIDACKCEVSQ6C2EXAMPLE\"}}, \"service\": {\"action\": {\"actionType\": \"AWS_API_CALL\", \"awsApiCallAction\": {\"api\": \"ListBuckets\", \"serviceName\": \"s3.amazonaws.com\", \"remoteIpDetails\": {\"ipAddressV4\": \"203.0.113.42\", \"organization\": {\"asnOrg\": \"Malicious Actor ISP\"}, \"country\": {\"countryName\": \"Unknown\"}, \"city\": {\"cityName\": \"Unknown\"}}}}}}"
}
]
EOF
# 触发 EVENT
aws events put-events --entries file:///tmp/ir-putevents-payload.json
```
The alert email was sent near realtime after triggering the event
### 10. 验证完整遏制
```
# 验证 access key 为 Inactive
aws iam list-access-keys --user-name icorp-app-service-account --query 'AccessKeyMetadata[0].{KeyId:AccessKeyId, Status:Status}'
# 验证已附加 Deny-All inline policy
aws iam list-user-policies --user-name icorp-app-service-account
# 验证 DynamoDB case record
aws iam get-user-policy --user-name icorp-app-service-account --policy-name IREmergencyDenyAll --query 'PolicyDocument'
```
我们也可以通过控制台进行验证。
用户的遏制已经成功且在 60 秒内完成,现在 SOC 分析师/安全工程师可以查看 DynamoDB 案例记录并开始调查该事件。
### 11. 销毁环境
最后一步是销毁实验环境,以避免产生任何经常性费用。
```
#GuardDuty
aws guardduty delete-detector --detector-id $DETECTOR_ID
# Lambda
aws lambda delete-function --function-name icorp-IR-containment
# EventBridge
aws events remove-targets --rule icorp-IR-iam-compromise --ids IRContainmentLambda
aws events delete-rule --name icorp-IR-iam-compromise
# SNS
aws sns unsubscribe --subscription-arn $SUBSCRIPTION_ARN
aws sns delete-topic --topic-arn $SNS_TOPIC_ARN
# DynamoDB
aws dynamodb delete-table --table-name icorp-IR-cases
# IAM 受害用户
aws iam detach-user-policy \
--user-name icorp-app-service-account \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# 删除 inline policy(如果仍然存在)
aws iam delete-user-policy \
--user-name icorp-app-service-account \
--policy-name IREmergencyDenyAll 2>/dev/null || true
aws iam delete-access-key \
--user-name icorp-app-service-account \
--access-key-id $VICTIM_KEY_ID
aws iam delete-user --user-name icorp-app-service-account
# IAM Lambda role
for policy in \
"IAMFullAccess" \
"AmazonDynamoDBFullAccess" \
"AmazonSNSFullAccess" \
"service-role/AWSLambdaBasicExecutionRole"; do
aws iam detach-role-policy \
--role-name icorp-IR-lambda-role \
--policy-arn arn:aws:iam::aws:policy/$policy
done
aws iam delete-role --role-name icorp-IR-lambda-role
```
### 12. Terraform
[TODO] : 稍后添加
## 威胁建模 (STRIDE)
为了构建安全设计结构,我使用了 STRIDE 框架——这是一种在云环境中思考威胁的简单而强大的方法。
| 类别 | 威胁 | 控制 |
|---|---|---|
| **欺骗** | 从恶意 IP 使用被盗的长期访问密钥来冒充 `icorp-app-service-account` | GuardDuty 的 `MaliciousIPCaller` 检测会在发布检测结果后的 60 秒内触发自动密钥撤销 |
| **篡改** | 攻击者在被遏制之前通过 `iam:AttachUserPolicy` 提升权限以获取更广泛的访问权限 | 将 `IREmergencyDenyAll` 内联 Deny-All 策略应用于身份——无论附加了什么权限,所有后续的 API 调用都会被阻止 |
| **否认** | 攻击者禁用 CloudTrail 以抹除 API 活动的证据并掩盖横向移动 | 启用 CloudTrail 日志文件验证 + 在日志存储桶上启用 S3 MFA 删除,防止篡改审计跟踪 |
| **信息泄露** | 攻击者在 GuardDuty 发布检测结果之前枚举 S3 存储桶并外泄客户 PII | 启用了 GuardDuty S3 Protection;约 5-10 分钟的检测窗口限制了数据外泄量 |
| **拒绝服务** | 使用被盗密钥大规模终止 EC2 实例或删除 RDS 快照,导致生产环境停机 | 密钥撤销和 Deny-All 策略可在 Lambda 执行后的几秒钟内阻止所有破坏性的 API 调用 |
| **权限提升** | 调用 `sts:AssumeRole` 从受损的服务账户跳转到权限更高的管理员角色 | Deny-All 策略会在遏制后阻止 `AssumeRole`;5-10 分钟的 GuardDuty 检测窗口是主要的风险面 |
## 技术步骤
### 1. 实验环境设置
对于本实验,我将使用一个免费套餐 AWS 账户,并配置一个用于 CLI 和控制台的 IAM 用户,在区域方面我选择了 eu-west-1(爱尔兰),因为它在摩洛哥的延迟较低。
/!\ 如果您想重现此实验,请务必设置预算警报并在完成后销毁实验环境,以避免产生任何意外费用。
```
# 验证 CLI 已配置
aws sts get-caller-identity
# 为整个会话设置 region 和 account ID
export AWS_DEFAULT_REGION=eu-west-1
export ACCOUNT_ID=123456789
```
### 2. 启用 GuardDuty 并生成示例检测结果
```
# 我已经启用了 GuardDuty,首次使用请运行以下命令
aws guardduty create-detector --enable --finding-publishing-frequency FIFTEEN_MINUTES
# 保存 detector ID
export DETECTOR_ID=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text)
# 确认已启用
aws guardduty get-detector --detector-id $DETECTOR_ID --query '{Status: Status}'
```
GuardDuty 提供了生成安全示例检测结果的功能,这些结果类似于真实攻击,我们可以用它们来测试事件响应流程。
对于这种情况,我选择使用 "UnauthorizedAccess:IAMUser/MaliciousIPCaller" 检测结果来模拟用户访问密钥泄露以及被已知恶意 IP 使用的情况。
```
# 生成示例 findings
aws guardduty create-sample-findings --detector-id $DETECTOR_ID --finding-types "UnauthorizedAccess:IAMUser/MaliciousIPCaller"
# 列出 MaliciousIPCaller finding ID
aws guardduty list-findings --detector-id $DETECTOR_ID --finding-criteria '{"Criterion":{"type":{"Eq":["UnauthorizedAccess:IAMUser/MaliciousIPCaller"]}}}' --query 'FindingIds'
# 保存 finding ID
export FINDING_ID={Replace_with_FINDING_ID}
# 可视化查看 finding JSON 详情
aws guardduty get-findings --detector-id $DETECTOR_ID --finding-ids $FINDING_ID --query 'Findings[0]'
```
我们还可以通过 GUI 控制台查看该检测结果。
### 3. 创建 IAM 受害者用户账户
该受害者用户将是一个有权访问 S3 存储桶的应用程序服务账户。
```
# 创建受害服务账户
aws iam create-user --user-name icorp-app-service-account
# 附加 S3 scoped policy
aws iam attach-user-policy --user-name icorp-app-service-account --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# 创建 access key(这是在遏制期间将被撤销的内容)
aws iam create-access-key --user-name icorp-app-service-account > victim_key.json
cat victim_key.json
# 保存 key ID 以供整个实验使用
export VICTIM_KEY_ID={Replace_by_VICTIM_KEY_ID}
```
### 4. 创建 Lambda 执行角色
为了使 Lambda 函数能够自动化执行 IR 操作,我们需要为其授予 IAM 用户遏制(密钥撤销和附加 Deny-All 策略)、SNS 和 DynamoDB 所需的权限。
```
# Trust policy(此 policy 将允许 lambda service assume 该 role)
cat > lambda-trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
EOF
# 创建 role
aws iam create-role --role-name icorp-IR-lambda-role --assume-role-policy-document file://lambda-trust-policy.json --description "Execution role for iCorp IR containment lambda"
# 保存 role ARN
export LAMBDA_ROLE_ARN={Replace_with_ROLE_ARN}
# 附加 managed policies
for policy in \
"IAMFullAccess" \
"AmazonDynamoDBFullAccess" \
"AmazonSNSFullAccess" \
"service-role/AWSLambdaBasicExecutionRole"; do
aws iam attach-role-policy \
--role-name icorp-IR-lambda-role \
--policy-arn arn:aws:iam::aws:policy/$policy
echo "Attached: $policy"
done
# 确认已附加全部四个
aws iam list-attached-role-policies --role-name icorp-IR-lambda-role --query 'AttachedPolicies[].PolicyName'
```
### 5. 创建 DynamoDB 案例记录表
该 DynamoDB 表将作为案例记录,供 SOC 分析师/安全工程师查看受影响的用户和密钥。
```
# 创建 table
aws dynamodb create-table --table-name icorp-IR-cases \
--attribute-definitions AttributeName=case_id,AttributeType=S \
--key-schema AttributeName=case_id,KeyType=HASH --billing-mode PAY_PER_REQUEST
# 等待 active 状态
aws dynamodb wait table-exists --table-name icorp-IR-cases
# 确认 table 创建
aws dynamodb describe-table --table-name icorp-IR-cases --query 'Table.{Name:TableName, Status:TableStatus}'
```
### 6. 创建 SNS 电子邮件并订阅邮件
为了在触发自动化 IR 时能够接收即时电子邮件,我们将创建一个 SNS 主题并使用我们的电子邮件地址进行订阅。
```
# 创建 topic
aws sns create-topic --name icorp-IR-alets
# 保存 ARN
export SNS_TOPIC_ARN={Replace_with_SNS_TOPIC_ARN}
# Subscribe
aws sns subscribe --topic-arn $SNS_TOPIC_ARN --protocol email --notification-endpoint {email address}
```
We will receive an email from aws to confirm our subscription to the topic.
```
# 确认后 — 验证 subscription 是否已生效
aws sns list-subscriptions-by-topic --topic-arn $SNS_TOPIC_ARN \
--query 'Subscriptions[0].{Protocol:Protocol,Endpoint:Endpoint,Status:SubscriptionArn}'
```
### 7. 打包并部署 Lambda
Lambda 函数将负责在接收到 GuardDuty 的触发后执行遏制流程。
完整函数代码 -> [handler.py](https://github.com/ELMBoukhriss/Automated-IAM-Incident-Response-on-AWS/blob/main/lambda/handler.py)
```
# 创建 lambda handler.py 并将其 zip
nano handler.py
zip -r icorp-ir-containment.zip
# 部署 Lambda
aws lambda create-function --function-name icorp-IR-containment --runtime python3.12 --role $LAMBDA_ROLE_ARN --handler handler.lambda_handler \
--zip-file fileb://icorp-ir-containment.zip --timeout 30 --memory-size 128 --environment "Variables={DYNAMODB_TABLE=icorp-IR-cases,SNS_TOPIC_ARN=$SNS_TOPIC_ARN}" \
--description "iCorp IR: automated IAM containment on GuardDuty MaliciousIPCaller finding"
# 等待 active 状态
aws lambda wait function-active --function-name icorp-IR-containment
# 确认已使用 env vars 部署
aws lambda get-function-configuration --function-name icorp-IR-containment --query '{Name:FunctionName, State:State, Runtime:Runtime, Env:Environment.Variables}'
```
### 8. 创建 EventBridge 规则并连接到 Lambda
EventBridge 是将 GuardDuty 检测结果连接到 Lambda 函数的中间件。
```
# 编写 event pattern 文件(如果你注意到的话,我将 "aws.guardduty" 替换为了 "icorp.guardduty",我将在下一节 Testing 中解释原因。
cat > ir-event-pattern.json << 'EOF'{
"source": ["icorp.guardduty"],
"detail-type": ["GuardDuty Finding"],
"detail": {
"type": [
"UnauthorizedAccess:IAMUser/MaliciousIPCaller"
]
}
}
EOF
# 创建 Rule
aws events put-rule --name icorp-IR-iam-compromise --event-pattern file://ir-event-pattern.json \--state ENABLED --description "iCorp IR: route Guardduty IAM findings to containment Lambda"
# 保存 rule ARN
export RULE_ARN={Replace_with_Rule_ARN}
# 保存 Lambda ARN
export LAMBDA_ARN={Replace_with_Rule_ARN}
# 将 Lambda 添加为 target
aws events put-targets --rule icorp-IR-iam-compromise --targets "Id=IRContainmentLambda,Arn=$LAMBDA_ARN"
# 授予 EventBridge 调用 Lambda 的权限
aws lambda add-permission --function-name icorp-IR-containment --statement-id EventBridgeIRInvoke --action lambda:InvokeFunction --principal events.amazonaws.com --source-arn $RULE_ARN
# 验证完整设置
aws events describe-rule --name icorp-IR-iam-compromise --query '{Name:Name, State:State}'
aws lambda get-policy --function-name icorp-IR-containment --query 'Policy' --output text | python3 -m json.tool
```
### 9. 通过 EventBridge put-events 进行测试
GuardDuty 的 "create-sample-findings" 总是注入 "GeneratedFindingAccessKeyId" 作为一个硬编码的占位符,您无法用真实的密钥 ID 覆盖它。"put-events" 完全绕过了这一限制,允许您将一个完全定制的、符合 GuardDuty 格式的事件(包含真实的受害者密钥 ID)直接注入到 EventBridge 中。这样 Lambda 就能够通过密钥 ID 对受害者用户执行遏制步骤,这就是为什么在上一步中我将 "aws.guardduty" 替换为了自定义的 "icorp.guardduty"。
```
# 在测试前确认受害 key 仍然为 Active
aws iam list-access-keys --user-name icorp-app-service-account --query 'AccessKeyMetadata[0].[AccessKeyId,Status]'
# 构建经过构造的 GuardDuty 形状 event payload
cat > ir-putevents-payload.json << EOF
[
{
"Source": "icorp.guardduty",
"DetailType": "GuardDuty Finding",
"EventBusName": "default",
"Detail": "{\"type\": \"UnauthorizedAccess:IAMUser/MaliciousIPCaller\", \"severity\": 7, \"accountId\": \"$ACCOUNT_ID\", \"region\": \"$AWS_DEFAULT_REGION\", \"id\": \"ir-test-$(date +%s)\", \"resource\": {\"resourceType\": \"AccessKey\", \"accessKeyDetails\": {\"accessKeyId\": \"$VICTIM_KEY_ID\", \"userName\": \"$PROJECT-app-service-account\", \"userType\": \"IAMUser\", \"principalId\": \"AIDACKCEVSQ6C2EXAMPLE\"}}, \"service\": {\"action\": {\"actionType\": \"AWS_API_CALL\", \"awsApiCallAction\": {\"api\": \"ListBuckets\", \"serviceName\": \"s3.amazonaws.com\", \"remoteIpDetails\": {\"ipAddressV4\": \"203.0.113.42\", \"organization\": {\"asnOrg\": \"Malicious Actor ISP\"}, \"country\": {\"countryName\": \"Unknown\"}, \"city\": {\"cityName\": \"Unknown\"}}}}}}"
}
]
EOF
# 触发 EVENT
aws events put-events --entries file:///tmp/ir-putevents-payload.json
```
The alert email was sent near realtime after triggering the event
### 10. 验证完整遏制
```
# 验证 access key 为 Inactive
aws iam list-access-keys --user-name icorp-app-service-account --query 'AccessKeyMetadata[0].{KeyId:AccessKeyId, Status:Status}'
# 验证已附加 Deny-All inline policy
aws iam list-user-policies --user-name icorp-app-service-account
# 验证 DynamoDB case record
aws iam get-user-policy --user-name icorp-app-service-account --policy-name IREmergencyDenyAll --query 'PolicyDocument'
```
我们也可以通过控制台进行验证。
用户的遏制已经成功且在 60 秒内完成,现在 SOC 分析师/安全工程师可以查看 DynamoDB 案例记录并开始调查该事件。
### 11. 销毁环境
最后一步是销毁实验环境,以避免产生任何经常性费用。
```
#GuardDuty
aws guardduty delete-detector --detector-id $DETECTOR_ID
# Lambda
aws lambda delete-function --function-name icorp-IR-containment
# EventBridge
aws events remove-targets --rule icorp-IR-iam-compromise --ids IRContainmentLambda
aws events delete-rule --name icorp-IR-iam-compromise
# SNS
aws sns unsubscribe --subscription-arn $SUBSCRIPTION_ARN
aws sns delete-topic --topic-arn $SNS_TOPIC_ARN
# DynamoDB
aws dynamodb delete-table --table-name icorp-IR-cases
# IAM 受害用户
aws iam detach-user-policy \
--user-name icorp-app-service-account \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# 删除 inline policy(如果仍然存在)
aws iam delete-user-policy \
--user-name icorp-app-service-account \
--policy-name IREmergencyDenyAll 2>/dev/null || true
aws iam delete-access-key \
--user-name icorp-app-service-account \
--access-key-id $VICTIM_KEY_ID
aws iam delete-user --user-name icorp-app-service-account
# IAM Lambda role
for policy in \
"IAMFullAccess" \
"AmazonDynamoDBFullAccess" \
"AmazonSNSFullAccess" \
"service-role/AWSLambdaBasicExecutionRole"; do
aws iam detach-role-policy \
--role-name icorp-IR-lambda-role \
--policy-arn arn:aws:iam::aws:policy/$policy
done
aws iam delete-role --role-name icorp-IR-lambda-role
```
### 12. Terraform
[TODO] : 稍后添加标签:AWS, DPI, IAM访问控制, Serverless, StruQ, 安全编排与自动化响应(SOAR), 自动化事件响应, 逆向工具