pfrederiksen/cloudnecromancer
GitHub: pfrederiksen/cloudnecromancer
通过回放 CloudTrail 事件重建任意历史时间点的 AWS 基础设施状态快照,支持多格式导出和差异对比。
Stars: 0 | Forks: 0
# CloudNecromancer
通过回放 CloudTrail 事件来重建时间点 AWS 基础设施快照。
给定任意历史时间戳,CloudNecromancer 可以复活那一刻存在的所有资源 —— EC2 实例、IAM 角色、S3 存储桶、Lambda 函数、安全组、VPC、RDS 数据库等 —— 这些均基于存储在 CloudTrail 中的创建/修改/删除事件链。
```
░░░░░░░░░░░░░░░░░░░░░░░░░░
░ ☠ CloudNecromancer ☠ ░
░░░░░░░░░░░░░░░░░░░░░░░░░░
Raising the dead since 2026
```
## 使用场景
- **事件响应** — “违规事件发生前凌晨 3 点正在运行的是什么?”
- **合规审计** — 任意过去日期的时间点清单
- **事后时间线** — 完整的基础设施状态重建
- **偏差分析** — 比较两个时间戳以查看变化
## 安装
### Homebrew (macOS / Linux)
```
brew tap pfrederiksen/tap
brew install cloudnecromancer
```
### 从发布二进制文件
从 [Releases](https://github.com/pfrederiksen/cloudnecromancer/releases) 下载适用于您平台的最新版本。
| 平台 | 架构 |
|----------|-------------|
| macOS | Intel (amd64), Apple Silicon (arm64) |
| Linux | amd64 |
### 从源码
```
go install github.com/pfrederiksen/cloudnecromancer@latest
```
### 本地构建
```
git clone https://github.com/pfrederiksen/cloudnecromancer.git
cd cloudnecromancer
make build
# 位于 ./bin/cloudnecromancer 的 Binary
```
## 快速开始
```
# 1. 获取 CloudTrail 事件到本地数据库
cloudnecromancer fetch \
--account-id 123456789012 \
--regions us-east-1,us-west-2 \
--start 2026-01-01T00:00:00Z \
--end 2026-03-01T00:00:00Z
# 2. 在特定时间点复活基础设施
cloudnecromancer resurrect --at 2026-02-15T03:00:00Z
# 3. 比较两个时间点
cloudnecromancer diff \
--from 2026-01-01T00:00:00Z \
--to 2026-02-15T03:00:00Z
```
## 命令
### `fetch` — 将 CloudTrail 事件拉取到本地 DB
```
cloudnecromancer fetch \
--account-id 123456789012 \
--region us-east-1 \
--start 2026-01-01T00:00:00Z \
--end 2026-03-01T00:00:00Z \
[--regions us-east-1,us-west-2,eu-west-1] \
[--profile my-aws-profile] \
[--db ./necromancer.db]
```
跨一个或多个区域并发获取 CloudTrail 管理事件,并将其存储在本地 DuckDB 数据库中。事件通过事件 ID 进行去重,因此重新运行获取重叠时间范围的数据是安全的。
**示例输出:**
```
░░░░░░░░░░░░░░░░░░░░░░░░░░
░ ☠ CloudNecromancer ☠ ░
░░░░░░░░░░░░░░░░░░░░░░░░░░
Raising the dead since 2026
Fetching CloudTrail events...
us-east-1 ████████████████████████████████ 100% | 12,847 events
us-west-2 ████████████████████████████████ 100% | 3,291 events
Summary:
Events fetched: 16,138
Services: ec2, iam, s3, lambda, rds
Date range: 2026-01-01 to 2026-03-01
Database: ./necromancer.db (24 MB)
```
### `resurrect` — 重建某个时间点的基础设施
```
cloudnecromancer resurrect \
--at 2026-02-15T03:00:00Z \
[--services ec2,iam,s3] \
[--region us-east-1] \
[--format json|terraform|cloudformation|cdk|pulumi|ocsf|csv] \
[--output ./snapshot.json] \
[--include-dead] \
[--ritual] \
[--db ./necromancer.db]
```
回放给定时间戳之前的所有事件并重建每个资源的状态。`--ritual` 标志会添加一个带有“RAISING THE DEAD...”打字机效果的动画 ASCII 骷髅。
**示例 JSON 输出** (`--format json`):
```
{
"timestamp": "2026-02-15T03:00:00Z",
"account_id": "123456789012",
"regions": ["us-east-1", "us-west-2"],
"resources": {
"ec2:instance": [
{
"resource_id": "i-0abc123def456789",
"state": "running",
"attributes": {
"instance_type": "t3.medium",
"image_id": "ami-0abcdef1234567890",
"vpc_id": "vpc-0123456789abcdef0",
"subnet_id": "subnet-0123456789abcdef0"
},
"created_at": "2026-01-10T14:22:00Z",
"last_modified": "2026-02-01T09:15:00Z"
}
],
"iam:role": [
{
"resource_id": "WebAppRole",
"state": "active",
"attributes": {
"attached_policies": [
"arn:aws:iam::123456789012:policy/S3ReadOnly",
"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
]
},
"created_at": "2026-01-05T10:00:00Z",
"last_modified": "2026-01-20T16:30:00Z"
}
],
"s3:bucket": [
{
"resource_id": "prod-data-lake-2026",
"state": "active",
"attributes": {
"versioning": "Enabled",
"public_access_block": true
},
"created_at": "2026-01-02T08:00:00Z",
"last_modified": "2026-01-15T12:00:00Z"
}
]
},
"summary": {
"total_resources": 47,
"by_service": {
"ec2": 23,
"iam": 12,
"s3": 5,
"lambda": 4,
"rds": 3
},
"by_state": {
"active": 42,
"running": 5
}
}
}
```
**示例 HCL 输出** (`--format hcl`):
```
# 已重建 — 应用前请验证
# 由 CloudNecromancer 于 2026-02-15T03:00:00Z 生成
import {
to = aws_instance.i_0abc123def456789
id = "i-0abc123def456789"
}
resource "aws_instance" "i_0abc123def456789" {
instance_type = "t3.medium"
ami = "ami-0abcdef1234567890"
subnet_id = "subnet-0123456789abcdef0"
}
import {
to = aws_iam_role.WebAppRole
id = "WebAppRole"
}
resource "aws_iam_role" "WebAppRole" {
}
import {
to = aws_s3_bucket.prod_data_lake_2026
id = "prod-data-lake-2026"
}
resource "aws_s3_bucket" "prod_data_lake_2026" {
}
```
**示例 CloudFormation 输出** (`--format cloudformation`):
```
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Reconstructed by CloudNecromancer at 2026-02-15T03:00:00Z -- verify before deploying",
"Resources": {
"Ec2Instancei0abc123def456789": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": "t3.medium",
"ImageId": "ami-0abcdef1234567890",
"SubnetId": "subnet-0123456789abcdef0"
}
},
"S3Bucketproddatalake2026": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "prod-data-lake-2026"
}
}
}
}
```
**示例 CDK 输出** (`--format cdk`):
```
// RECONSTRUCTED -- verify before deploying
// Generated by CloudNecromancer at 2026-02-15T03:00:00Z
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';
export class CloudNecromancerStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new ec2.CfnInstance(this, "i-0abc123def456789", {
instanceType: "t3.medium",
imageId: "ami-0abcdef1234567890",
subnetId: "subnet-0123456789abcdef0",
});
new s3.CfnBucket(this, "prod-data-lake-2026", {
bucketName: "prod-data-lake-2026",
});
}
}
```
**示例 Pulumi 输出** (`--format pulumi`):
```
// RECONSTRUCTED -- verify before deploying
// Generated by CloudNecromancer at 2026-02-15T03:00:00Z
import * as aws from "@pulumi/aws";
const i_0abc123def456789 = new aws.ec2.Instance("i-0abc123def456789", {
instanceType: "t3.medium",
ami: "ami-0abcdef1234567890",
subnetId: "subnet-0123456789abcdef0",
});
const prod_data_lake_2026 = new aws.s3.Bucket("prod-data-lake-2026", {
bucket: "prod-data-lake-2026",
});
```
**示例 CSV 输出** (`--format csv`):
```
resource_id,resource_type,service,state,region,account_id,created_at,last_modified,snapshot_timestamp,attributes_json
i-0abc123def456789,instance,ec2,running,us-east-1,123456789012,2026-01-10T14:22:00Z,2026-02-01T09:15:00Z,2026-02-15T03:00:00Z,"{""instance_type"":""t3.medium""}"
WebAppRole,role,iam,active,us-east-1,123456789012,2026-01-05T10:00:00Z,2026-01-20T16:30:00Z,2026-02-15T03:00:00Z,"{""attached_policies"":[""arn:aws:iam::123456789012:policy/S3ReadOnly""]}"
```
### `diff` — 比较两个时间戳之间的基础设施
```
cloudnecromancer diff \
--from 2026-01-01T00:00:00Z \
--to 2026-02-15T03:00:00Z \
[--format table|json] \
[--db ./necromancer.db]
```
生成两个时间戳的快照并报告变化。
**示例输出**(默认表格格式):
```
░░░░░░░░░░░░░░░░░░░░░░░░░░
░ ☠ CloudNecromancer ☠ ░
░░░░░░░░░░░░░░░░░░░░░░░░░░
Raising the dead since 2026
Diff: 2026-01-01T00:00:00Z → 2026-02-15T03:00:00Z
+ ADDED (12 resources)
+ ec2:instance i-0abc123def456789 t3.medium us-east-1
+ ec2:instance i-0def456789abc123 t3.large us-west-2
+ s3:bucket prod-data-lake-2026 us-east-1
+ lambda:function process-orders python3.12 us-east-1
...
- REMOVED (3 resources)
- ec2:instance i-0old999888777666 t2.micro us-east-1
- iam:role LegacyAdminRole us-east-1
- s3:bucket temp-migration-2025 us-east-1
~ MODIFIED (8 resources)
~ iam:role WebAppRole us-east-1
attached_policies: +arn:aws:iam::123456789012:policy/S3ReadOnly
~ ec2:security_group sg-0123456789abcdef0 us-east-1
ingress: +0.0.0.0/0:443
```
### `export` — 重新导出现有快照
```
cloudnecromancer export \
--input ./snapshot.json \
--format hcl \
--output ./snapshot.tf
```
### `info` — 显示数据库统计信息
```
cloudnecromancer info [--db ./necromancer.db]
```
**示例输出:**
```
Database: ./necromancer.db
Events: 16,138
Date range: 2026-01-01T00:00:00Z to 2026-03-01T00:00:00Z
Services: ec2, iam, s3, lambda, rds
Regions: us-east-1, us-west-2
Size: 24 MB
```
## 全局标志
| 标志 | 默认值 | 描述 |
|------|---------|-------------|
| `--db` | `./necromancer.db` | DuckDB 数据库文件路径 |
| `--profile` | *(默认链)* | 要使用的 AWS profile |
| `--quiet` | `false` | 抑制横幅和非必要输出 |
| `--verbose` | `false` | 启用详细日志记录 |
## AWS 权限
CloudNecromancer 需要对 CloudTrail 的只读访问权限。有关最小 IAM 策略,请参阅 [AWS_PERMISSIONS.md](AWS_PERMISSIONS.md)。
简要版本:
```
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudtrail:LookupEvents",
"cloudtrail:GetTrailStatus",
"cloudtrail:DescribeTrails"
],
"Resource": "*"
}
]
}
```
凭证通过标准 AWS SDK 凭证链解析:环境变量、`~/.aws/credentials`、IAM 实例角色等。
## 输出格式
| 格式 | 标志 | 描述 |
|--------|------|-------------|
| JSON | `--format json` | 包含嵌套资源属性的完整快照 |
| Terraform | `--format terraform` | 可导入 Terraform 的 HCL,包含 `import` + `resource` 块(别名:`hcl`,`tf`) |
| CloudFormation | `--format cloudformation` | AWS CloudFormation JSON 模板(别名:`cfn`) |
| CDK | `--format cdk` | 使用 L1 constructs 的 AWS CDK TypeScript stack |
| Pulumi | `--format pulumi` | 使用 `@pulumi/aws` 的 Pulumi TypeScript 程序 |
| OCSF | `--format ocsf` | OCSF Inventory Info 事件 (class_uid 5001),换行符分隔的 JSON |
| CSV | `--format csv` | Splunk lookup table 格式 |
### 在 Splunk 中使用 CSV
将 CSV 输出作为 Splunk lookup table 上传,然后与 CloudTrail 日志关联:
```
| inputlookup cloudnecromancer_lookup.csv
| join resource_id [search index=cloudtrail earliest=-30d]
```
## 支持的服务 (23)
| 服务 | 资源 | 创建 | 更新 | 删除 |
|---------|-----------|--------|--------|--------|
| EC2 | instances, VPCs, subnets, security groups, IGWs | Yes | Yes | Yes |
| IAM | roles, users, policies | Yes | Yes | Yes |
| S3 | buckets, policies, versioning, public access | Yes | Yes | Yes |
| Lambda | functions | Yes | Yes | Yes |
| RDS | instances, clusters | Yes | Yes | Yes |
| ELB | load balancers, target groups, listeners | Yes | Yes | Yes |
| ECS | clusters, services, task definitions | Yes | Yes | Yes |
| EKS | clusters, nodegroups | Yes | Yes | Yes |
| KMS | keys, aliases, rotation | Yes | Yes | Yes |
| Secrets Manager | secrets, rotation, restore | Yes | Yes | Yes |
| CloudWatch Logs | log groups, log streams, retention | Yes | Yes | Yes |
| DynamoDB | tables, global tables | Yes | Yes | Yes |
| SNS | topics, subscriptions | Yes | Yes | Yes |
| SQS | queues, queue attributes | Yes | Yes | Yes |
| API Gateway | REST APIs, HTTP APIs, stages | Yes | Yes | Yes |
| Route 53 | hosted zones, record sets | Yes | Yes | Yes |
| ECR | repositories, lifecycle policies, scanning | Yes | Yes | Yes |
| ElastiCache | clusters, replication groups | Yes | Yes | Yes |
| WAF v2 | web ACLs, rule groups, IP sets | Yes | Yes | Yes |
| GuardDuty | detectors, filters | Yes | Yes | Yes |
| CloudFront | distributions, origin access controls | Yes | Yes | Yes |
| EBS | volumes, snapshots | Yes | Yes | Yes |
| SSM | documents, parameters, maintenance windows | Yes | Yes | Yes |
## 工作原理
1. **Fetch (获取)** — CloudNecromancer 通过 `LookupEvents` 拉取 CloudTrail 管理事件,并将其存储在嵌入式 DuckDB 数据库中。多区域获取并发运行。
2. **Parse (解析)** — 每个 CloudTrail 事件通过服务特定的解析器(在启动时注册)进行路由,该解析器提取 `ResourceDelta`:操作(创建/更新/删除)、资源 ID 和相关属性。
3. **Replay (回放)** — 为了重建时间 T 的状态,引擎查询 T 之前的所有事件(按时间顺序排列)并将每个增量应用到内存中的资源映射。创建即插入,更新即合并属性,删除即将资源标记为已终止。
4. **Export (导出)** — 最终快照以请求的格式序列化。
## 开发
```
make build # Build binary to ./bin/cloudnecromancer
make test # Run all tests
make lint # Run golangci-lint
make snapshot # Build cross-platform binaries (GoReleaser)
```
### 添加新的服务解析器
1. 创建 `internal/parser/services/myservice.go`
2. 实现 `Parser` 接口
3. 在 `init()` 中使用 `parser.Register(&MyServiceParser{})` 注册
4. 将测试 fixtures 添加到 `testdata/`
5. 在 `internal/parser/services/myservice_test.go` 中添加表驱动测试
### 添加新的导出器
1. 创建 `internal/export/myformat.go`
2. 实现 `Exporter` 接口 (`Export(snapshot, writer) error`)
3. 在 `internal/export/exporter.go` 的 `GetExporter()` 中注册
4. 在 `internal/export/export_test.go` 中添加测试
5. 更新 `cmd/resurrect.go` 和 `cmd/export.go` 中的 `--format` 标志描述
## 许可证
MIT
标签:AWS, CloudTrail, DPI, EC2, EVTX分析, Go, HTTP/HTTPS抓包, IaC, IAM, Lambda, RDS, Ruby工具, S3, VPC, Web报告查看器, 事件回放, 云资源管理, 偏差分析, 历史记录, 基础设施重建, 态势感知, 数字取证, 文档结构分析, 日志审计, 时间点快照, 网络安全审计, 自动化脚本, 足迹分析