dbnz-io/opencdr
GitHub: dbnz-io/opencdr
OpenCDR 是一款开源的 AWS 云检测与响应平台,通过事件驱动架构实时接收 CloudTrail 和 GuardDuty 事件,运行可配置的检测与关联规则,并将安全告警分发给多种通知渠道,同时支持自动化事件响应。
Stars: 0 | Forks: 0
# OpenCDR
[](https://github.com/dbnz-io/opencdr/actions/workflows/ci.yml)

[](https://opensource.org/licenses/MPL-2.0)
针对 AWS 的开源事件驱动云检测与响应。OpenCDR 接收 CloudTrail 和 GuardDuty 事件,根据可配置的检测规则对其进行评估,关联相关活动,并将警报发送到 Slack、Discord、电子邮件、AWS Security Hub、Jira 或任何 HTTPS webhook——并支持可选的自动化事件响应。
📚 本 README 是快速入门概述和复制粘贴命令参考。如需深度参考文档——包括架构、安全模型以及“查找所需内容”的索引——请参阅 **[`docs/`](docs/README.md)**。
## 目录
- [工作原理](#how-it-works)
- [架构](#architecture)
- [完整设置](#complete-setup)
- [前置条件](#prerequisites)
- [必须启用 CloudTrail](#cloudtrail-must-be-enabled)
- [组织级部署](#organization-level-deployment)
- [安装依赖项](#install-dependencies)
- [部署](#deployment)
- [CloudWatch 警报](#cloudwatch-alarms)
- [可观测性](#observability)
- [成本追踪](#cost-tracking)
- [多区域覆盖](#multi-region-coverage)
- [环境变量](#environment-variables)
- [CI/CD 部署(OIDC,无长期密钥)](#cicd-deployment-oidc-no-long-lived-keys)
- [OpenCDR CLI](#opencdr-cli)
- [快速开始](#quick-start)
- [命令](#commands)
- [开箱即用 — 检测规则](#batteries-included--detection-rules)
- [信号规则](#signal-rules)
- [关联规则](#correlation-rules)
- [本地测试规则](#testing-rules-locally)
- [集成测试(已部署的 stack)](#integration-testing-deployed-stack)
- [编写检测规则](#writing-detection-rules)
- [信号规则](#signal-rule)
- [关联规则](#correlation-rule)
- [自动化事件响应](#automated-incident-response)
- [responder 如何进行授权](#how-the-responder-authorizes-itself)
- [通知](#notifications)
- [Slack 和 Discord](#slack-and-discord)
- [通过 SNS 发送电子邮件通知](#email-notifications-via-sns)
- [AWS Security Hub](#aws-security-hub)
- [Jira](#jira)
- [自定义 webhook](#custom-webhook)
- [通过 SNS 进行自定义集成](#custom-integrations-via-sns)
- [SIEM 集成](#siem-integrations)
- [API](#api)
- [项目结构](#project-structure)
- [运行测试](#running-tests)
- [许可证](#license)
## 工作原理
```
EventBridge (CloudTrail / GuardDuty)
└─► processor — normalizes events, runs detection rules → writes signals
└─► alerter — runs correlation rules → writes alerts + outbox
└─► publisher — drains outbox → SQS
├─► notifier — sends alerts to Slack / Discord / Email / Security Hub / Jira / custom webhook
└─► responder — executes automated IR actions (disable user, isolate EC2, block S3…)
```
REST API 允许您在运行时查询信号、日志和规则,并管理配置。
## 架构
| 组件 | 触发器 | 职责 |
|---|---|---|
| **processor** | EventBridge rule | 解析事件 → 规范化 → 运行信号检测 → 存储信号 |
| **alerter** | DynamoDB stream (signals) | 运行关联规则 → 存储警报 → 写入发件箱 |
| **publisher** | DynamoDB stream (outbox) | 认领发件箱记录 → 发布到 SQS 队列 |
| **notifier** | SQS (notifications) | 格式化并将警报发送到 Slack / Discord / 电子邮件 (SNS) / Security Hub / Jira / 自定义 webhook |
| **responder** | SQS (responses) | 通过 IAM / EC2 / S3 执行事件响应操作 |
| **api** | API Gateway (HTTP) | 查询信号、日志、规则;管理设置 |
所有状态都保存在 DynamoDB 中(按需计费)。发件箱模式保证了从 alerter 到 SQS 的至少一次交付,且无需直接耦合。
## 完整设置
以下部分深入介绍了每个步骤。依次进行,从一个干净的 AWS 账户到一个完全正常运行的部署:
1. **前置条件** — Node.js、Serverless Framework、Python 3.12、AWS 凭证、已启用 CloudTrail。
2. **部署 stack** — `serverless deploy --stage dev`。
3. **加载内置检测规则** — `./scripts/load_rules.sh --stage dev`。
4. **配置通知渠道** — `python3 scripts/opencdr.py setup`(交互式;也会执行第 3 步)。
5. **设置警报交付** — 关于运营健康状况,而非安全警报;`alarmEmail` 参数或 Slack SSM 参数。
6. **启用成本追踪** — 两个手动的 AWS 控制台步骤,然后运行 `./scripts/cost_report.sh`。
7. **接入其他区域** — 仅当您的账户在多个区域运行时;否则在部署区域之外将处于盲目状态。运行 `./scripts/setup_region_forwarding.sh`。
8. **接入其他账户** — 仅当您需要跨账户事件响应时;单账户无需此操作。在另一个账户中创建同名 IR 角色,然后注册它:`curl -X POST "$OPENCDR_API_URL/ir-roles" -H "x-api-key: $OPENCDR_API_KEY" -d '{"aws_account_id": "", "role_arn": ""}'` — 完整演练(信任策略、终止开关)请见 [`docs/ir-role.md`](docs/ir-role.md#multi-account-onboard-each-additional-account)。
9. **设置 CI/CD** — 可选,建议在一次性评估之外使用。在 [`ci-bootstrap/`](ci-bootstrap/README.md) 中进行一次性引导,然后每次推送到 `main` 分支都会自动部署。
10. **端到端验证** — `./scripts/test_deployed.sh`。
对于单账户、单区域评估,步骤 7–9 是可选且可跳过的。完整细节、确切命令以及每个步骤的实际作用:**[`docs/setup.md`](docs/setup.md)**。
## 前置条件
- [Node.js](https://nodejs.org/) >= 18(CI 本身运行 Node 20)
- [Serverless Framework](https://www.serverless.com/) v3
- Python 3.12(与 `serverless.yml` 中的 `provider.runtime` 匹配)
- 已配置 AWS 凭证(`aws configure` 或环境变量)
- `jq`(用于加载/测试脚本)
### 必须启用 CloudTrail
OpenCDR 通过 EventBridge 接收事件。只有当您的账户和区域中激活了 CloudTrail 时,CloudTrail 管理事件才会被交付到 EventBridge。
在部署前启用它:
```
# 创建 trail(一次性设置)
aws cloudtrail create-trail \
--name opencdr-trail \
--s3-bucket-name \
--is-multi-region-trail
# 开始日志记录
aws cloudtrail start-logging --name opencdr-trail
```
或者在 AWS 控制台的 **CloudTrail → Trails → Create trail** 下启用。必须启用管理事件(读取 + 写入)——数据事件是可选的。
### 组织级部署
对于多账户 AWS Organizations 设置,您可以将每个成员账户的所有 CloudTrail 和 GuardDuty 事件路由到一个单一的中央 EventBridge 总线,并在一个专门的安全账户中部署一次 OpenCDR。
```
Member Account A ─┐
Member Account B ─┼─► EventBridge cross-account rules ─► Central Security Account
Member Account C ─┘ EventBridge default bus
│
OpenCDR processor Lambda
```
**设置步骤:**
1. 在管理账户中**启用组织追踪**——这会创建一个自动覆盖所有成员账户的 CloudTrail:
aws cloudtrail create-trail \
--name org-trail \
--s3-bucket-name \
--is-organization-trail \
--is-multi-region-trail
aws cloudtrail start-logging --name org-trail
2. **允许成员账户将事件发送到中央总线。** 在中央安全账户中,向默认的 EventBridge 总线添加资源策略:
aws events put-permission \
--action events:PutEvents \
--principal "*" \
--statement-id AllowOrgAccounts \
--condition '{"Type":"StringEquals","Key":"aws:PrincipalOrgID","Value":"o-XXXXXXXXXX"}'
3. **在每个成员账户中创建转发规则**(或通过 CloudFormation StackSets 在整个组织中进行部署),以匹配 CloudTrail 和 GuardDuty 事件并将它们转发到中央总线:
aws events put-rule \
--name forward-to-central-opencdr \
--event-pattern '{"source":["aws.cloudtrail","aws.guardduty"]}' \
--state ENABLED
aws events put-targets \
--rule forward-to-central-opencdr \
--targets '[{
"Id": "CentralBus",
"Arn": "arn:aws:events:::event-bus/default",
"RoleArn": "arn:aws:iam:::role/EventBridgeForwardRole"
}]'
4. 在中央安全账户中**正常部署 OpenCDR**。processor Lambda 将通过中央总线接收来自所有成员账户的事件,并且信号将包含来源 `aws_account_id` 以便进行分类。
### 安装依赖项
```
npm install -g serverless
npm install # installs serverless-python-requirements and serverless-iam-roles-per-function
```
## 部署
```
# 部署到 dev(默认)
serverless deploy
# 部署到特定 stage / region
serverless deploy --stage prod --region us-west-2
# 使用电子邮件订阅部署
serverless deploy \
--param="alarmEmail=ops@example.com" \
--param="alertEmail=security@example.com"
```
`alarmEmail` 订阅基础设施警报(Lambda 错误、DLQ 深度)。`alertEmail` 订阅安全检测警报。两者都是可选的——您可以稍后通过 SNS topic ARN 进行订阅。
这将创建:
- 7 个 Lambda 函数(每个都有自己最小权限的 IAM 角色):processor、alerter、publisher、notifier、responder、api、alarmNotifier
- 7 个 DynamoDB 表(signals、alerts、outbox、logs、detection-rules、settings、ir-account-roles)
- 2 个带有死信队列的 SQS 队列(notifications、responses)
- 1 个流失败队列(捕获来自 DynamoDB streams 的有害记录)
- 带有 API key 身份验证的 API Gateway(每月 1 万次请求,100 RPS)
- 2 个 SNS topic:基础设施警报(`opencdr--alarms`)和安全警报(`opencdr--alerts`)
- 11 个 CloudWatch 警报 + 1 个控制面板(Lambda 错误、DLQ 深度、流迭代器年龄——请参阅 [CloudWatch 警报](#cloudwatch-alarms))
- 1 个月度成本预算,通过与上述警报相同的 Slack pipeline 发出警报(请参阅 [成本追踪](#cost-tracking))
- X-Ray 追踪和用于检测健康状况的自定义 CloudWatch 指标(请参阅 [可观测性](#observability))
- 跨区域事件转发的接收端(一个 IAM 角色 + 总线策略)——发送端需要针对每个额外区域执行单独的可选步骤(请参阅 [多区域覆盖](#multi-region-coverage))
### CloudWatch 警报
OpenCDR 开箱即用提供了 11 个警报:
| 警报 | 指标 | 阈值 |
|---|---|---|
| `processor`/`alerter`/`publisher`/`notifier`/`responder`/`api` 错误(各一个警报——特意排除了 `alarmNotifier` 本身,以避免出现警报通知循环) | `AWS/Lambda Errors` | > 0 |
| 通知 DLQ 深度 | `AWS/SQS ApproximateNumberOfMessagesVisible` | > 0 |
| 响应 DLQ 深度 | `AWS/SQS ApproximateNumberOfMessagesVisible` | > 0 |
| 流失败队列深度 | `AWS/SQS ApproximateNumberOfMessagesVisible` | > 0 |
| Alerter 流迭代器年龄 | `AWS/Lambda IteratorAge` | > 5 分钟 |
| Publisher 流迭代器年龄 | `AWS/Lambda IteratorAge` | > 5 分钟 |
所有警报都会交付到 `opencdr--alarms` SNS topic,`alarmNotifier` 会将其转发到 Slack(🔴 ALARM / ✅ OK、名称、描述、原因)——与下方 [成本预算](#cost-tracking) 重用的交付路径相同。在部署时传入 `--param="alarmEmail=you@example.com"`,即可将电子邮件地址直接订阅到该 topic。AWS 将发送一封确认电子邮件——只需点击一次链接即可激活。
一个 CloudWatch Dashboard(`OpsDashboard`,部署后会在 stack 的输出中提供链接)将所有 7 个函数的 Lambda 健康/持续时间/调用情况、所有三个队列深度以及下方的自定义检测健康指标结合在一起。
### 可观测性
X-Ray 追踪、四个自定义检测健康指标和 `OpsDashboard` CloudWatch 控制面板都是自动配置的,无需任何配置。完整细节——包括 X-Ray 服务映射的节点覆盖范围如何工作——请见 [`docs/observability.md`](docs/observability.md)。
### 成本追踪
此 stack 创建的每个资源都带有 `Project=opencdr` / `Stage=` 标签,并且每个月度 `AWS::Budgets::Budget`(`serverless.yml` 中的 `CostBudget`)会在达到 80% 实际、100 实际和 100% 预测支出时,通过与上述 CloudWatch 警报相同的 Slack pipeline 发出警报。在部署时传入 `--param="monthlyBudgetUsd="` 来设置阈值(默认为 `50`)。
在其中的任何一项报告真实数据之前,需要在 AWS 账户中进行两个一次性步骤——这两者都是 CloudFormation 无法为您完成的:
1. 启用一次 Cost Explorer(账单控制台 → Cost Explorer)。
2. 激活 `Project`/`Stage` 标签作为成本分配标签(账单控制台 → 成本分配标签)——最多需要 24 小时才会开始显示,并且仅涵盖激活后的支出,而非追溯涵盖。
完成这两步后,使用以下命令获取阶段的支出明细:
```
./scripts/cost_report.sh --stage dev
./scripts/cost_report.sh --stage prod --granularity MONTHLY --start 2026-07-01 --end 2026-08-01
```
### 多区域覆盖
**全新的部署仅覆盖其所在区域。** CloudTrail 将事件交付到发生 API 调用的任何区域的默认 EventBridge 总线——即使对于多区域追踪也是如此——并且 GuardDuty 检测器是按区域划分的。如果您的账户在多个区域中运行,那么在您明确接入每个额外区域之前,部署区域之外的活动将被默默忽略:
```
./scripts/setup_region_forwarding.sh --stage dev --region eu-west-1 # one region
./scripts/setup_region_forwarding.sh --stage dev --regions eu-west-1,ap-southeast-1 # several
./scripts/setup_region_forwarding.sh --stage dev --region eu-west-1 --remove # tear one down
```
这会独立地在每个区域上执行,并在遇到失败时继续运行而不是中止整个过程——受限于批准区域列表(AWS Control Tower、SCP)的账户会在被阻止的区域中合理地拒绝此操作,这是预期的,而不是 bug。完整细节(包括确切受影响的信号规则)请见 [`docs/region-forwarding.md`](docs/region-forwarding.md)。
### 环境变量
| 变量 | 默认值 | 描述 |
|---|---|---|
| `OPENCDR_IR_ROLE_ARN` | 自动创建的本账户角色 | 当检测到的 AWS 账户在 `irAccountRolesTable` 中没有记录时,responder 假定的备用 IAM 角色——请参阅 [docs/ir-role.md](docs/ir-role.md)。由 `serverless.yml` 自动配置;仅设置此项以覆盖它。 |
| `DREDGE_DRY_RUN` | `false` | 设置为 `true` 以模拟 IR 操作而不实际执行它们 |
| `RESPONDER_RATE_LIMIT_WINDOW_MINUTES` | `5` | responder 操作速率断路器的滚动窗口 |
| `RESPONDER_RATE_LIMIT_MAX_ACTIONS` | `20` | 断路器跳闸前每个窗口的最大破坏性操作数 |
| `RESPONDER_ROLE_CACHE_TTL_SECONDS` | `60` | 重新检查 `irAccountRolesTable` 之前,已解析的账户→角色查找的缓存时间 |
| `CORRELATION_QUERY_LIMIT` | `300` | 每次关联评估查询的最大信号数 |
### CI/CD 部署(OIDC,无长期密钥)
`.github/workflows/ci.yml` 会在每次推送到 `main` 时自动部署到 `dev` 阶段,
使用通过 GitHub 的 OIDC 提供商联合的短期凭证,
而不是长期的 AWS 访问密钥。为您自己的账户(或客户的账户)进行的一次性设置在
[`ci-bootstrap/`](ci-bootstrap/README.md)
中——对于希望使用此方法而非上述手动 `serverless deploy` 流程的采用者,同一模板也可用作参考工作流。请参阅
[`docs/stack-protection.md`](docs/stack-protection.md) 以了解随附的终止保护和漂移检测。
每次 CI 部署还会将阶段的真实 API key 作为 SecureString
写入 SSM Parameter Store
(`/opencdr-/api-key`)——使用以下命令检索它:
```
aws ssm get-parameter --name /opencdr-dev/api-key --with-decryption \
--query Parameter.Value --output text
```
而不是手动将其拉取到本地文件中——这正是之前导致真实密钥被提交到此仓库的原因(请参阅 git 历史记录中的 `.opencdr.json`,现已被移除)。
## OpenCDR CLI
`scripts/opencdr.py` 是一个用于与已部署的 OpenCDR stack 交互的管理 CLI。它包装了 REST API 并提供了一个交互式设置向导。
### 快速开始
```
# 交互式设置向导 — 配置 API 连接,加载 rules,并设置通知
python3 scripts/opencdr.py setup
# 或手动配置
python3 scripts/opencdr.py config set --url https://.execute-api..amazonaws.com/dev --key
```
您的 API URL 和密钥会在 `serverless deploy` 的 endpoints 和 API Keys 部分中打印出来。
### 命令
```
# 检查 API 健康状态
python3 scripts/opencdr.py status
# Rules
python3 scripts/opencdr.py rules load # load all rules from support_files/
python3 scripts/opencdr.py rules list --kind signal
python3 scripts/opencdr.py rules get --kind signal
python3 scripts/opencdr.py rules delete --kind signal
# 通知设置
python3 scripts/opencdr.py settings get
python3 scripts/opencdr.py settings set --slack-webhook https://hooks.slack.com/...
python3 scripts/opencdr.py settings set --discord-webhook https://discord.com/api/webhooks/...
python3 scripts/opencdr.py settings set --email-topic-arn arn:aws:sns:::opencdr-dev-alerts
python3 scripts/opencdr.py settings set --enable-securityhub
python3 scripts/opencdr.py settings set \
--jira-url https://yourco.atlassian.net \
--jira-project SEC \
--jira-email soc@yourco.com \
--jira-token
python3 scripts/opencdr.py settings set \
--webhook-url https://events.pagerduty.com/v2/enqueue \
--webhook-name pagerduty
python3 scripts/opencdr.py settings set \
--webhook-url https://api.opsgenie.com/v2/alerts \
--webhook-name opsgenie \
--webhook-header "Authorization=GenieKey "
python3 scripts/opencdr.py settings set --file support_files/settings/settings.json # full payload
# 查询 signals 和日志
python3 scripts/opencdr.py signals list --severity HIGH
python3 scripts/opencdr.py logs list --service OCDR-PROCESSOR
# 运行测试
python3 scripts/opencdr.py test local
python3 scripts/opencdr.py test deployed --stage dev
```
## 开箱即用 — 检测规则
OpenCDR 内置了 19 条信号规则和 4 条关联规则,涵盖了最常见的 AWS 攻击模式。使用以下命令加载它们:
```
# 将所有 rules 加载到 DynamoDB(dev stage)
./scripts/load_rules.sh
# 加载到特定 stage / region
./scripts/load_rules.sh --stage prod --region us-west-2
# 预览而不写入
./scripts/load_rules.sh --dry-run
```
### 信号规则
| 规则 | 严重程度 | 战术 |
|---|---|---|
| `001` 不使用 MFA 的控制台登录 | HIGH | 初始访问 |
| `002` Root 账户用于任何操作 | CRITICAL | 权限提升 |
| `003` Root 账户控制台登录 | CRITICAL | 初始访问 |
| `004` 创建 Root 访问密钥 | CRITICAL | 持久性 |
| `005` 创建 IAM 用户 | MEDIUM | 持久性 |
| `006` 创建访问密钥 | MEDIUM | 持久性 |
| `007` 创建 IAM 角色 | MEDIUM | 持久性 |
| `008` 创建或更新 Lambda 函数 | MEDIUM | 持久性 |
| `009` 附加 AdministratorAccess 策略 | CRITICAL | 权限提升 |
| `010` 创建通配符内联策略 | HIGH | 权限提升 |
| `011` 添加安全组入口规则 | MEDIUM | 防御规避 |
| `012` CloudTrail 停止、删除或更新 | CRITICAL | 防御规避 |
| `013` GuardDuty 检测器被删除或禁用 | CRITICAL | 防御规避 |
| `014` AWS Config 记录器被停止或删除 | HIGH | 防御规避 |
| `015` 禁用 Security Hub | HIGH | 防御规避 |
| `016` 访问 Secrets Manager 密钥 | HIGH | 凭证访问 |
| `017` 访问 SSM 参数 | MEDIUM | 凭证访问 |
| `018` S3 存储桶被公开 | HIGH | 数据泄露 |
| `019` RDS 快照被公开 | HIGH | 数据泄露 |
### 关联规则
| 规则 | 严重程度 | 描述 |
|---|---|---|
| `020` 控制台登录暴力破解 | CRITICAL | 15 分钟内同一用户进行 5 次以上无 MFA 登录 |
| `021` IAM 活动突发 | CRITICAL | 5 分钟内来自同一执行者的 5 个以上 IAM 信号 |
| `022` 防御规避激增 | CRITICAL | 10 分钟内禁用 2 个或更多日志/检测服务 |
| `023` 凭证收集 | CRITICAL | 5 分钟内来自同一执行者的 3 次或更多密钥/SSM 访问 |
## 本地测试规则
无需部署到 AWS 即可根据样本事件测试所有规则:
```
python3 scripts/test_rules_local.py
# 按 event 筛选
python3 scripts/test_rules_local.py --event 012
# 按 rule 筛选
python3 scripts/test_rules_local.py --rule cloudtrail
```
所有 19 条信号规则的样本事件位于 `support_files/test_events/` 中。
### 集成测试(已部署的 stack)
```
# 针对已部署的 processor Lambda 测试所有 events
./scripts/test_deployed.sh
# 测试单个 event
./scripts/test_deployed.sh --event 009
# 针对 prod 测试
./scripts/test_deployed.sh --stage prod --region us-west-2
```
## 编写检测规则
规则存储在 DynamoDB 中。您可以将它们编写为 JSON 并使用 `load_rules.sh` 加载,或者在运行时通过 API 管理它们。
### 信号规则
匹配单个规范化事件。当所有条件都通过时,会将信号写入信号表。
```
{
"rule_id": "001_console_login_no_mfa",
"rule_kind": "signal",
"description": "Console login without MFA.",
"enabled": true,
"severity": "HIGH",
"notify": true,
"response_module": "",
"playbook": "Verify user and source IP. If suspicious, revoke sessions and enforce MFA.",
"conditions": [
{ "field": "activity_name", "op": "equals", "value": "ConsoleLogin" },
{ "field": "raw_event.detail.additionalEventData.MFAUsed", "op": "equals", "value": "No" }
]
}
```
**支持的运算符:** `exists`、`not_exists`、`equals`、`not_equals`、`in`、`not_in`、`contains`、`not_contains`、`prefix`、`suffix`、`matches`(正则表达式)、`wildcard`(匹配任何事件)
**条件中可用的规范化字段:**
| 字段 | 描述 |
|---|---|
| `activity_name` | CloudTrail 事件名称(例如 `ConsoleLogin`、`CreateUser`) |
| `category` | 从服务派生的事件类别(例如 `iam`、`s3`、`ec2`、`authn`) |
| `class_name` | 事件类(`api_activity`、`authentication`、`security_finding`) |
| `source` | 事件来源(`cloudtrail`、`guardduty`) |
| `severity` | 规范化的严重程度(`CRITICAL`、`HIGH`、`MEDIUM`、`LOW`、`UNKNOWN`) |
| `actor.type` | 身份类型(`Root`、`IAMUser`、`AssumedRole`、`FederatedUser`) |
| `actor.user_name` | IAM 主体名称 |
| `actor.account_id` | 执行者的 AWS 账户 ID |
| `actor.arn` | 执行者的完整 ARN |
| `network.source_ip` | 源 IP 地址 |
| `network.user_agent` | User agent 字符串 |
| `api.service` | AWS 服务端点(例如 `iam.amazonaws.com`) |
| `api.operation` | API 操作名称 |
| `api.error_code` | 如果调用失败,则为 CloudTrail 错误代码 |
| `raw_event.detail.*` | 原始 EventBridge 事件 payload 中的任何字段 |
### 关联规则
按字段对信号进行分组,在时间窗口内对其进行计数,并在达到阈值时触发警报。`signal_conditions` 可选择性地过滤哪些信号会计入阈值。
```
{
"rule_id": "020_correlation_console_login_bruteforce",
"rule_kind": "correlation",
"description": "Multiple MFA-less logins from the same user.",
"enabled": true,
"severity": "CRITICAL",
"group_by": "actor.user_name",
"time_window_seconds": 900,
"threshold": 5,
"signal_conditions": [
{ "field": "rule_id", "op": "equals", "value": "001_console_login_no_mfa" }
],
"notify": true,
"response_module": "disable_user",
"playbook": "Disable the user and investigate source IPs."
}
```
## 自动化事件响应
在任何规则上设置 `response_module`,以便在触发时执行自动操作。
| 模块 | 操作 |
|---|---|
| `disable_user` | 禁用执行者的所有 IAM 访问密钥 |
| `delete_user` | 删除 IAM 用户 |
| `disable_access_key` | 禁用特定的访问密钥 |
| `disable_role` | 向角色附加拒绝所有操作的内联策略 |
| `block_s3_public_access` | 启用账户级别的 S3 公共访问阻止 |
| `block_s3_bucket_public_access` | 阻止对特定存储桶的公共访问 |
| `block_s3_object_public_access` | 将单个 S3 对象设为私有(`ACL=private`) |
| `isolate_ec2_instances` | 将实例安全组替换为隔离组 |
设置 `DREDGE_DRY_RUN=true` 以模拟所有 IR 操作而不进行任何更改。
破坏性操作还受到滚动窗口断路器的限制
(每个 `RESPONDER_RATE_LIMIT_WINDOW_MINUTES` 中的
`RESPONDER_RATE_LIMIT_MAX_ACTIONS`,默认为 5 分钟内 20 次)——一旦跳闸,在窗口滚动之前,进一步的匹配检测将被记录并跳过,而不是被执行。
成功的操作不仅仅是记录——它还会通知。`responder`
会将第二个、绿色样式的 Slack/Discord/电子邮件通知加入队列,它与触发它的警报是分开的(此通知类型尚不支持 Security Hub/Jira/webhook),因此“这已被修复”与“这已被检测到”一样可见。请参阅[通知](#notifications)。
### responder 如何进行授权
responder 自身的 Lambda 执行角色没有任何破坏性的 AWS
权限——它在自己的凭证上唯一能做的就是在*任何* AWS 账户中对名为 `${self:service}-${self:provider.stage}-ir-role`(例如 `opencdr-dev-ir-role`)的角色执行 `sts:AssumeRole`,而不是一揽子授权。响应模块实际执行的所有操作(禁用用户、阻止 S3 公共访问、隔离 EC2 实例等)都是通过假定其中一个角色返回的临时凭证来运行的。
假定哪个角色是**按检测**解析的,基于检测来源的 AWS 账户(`src/handlers/responder.py` 中的 `_resolve_role_arn`):
1. 该账户在 `irAccountRolesTable` DynamoDB 表中有一条已启用的记录 → 假定该记录的 `role_arn`。
2. 该账户有一条记录但已禁用 → 完全跳过操作(记录为 `IR_ACCOUNT_DISABLED`)——**不会**回退到(3)。
3. 该账户没有记录,或者根本无法确定该账户 → `OPENCDR_IR_ROLE_ARN`。
**单账户部署无需为此进行任何设置。**
`serverless.yml` 会自动创建本账户的 IR 角色作为 CloudFormation
资源,并自动将 `OPENCDR_IR_ROLE_ARN` 连接到它——仅凭 `serverless
deploy` 就足够了;没有手动的 `aws iam create-role` 步骤,也不需要设置环境变量。
**其他账户**(多账户 / 跨账户 IR)的接入方法是在其中手动创建同名角色,并通过 `POST /ir-roles` 添加一行记录:
```
aws iam create-role --role-name opencdr-dev-ir-role \
--assume-role-policy-document file:///tmp/trust-policy.json # see docs/ir-role.md
aws iam put-role-policy --role-name opencdr-dev-ir-role \
--policy-name opencdr-ir-permissions \
--policy-document file://docs/ir-role-permissions.json
curl -X POST "$OPENCDR_API_URL/ir-roles" -H "x-api-key: $OPENCDR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"aws_account_id": "", "role_arn": "arn:aws:iam:::role/opencdr-dev-ir-role"}'
```
完整演练(信任策略示例、终止开关/禁用、缓存 TTL、保持权限策略同步)请见
[docs/ir-role.md](docs/ir-role.md)。
## 通知
通过 CLI 或 API 在设置表中配置渠道和路由。完整示例位于 `support_files/settings/settings.json` 中。
```
{
"setting_id": "global",
"notifications_enabled": true,
"channels": {
"slack": {
"enabled": true,
"webhook_url": "https://hooks.slack.com/services/..."
},
"discord": {
"enabled": false,
"webhook_url": "https://discord.com/api/webhooks/..."
},
"email": {
"enabled": false,
"topic_arn": "arn:aws:sns:us-east-1:123456789012:opencdr-dev-alerts"
},
"securityhub": {
"enabled": false
},
"jira": {
"enabled": false,
"base_url": "https://yourco.atlassian.net",
"project_key": "SEC",
"user_email": "soc@yourco.com",
"api_token": "",
"issue_type": "Bug"
},
"webhook": {
"enabled": false,
"targets": [
{
"name": "pagerduty",
"url": "https://events.pagerduty.com/v2/enqueue",
"headers": {}
},
{
"name": "opsgenie",
"url": "https://api.opsgenie.com/v2/alerts",
"headers": { "Authorization": "GenieKey " }
}
]
}
},
"routing": {
"CRITICAL": ["slack", "email", "jira"],
"HIGH": ["slack", "securityhub"],
"MEDIUM": ["discord"],
"LOW": ["webhook"]
}
}
```
路由是按严重程度进行的。如果没有匹配的路由条目,所有具有足够配置的已启用渠道都会收到警报。
### Slack 和 Discord
在 Slack 应用或 Discord 服务器设置中生成传入的 webhook URL,并将其传递给 CLI:
```
python3 scripts/opencdr.py settings set --slack-webhook https://hooks.slack.com/services/...
python3 scripts/opencdr.py settings set --discord-webhook https://discord.com/api/webhooks/...
```
webhook URL 是这两个平台的唯一身份验证机制——请将其视为机密。
### 通过 SNS 发送电子邮件通知
电子邮件通知是通过 stack 创建的 `opencdr--alerts` SNS topic 交付的。
**获取 topic ARN:**
```
aws sns list-topics \
--query "Topics[?contains(TopicArn, 'opencdr') && contains(TopicArn, 'alerts')]" \
--output text
```
**订阅您的电子邮件地址:**
```
aws sns subscribe \
--topic-arn arn:aws:sns:::opencdr--alerts \
--protocol email \
--notification-endpoint you@example.com
```
AWS 将发送一封确认电子邮件——在交付警报之前,请单击链接以激活订阅。
或者,在部署时传入 `--param="alertEmail=you@example.com"`,订阅将自动创建。
**在设置中启用电子邮件:**
```
python3 scripts/opencdr.py settings set \
--email-topic-arn arn:aws:sns:::opencdr--alerts
```
### AWS Security Hub
OpenCDR 可以将发现结果以 [ASFF 格式](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format.html)推送到 Security Hub。发现结果会显示在 Security Hub 控制台中您账户的自定义产品下。
**前提条件:** 必须在您的账户和区域中启用 Security Hub。
```
# 验证 Security Hub 是否活跃
aws securityhub describe-hub
# 启用 channel
python3 scripts/opencdr.py settings set --enable-securityhub
```
无需额外配置——notifier Lambda 会在运行时从其自身的执行上下文中派生出产品 ARN。
### Jira
OpenCDR 通过 [Jira REST API v3](https://developer.atlassian.com/cloud/jira/platform/rest/v3/) 创建 Jira issue。创建的 issue 包含 ADF 格式的描述、按严重程度映射的优先级以及一个 `opencdr` 标签。
**严重程度 → Jira 优先级映射:**
| OpenCDR 严重程度 | Jira 优先级 |
|---|---|
| CRITICAL | Highest |
| HIGH | High |
| MEDIUM | Medium |
| LOW | Low |
| INFORMATIONAL | Lowest |
**设置:**
1. 在 [id.atlassian.com/manage-profile/security/api-tokens](https://id.atlassian.com/manage-profile/security/api-tokens) 生成 Jira API token
2. 配置渠道:
```
python3 scripts/opencdr.py settings set \
--jira-url https://yourco.atlassian.net \
--jira-project SEC \
--jira-email soc@yourco.com \
--jira-token
# 可选:使用不同的 issue type(默认:Bug)
python3 scripts/opencdr.py settings set \
--jira-url https://yourco.atlassian.net \
--jira-project SEC \
--jira-email soc@yourco.com \
--jira-token \
--jira-issue-type Task
```
所有四个 Jira 标志(`--jira-url`、`--jira-project`、`--jira-email`、`--jira-token`)必须一起提供。
### 自定义 webhook
自定义 webhook 渠道将原始 OpenCDR 警报 JSON POST 到一个或多个 HTTPS 端点。配置任意数量的命名目标,每个目标都有自己的 URL 和可选标头。这涵盖了接受通用 webhook 的平台——PagerDuty、OpsGenie、Microsoft Teams 等——而无需专门的 第一方 集成。
**单个目标(无身份验证):**
```
python3 scripts/opencdr.py settings set \
--webhook-url https://events.pagerduty.com/v2/enqueue \
--webhook-name pagerduty
```
**带有 authorization header:**
```
python3 scripts/opencdr.py settings set \
--webhook-url https://api.opsgenie.com/v2/alerts \
--webhook-name opsgenie \
--webhook-header "Authorization=GenieKey "
```
**多个标头:**
```
python3 scripts/opencdr.py settings set \
--webhook-url https://example.com/hook \
--webhook-name my-hook \
--webhook-header "Authorization=Bearer " \
--webhook-header "X-Source=opencdr"
```
要配置多个目标,请使用带有完整设置 JSON 的 `--file`。
每个目标都是独立尝试的——如果一个目标失败,其他目标仍会运行,发送/失败计数反映了各个目标的结果。
### 通过 SNS 进行自定义集成
对于内置渠道之外的任何需求——自定义 payload 格式、条件路由、多步骤工作流——请将一个 Lambda 订阅到 `opencdr--alerts` SNS topic。OpenCDR 会将每个警报发布到那里;您的 Lambda 会执行您需要的任何操作。
**架构:**
```
OpenCDR notifier
└─► SNS topic (opencdr--alerts)
└─► Your Lambda
├─► PagerDuty (with custom payload)
├─► ServiceNow
├─► Datadog
└─► Anything else
```
**设置:**
1. 部署您的集成 Lambda(任何 runtime)
2. 将其订阅到 SNS topic:
```
aws sns subscribe \
--topic-arn arn:aws:sns:::opencdr--alerts \
--protocol lambda \
--notification-endpoint arn:aws:lambda:::function:
```
3. 授予 SNS 调用您的 Lambda 的权限:
```
aws lambda add-permission \
--function-name \
--statement-id opencdr-sns-invoke \
--action lambda:InvokeFunction \
--principal sns.amazonaws.com \
--source-arn arn:aws:sns:::opencdr--alerts
```
您的 Lambda 会在 `event["Records"][0]["Sns"]["Message"]` 中以 JSON 字符串的形式接收完整的 OpenCDR 警报 payload。无需对 OpenCDR 进行任何更改。
## SIEM 集成
OpenCDR 警报可以使用内置的自定义 webhook 渠道或 SNS 扇出模式发送到 SIEM——通过 HTTP 发送原始 JSON,或者将一个 Lambda 订阅到警报 topic 以进行 payload 转换。针对 Datadog、Splunk、Microsoft Sentinel、Elastic/OpenSearch、Chronicle、IBM QRadar 和 Sumo Logic 的完整演练位于 [`docs/siem-integrations.md`](docs/siem-integrations.md) 中。
## API
所有端点都需要 `x-api-key` 标头。该密钥由 Serverless 自动创建,并在部署后在 API Gateway 中可用。
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/status` | 健康检查 |
| `GET` | `/help` | 端点参考 |
| `GET` | `/signals` | 按 `severity`、`event_id` 或 `category` 查询信号 |
| `GET` | `/logs` | 按 `service`、`event_id` 或 `event_name` 查询日志 |
| `GET` | `/rules` | 列出规则(按 `rule_kind=signal\|correlation` 过滤) |
| `GET` | `/settings` | 获取全局通知设置 |
| `GET` | `/ir-roles` | 列出 AWS 账户 → IR 角色映射(请参阅 [docs/ir-role.md](docs/ir-role.md)) |
所有列表端点都支持 `page_size`、`order`(`asc`/`desc`),以及通过 `next_token` 进行基于游标的分页。
## 项目结构
```
src/
domain/ # Cloud-agnostic detection & correlation logic
handlers/ # Lambda entry points (processor, alerter, publisher, notifier, responder, api, alarm_notifier)
infra/ # AWS adapters (DynamoDB, SQS, logging, metrics, X-Ray)
config/ # Env/config loading shared across handlers
notifier/ # Shared HTTP transport used by notification delivery
docs/ # Deep-reference documentation — see docs/README.md
support_files/
detection_rules/ # Production rules (load with scripts/load_rules.sh)
test_events/ # Sample EventBridge events for local rule testing
settings/ # Example notification settings
scripts/
opencdr.py # Management CLI (setup wizard, rules, settings, signals, logs)
test_rules_local.py # Test rules locally without AWS
load_rules.sh # Seed rules into DynamoDB
test_deployed.sh # Integration test against deployed stack
cost_report.sh # Query Cost Explorer spend for a stage
setup_region_forwarding.sh # Onboard additional AWS regions (see docs/region-forwarding.md)
tests/
domain/ # Unit tests for detection, correlation, and parser
handlers/ # Unit tests for Lambda handlers (notifier channels, etc.)
infra/ # Unit tests for AWS adapter layer
scripts/ # Unit tests for the CLI
ci-bootstrap/ # Standalone CFN template for the OIDC deploy role (see docs/deployment.md)
region-forwarding/ # Standalone CFN template for cross-region event forwarding (see docs/region-forwarding.md)
serverless.yml # Infrastructure definition
openapi.yml # API spec (see docs/api-reference.md for known drift)
```
注意:`dredge`(`responder` 通过其运行操作的事件响应操作库)是一个单独的固定依赖项(`requirements.txt`),并未包含在此仓库中——请参阅 [事件响应](docs/incident-response.md)。
## 运行测试
```
pip install pytest pytest-cov
pytest tests/ -v
# With coverage
pytest tests/ --cov=src --cov=scripts --cov-report=term-missing
```
## 许可证
[MPL 2.0](LICENSE)
标签:AMSI绕过, AWS, DPI, FOFA, MITM代理, SIoC, 威胁检测, 安全运营, 扫描框架, 构建工具, 逆向工具