jrlyons13/aws-incident-response-lab
GitHub: jrlyons13/aws-incident-response-lab
一个基于 Terraform 的 AWS 安全实验室项目,通过模拟加密劫持攻击来练习和演示 EC2 实例的自动化事件检测、隔离与通知流程。
Stars: 0 | Forks: 0
# AWS EC2 事件响应隔离实验室 (v1.5)
一个适合初学者的 Terraform 项目,用于练习 EC2 事件响应隔离。在 `us-east-1` 中部署一个小型实验室,模拟 cryptojacking/资源耗尽事件,并让 CloudWatch + SNS 自动触发隔离。
## 本实验室的功能
### v1.0(手动隔离)
- 创建一个包含公有子网、Internet gateway、route table 和关联的 VPC
- 启动一个带有正常安全组(允许来自您的 IP 的 SSH,允许来自任何位置的 HTTP)的 Amazon Linux EC2 实例
- 创建一个没有入站或出站规则的隔离安全组
- 提供一个接受 EC2 实例 ID 并对实例进行隔离的隔离 Lambda
### v1.4(自动化 cryptojacking 模拟)
- 添加了一个**模拟器 Lambda**,它使用 **SSM Run Command** 启动临时的 CPU 压力工作负载
- 添加了一个专为实验室测试调优的 **CloudWatch CPU 告警**
- 将告警状态更改发布到 **SNS**
- 配置 SNS 以调用**隔离 Lambda**
- 增强隔离功能以:
1. 为所有挂载的卷创建带标签的 **EBS 快照**
2. 移除 IAM instance profile
3. 附加隔离安全组
4. 发布详细的 SNS 通知
### v1.5(Slack 通知)
- 添加了一个 **Slack 通知 Lambda** 作为第二个 SNS 订阅者
- 从 **AWS Secrets Manager** 读取 Slack **Incoming Webhook URL**
- 发送人类可读的 Slack 消息,用于:
- **CloudWatch 告警** — 标题:`CloudWatch Alarm Triggered` 或 `CloudWatch Alarm Cleared`
- **隔离事件** — 标题:`Isolation Has Occurred` 或 `Isolation Failed`
- **不**修改现有的隔离 Lambda
手动隔离仍然适用于:
```
{
"instance_id": "i-0123456789abcdef0"
}
```
## 架构
**AWS 自动化事件响应实验室 v1.5** — 检测 → 保留证据 → 遏制 → 通知

### SNS 通知扇出
所有事件均发布到一个 SNS topic。多个订阅者接收每条消息:
| 订阅者 | 协议 | 用途 |
|------------|----------|---------|
| 隔离 Lambda | Lambda | 自动化遏制 |
| Slack 通知 Lambda | Lambda | 格式化的 Slack 告警 |
| 电子邮件 | 电子邮件 | 手动订阅(可选) |
### 工作流程摘要
1. 操作员调用模拟器 Lambda
2. 模拟器 Lambda 通过 SSM 在 EC2 实例上运行短暂的 CPU 烧录循环
3. EC2 CPU 利用率上升
4. CloudWatch 告警进入 `ALARM` 状态
5. SNS 将告警发送到 **Slack**、**电子邮件**,并调用**隔离 Lambda**
6. 隔离 Lambda 创建带标签的 EBS 快照,移除 IAM profile,附加隔离 SG,并将结果发布到 SNS
7. SNS 将隔离结果发送到 **Slack** 和**电子邮件**
在完整的试运行期间,您应该会收到**两条 Slack 消息**和**两封电子邮件**:
1. CloudWatch 告警通知
2. 隔离完成通知
## 前置条件
在部署之前,请确保您具备:
1. 已安装 **Terraform** >= 1.5
2. 已安装并配置好 **AWS CLI**
3. 拥有具有创建 VPC、EC2、IAM、Lambda、SNS、CloudWatch、SSM 和 Secrets Manager 资源权限的 **AWS 凭证**
4. 一个 **Slack Incoming Webhook URL**(用于 v1.5 Slack 通知)
### 配置 AWS 凭证
```
aws configure
```
使用 `us-east-1` 作为默认区域。
验证凭证:
```
aws sts get-caller-identity
```
## 项目文件
| 文件 | 用途 |
|------|---------|
| `main.tf` | 网络、EC2、IAM、SNS、CloudWatch 告警和 Lambda 资源 |
| `variables.tf` | 输入变量 |
| `outputs.tf` | 部署后的有用值(包括 `slack_notifier_lambda_name`、`slack_webhook_secret_name`) |
| `lambda_function.py` | 隔离处理程序代码 |
| `simulator_lambda.py` | CPU 压力模拟器处理程序代码 |
| `slack_notifier_lambda.py` | Slack 通知处理程序代码 |
## 部署实验室
在此项目目录中:
```
terraform init
terraform plan
terraform apply
```
apply 完成后:
```
terraform output
```
### 配置 Slack Webhook Secret (v1.5)
Terraform 会创建 Secrets Manager secret,但**您需要手动添加 Webhook URL**,这样它就不会存储在 Terraform 状态或代码中。
在 `terraform apply` 之后,运行:
```
aws secretsmanager put-secret-value `
--secret-id (terraform output -raw slack_webhook_secret_name) `
--secret-string "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
```
或者在 AWS 控制台中:
1. 打开 **Secrets Manager**
2. 选择在 `terraform output slack_webhook_secret_name` 中命名的 secret
3. 选择 **Retrieve secret value** → **Edit**
4. 粘贴您的 Slack Incoming Webhook URL
5. 保存
在设置此 secret 值之前,Slack 通知器 Lambda 将无法工作。
secret 值必须**仅为 Webhook URL** — 没有引号、没有 JSON 包装、没有多余的空格。
### Slack 消息示例
在完整的事件模拟期间,Slack 通知器会发送**纯文本**消息(禁用 markdown 是为了确保可靠地显示 CloudWatch 告警详细信息)。
**消息 1 — CloudWatch 告警**
```
CloudWatch Alarm Triggered
Alarm: ir-isolation-lab-cpu-high
State: ALARM
Instance: i-0123456789abcdef0
Metric: CPUUtilization GreaterThanThreshold 90
Reason: Threshold Crossed: 1 datapoint was greater than the threshold (90.0).
Time: 2026-07-01T06:00:00.000+0000
```
**消息 2 — 隔离完成**
```
Isolation Has Occurred
Incident Type: SimulatedCryptoJacking
Instance ID: i-0123456789abcdef0
Snapshots: snap-0abc123def4567890
IAM Profile: disassociated_iam_instance_profile
Quarantine SG: sg-0abc123def4567890
Status: isolated
Time (UTC): 2026-07-01T06:00:03.950737+00:00
```
如果隔离失败,标题将更改为 **Isolation Failed** 并包含错误行。
如果告警解除,标题将为 **CloudWatch Alarm Cleared**。
Slack 消息将发送到**您创建 Incoming Webhook 时配置的频道** — 而不是发送到私信 (DM)。
### 测试 Slack 通知
通过 SNS 发送通用测试消息:
```
aws sns publish `
--topic-arn (terraform output -raw sns_topic_arn) `
--subject "IR Lab Slack Test" `
--message "Test notification from the incident response lab."
```
您应该会看到一条主题为 `IR Lab Slack Test` 的通用 Slack 消息。
在完整的事件模拟期间,您应该会收到**两条 Slack 消息**:
1. 当 CPU 告警进入 `ALARM` 状态时的 **CloudWatch Alarm Triggered**
2. 隔离 Lambda 完成后的 **Isolation Has Occurred**
如果 Slack 消息未出现,请检查 `terraform output -raw slack_notifier_lambda_name` 的 CloudWatch Logs。日志包含检测到的消息类型(`alarm`、`isolation` 或 `generic`)。
Terraform 还会在该目录中创建一个名为 `ir-isolation-lab-key.pem` 的私钥文件。
### 订阅 SNS 通知
电子邮件订阅需要手动确认:
```
aws sns subscribe `
--topic-arn (terraform output -raw sns_topic_arn) `
--protocol email `
--notification-endpoint you@example.com
```
检查您的收件箱并确认订阅。
## v1.5 测试计划
1. 运行 `terraform apply`
2. 将 Slack Webhook URL 添加到 Secrets Manager
3. 确认 EC2 以应用 SG 和 IAM instance profile 启动
4. 如果是手动配置的,请确认 SNS 电子邮件订阅
5. 发送测试 SNS 消息并确认其出现在 Slack 中
6. 调用模拟器 Lambda
7. 观察 CloudWatch CPU 指标上升
8. 确认 CloudWatch 告警进入 `ALARM`
9. 确认 **Slack 消息 1:** `CloudWatch Alarm Triggered`
10. 确认 SNS 触发隔离 Lambda
11. 确认存在带有事件标签的 EBS 快照
12. 确认 IAM instance profile 已被移除
13. 确认已附加隔离 SG
14. 确认 HTTP 访问失败
15. 确认 **Slack 消息 2:** `Isolation Has Occurred`
16. 确认 SNS 电子邮件包含告警和隔离详细信息
17. 运行 `terraform destroy`
18. 验证所有实验室资源均已被移除
## 在事件发生前验证实例
### 测试 HTTP
```
curl http://
```
您应该会看到包含 `IR Isolation Lab` 的 HTML。
### 确认 SSM 在线
apply 后等待几分钟,然后检查:
```
aws ssm describe-instance-information `
--filters "Key=InstanceIds,Values=$(terraform output -raw ec2_instance_id)"
```
在调用模拟器之前,实例应显示为 `Online`。
## 调用模拟器 Lambda
### AWS 控制台
1. 打开 **Lambda**
2. 选择 `terraform output -raw simulator_lambda_name`
3. 创建一个测试事件,如 `{}` 或:
```
{
"instance_id": "i-0123456789abcdef0"
}
```
4. 运行测试
### AWS CLI
```
$functionName = terraform output -raw simulator_lambda_name
aws lambda invoke `
--function-name $functionName `
--payload "{}" `
simulator-out.json
Get-Content simulator-out.json
```
模拟器默认启动一个安全且持续约 6 分钟的 CPU 压力循环。
## 观察自动化响应
### CloudWatch CPU 指标
1. 打开 **CloudWatch** -> **Metrics** -> **EC2** -> **Per-Instance Metrics**
2. 选择实验室实例的 `CPUUtilization`
3. 确认模拟器运行后利用率上升
### CloudWatch 告警
打开在以下位置命名的告警:
```
terraform output cloudwatch_alarm_name
```
在持续的高 CPU 负载后,它应进入 `ALARM` 状态。
### 隔离 Lambda 日志
打开以下内容的 CloudWatch Logs:
```
terraform output isolation_lambda_name
```
确认快照创建、IAM profile 移除以及隔离 SG 附加。
## 手动隔离路径(仍受支持)
您仍然可以手动调用隔离:
```
{
"instance_id": "i-0123456789abcdef0"
}
```
隔离 Lambda 还接受 SNS 告警 payload,并在需要时回退到 `TARGET_INSTANCE_ID` 环境变量。
### AWS CLI
```
$instanceId = terraform output -raw ec2_instance_id
$functionName = terraform output -raw isolation_lambda_name
aws lambda invoke `
--function-name $functionName `
--payload "{\"instance_id\":\"$instanceId\"}" `
out.json
Get-Content out.json
```
## 验证隔离是否生效
在自动化或手动隔离之后:
1. **HTTP 应当失败**
curl http://
2. **EC2 控制台检查**
- 仅附加了隔离安全组
- IAM instance profile 已被移除
3. **EBS 快照**
- 打开 **EC2** -> **Snapshots**
- 查找带有以下标签的快照:
- `Incident=true`
- `IncidentType=SimulatedCryptoJacking`
- `CreatedBy=IncidentResponseLab`
4. **SNS 通知**
- **电子邮件**应包含事件类型、实例 ID、快照 ID、IAM 结果、隔离 SG ID、时间戳和最终状态
- **Slack** 应显示 `CloudWatch Alarm Triggered`,随后是 `Isolation Has Occurred`
## 恢复正常访问(可选)
要在不销毁所有内容的情况下再次运行实验室:
- 运行 `terraform apply` 以恢复应用 SG 和 IAM instance profile,或者
- 在 EC2 控制台中手动重新附加它们
如果实例已被隔离,您可能需要在 SSM 再次工作之前恢复网络连接。
## 清理
当您完成练习后:
```
terraform destroy
```
出现提示时键入 `yes`。
如果保留有本地生成的文件,您也可以将其删除:
- `ir-isolation-lab-key.pem`
- `lambda_function.zip`
- `simulator_lambda.zip`
- `slack_notifier_lambda.zip`
## 成本说明
如果保持运行,主要成本是 EC2 实例(`t3.micro`,在免费套餐之外约为 8-10 美元/月)。在隔离期间创建的 EBS 快照在删除之前也会产生少量存储成本。完成后请销毁资源。
## 实验室限制
- 隔离用于遏制练习,而非完整的取证保留
- Lambda 会替换目标实例上的所有安全组
- SSH 访问取决于在 apply 时检测到您当前的公网 IP
- SNS 电子邮件订阅需要手动确认
- 模拟器仅使用临时的 CPU 压力;它不是真正的恶意软件
- 由于 CloudWatch 告警时机的原因,自动化隔离可能在模拟器启动后需要 1-2 分钟
- Slack 消息仅发布到 Webhook 频道;请确认您正在查看正确的频道
## 故障排除
| 问题 | 修复 |
|-------|-----|
| `terraform plan` 因凭证错误失败 | 运行 `aws configure` 并使用 `aws sts get-caller-identity` 验证 |
| 模拟器因 SSM 错误失败 | 等待 SSM agent 上线;如果缺失,使用 `dnf install -y amazon-ssm-agent` 安装 |
| 告警从未进入 `ALARM` | 确认模拟器已运行;检查 CPU 指标;在变量或告警控制台中降低阈值 |
| 隔离 Lambda 权限错误 | 重新运行 `terraform apply`;检查 CloudWatch Logs |
| 未收到 SNS 电子邮件 | 在您的收件箱中确认订阅 |
| 隔离后 HTTP 仍然有效 | 刷新 EC2 控制台;确认已附加隔离 SG |
| Slack 测试有效但缺少告警/隔离消息 | 打开 Webhook 频道;搜索 `CloudWatch Alarm Triggered`;检查 Slack Lambda 日 |
| Slack Lambda 报告 secret 错误 | 确认 secret 值是纯 Webhook URL,没有引号或 JSON 包装 |
| 完全没有 Slack 消息 | 确认已设置 secret 值;运行 SNS 测试发布;检查 `/aws/lambda/` 日志 |
标签:AWS, DPI, ECS, Terraform, 安全实验环境, 库, 应急响应, 自动化运维, 逆向工具