3. CloudTrail 事件结构解析:eventVersion、eventID、eventTime 等基础字段
做 Secrets Manager 审计,你绕不开 CloudTrail。说白了,每次有人读取、轮换、删除一个 Secret,Secrets Manager 都会往 CloudTrail 里塞一条事件。这条事件长什么样?哪些字段必须看、哪些可以跳过?这就是本章要聊的事。
我个人习惯,拿到一条 CloudTrail 事件后,先扫一眼四个基础字段——eventVersion、eventID、eventTime、eventType。这四个字段能帮你快速判断事件的来源、唯一性、发生时间以及事件类别。嗯,咱们一个一个拆开说。
3.1 一条 CloudTrail 事件长什么样?
先给你看一个真实的 Secrets Manager 事件片段。这段 JSON 是从 CloudTrail Log 里直接拷贝出来的,我隐掉了敏感信息:
{
"eventVersion": "1.08",
"userIdentity": {
"type": "IAMUser",
"arn": "arn:aws:iam::123456789012:user/zhang.san",
"accountId": "123456789012"
},
"eventTime": "2025-03-21T08:32:15Z",
"eventSource": "secretsmanager.amazonaws.com",
"eventName": "GetSecretValue",
"awsRegion": "us-east-1",
"sourceIPAddress": "203.0.113.42",
"userAgent": "aws-cli/2.15.0",
"requestParameters": {
"secretId": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod-db-password-aBc123"
},
"responseElements": null,
"eventID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"readOnly": true,
"resources": [
{
"ARN": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod-db-password-aBc123",
"accountId": "123456789012"
}
],
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "123456789012"
}
看到没有?一条事件里少说二三十个字段。但我们做审计,不需要全背下来。只要抓住几个骨架字段,就能把事件脉络理清楚。
3.2 eventVersion —— 格式版本号,别小看它
eventVersion 的值目前最常见的是 1.08 和 1.09。你可能会问:「版本号变了跟我有什么关系?」
关系大了。不同版本的事件结构可能不同。我记得有一次,团队里一个同学写了一个解析 CloudTrail 事件的脚本,跑了半年都没问题。结果某天突然报错——一查,AWS 把某个字段从嵌套结构改成了平铺结构,而他的脚本还是按老版本解析的。
我个人建议,在任何自动化处理 CloudTrail 事件的代码里,第一件事就是检查 eventVersion。如果遇到不认识的版本号,直接告警,而不是闷头往下解析。
| 版本 | 主要变化 | 当前使用情况 |
|---|---|---|
| 1.05 | 早期版本,字段较少 | 基本消失 |
| 1.06 | 增加 recipientAccountId | 旧系统偶见 |
| 1.07 | 增加 managementEvent 等 | 部分区域仍在使用 |
| 1.08 | 稳定版本,当前主流 | 大部分区域默认 |
| 1.09 | 新增边缘字段,结构微调 | 新区域逐步推广 |
WHERE eventVersion >= '1.08' 过滤掉老旧格式的事件,避免解析异常。
3.3 eventID —— 事件的「身份证号」
eventID 是一个 UUID v4 格式的字符串,比如 a1b2c3d4-e5f6-7890-abcd-ef1234567890。全局唯一,不会重复。
这个字段有什么用?两个场景:
- 去重:CloudTrail 可能会因为网络抖动或后端重试,把同一条事件投递两次。这时候用 eventID 去重,比用时间戳加事件名靠谱得多。
- 关联:如果你把 CloudTrail 事件和 GuardDuty 发现、Security Hub 告警做关联,eventID 就是那个「连接点」。
我曾经遇到过一个 case:客户说「有一条 GetSecretValue 的告警,但我去查 CloudTrail 找不到」。后来发现,他查的是 eventName,但告警里记录的是 eventID。两边用的字段不一样,当然对不上。嗯,这种低级坑,踩过一次就记住了。
3.4 eventTime —— 时间戳的精度与陷阱
eventTime 用的是 UTC 时间,ISO 8601 格式。精确到秒,但你别以为它就是事件发生的真实时间。
这里有个关键点:eventTime 是 AWS 服务接收到请求的时间,不是操作完成的时间。换句话说,如果服务端处理队列很长,eventTime 可能比你想象的要早。另外,跨区域调用时,eventTime 记录的是接收端的时间,不是发起端的时间。
举个例子:你在东京(ap-northeast-1)发起一个请求,但 Secret 在美国东部(us-east-1)。那么 eventTime 是美东时间,不是东京时间。做跨区域审计时,这个坑一定要避开。
eventID 去关联 responseElements 里的返回时间,或者用 CloudTrail 的 latency 字段。
3.5 其他基础字段一览
除了上面三个,还有几个字段也是一眼就能提供大量信息的:
| 字段 | 含义 | 审计价值 |
|---|---|---|
| eventType | 事件类型:AwsApiCall / AwsServiceEvent / AwsConsoleAction | 区分是 API 调用、服务内部事件还是控制台操作 |
| eventSource | 事件来源服务,如 secretsmanager.amazonaws.com | 快速过滤出 Secrets Manager 相关事件 |
| awsRegion | 事件发生的区域 | 判断资源是否跨区域访问 |
| managementEvent | 是否为管理事件(true/false) | Secrets Manager 全部是管理事件 |
| readOnly | 是否为只读操作 | 区分 GetSecretValue(读)和 RotateSecret(写) |
我自己在写审计查询时,最常用的组合就是:eventSource = 'secretsmanager.amazonaws.com' AND eventType = 'AwsApiCall'。这一下就能筛掉 90% 的噪音。
3.6 一张图看懂基础字段
下面这张图是我梳理的 CloudTrail 事件基础字段结构。你把它当成一个「事件骨架」就行:
3.7 实战:如何快速定位一条 Secrets Manager 事件
光说不练假把式。咱们来一个真实的查询场景。
假设你收到一个告警:「账号 123456789012 在 us-east-1 有人读取了 prod-db-password 这个 Secret」。你要怎么快速找到这条事件?
在 CloudTrail 控制台或 Athena 里,我会这样查:
SELECT eventID, eventTime, eventName, userIdentity.arn, sourceIPAddress
FROM cloudtrail_logs
WHERE eventSource = 'secretsmanager.amazonaws.com'
AND eventName = 'GetSecretValue'
AND awsRegion = 'us-east-1'
AND recipientAccountId = '123456789012'
AND eventTime BETWEEN '2025-03-21T08:00:00Z' AND '2025-03-21T09:00:00Z'
ORDER BY eventTime DESC
查出来之后,拿 eventID 去跟告警里的 ID 比对,再用 userIdentity.arn 定位到具体的人。一套组合拳下来,谁在什么时间看了哪个 Secret,清清楚楚。
好了,这一章的基础字段就说到这。你记住一句话就行:eventVersion 看格式,eventID 做去重,eventTime 定时间,eventType 分来源。把这四个焊死在你的审计流程里,后面章节的复杂字段解析,你会学得特别顺。