CloudTrail 日志结构解析
日志拿到手,第一件事就是看懂它的结构。我记得刚接触 CloudTrail 时,瞅着一大串 JSON 眼花缭乱。后来琢磨明白了,其实结构非常规整。你只要抓住几个核心字段,审计排查基本就稳了。
日志格式概览
CloudTrail 默认使用 JSON 格式,每行一个独立事件。每条日志就是一个 JSON 对象,顶层大概 20 多个字段。我建议你先记住下面这张表里的,其他字段查文档就行。
| 字段名 | 类型 | 说明 |
|---|---|---|
eventVersion | String | 日志格式版本,目前是 1.08 |
userIdentity | Object | 谁发起的请求 |
eventTime | String | 事件 UTC 时间,ISO8601 格式 |
eventSource | String | 服务域名,比如 ec2.amazonaws.com |
eventName | String | API 操作名字,比如 RunInstances |
awsRegion | String | 发生区域 |
sourceIPAddress | String | 来源 IP,要是来自 AWS 服务可能是 aws-internal |
userAgent | String | 客户端标识 |
requestParameters | Object | 请求参数,里面藏着关键配置 |
responseElements | Object | 响应数据 |
resources | Array | 操作涉及的资源列表 |
readOnly | Boolean | 是否为只读操作 |
eventType | String | AwsApiCall / AwsServiceEvent / AwsConsoleSignin 等 |
managementEvent | Boolean | 是否为管理事件(默认就是) |
recipientAccountId | String | 接收方账户 ID |
eventID | String | 全局唯一 ID,去重时特别有用 |
eventCategory | String | Management / Data / Insight |
重点记住: 排查问题时我一般先看 eventTime、eventName、sourceIPAddress 和 userIdentity。这四个组合起来就能定位到 90% 的异常。
核心字段详解——别被嵌套层数吓到
先说 userIdentity。它里面还有一层对象,包含这些子字段:
type:IAMUser、AssumedRole、Root、AWSService 等principalId:主体 IDarn:主体的 ARNaccountId:账户 IDaccessKeyId:访问密钥 ID(如果使用)userName:用户名(仅 IAMUser 时有)sessionContext:如果是临时凭证,这里会包含sessionIssuer和webIdFederationData
举个例子:一个 IAM 用户通过控制台操作,userIdentity 大概长这样:
"userIdentity": {
"type": "IAMUser",
"principalId": "AIDACKCEVSQ6C2EXAMPLE",
"arn": "arn:aws:iam::123456789012:user/zhangsan",
"accountId": "123456789012",
"accessKeyId": "ASIAIOSFODNN7EXAMPLE",
"userName": "zhangsan",
"sessionContext": null
}
requestParameters 和 responseElements 这两个字段最容易被忽略。说白了,它们就是请求和响应的完整参数副本。我遇到过一次运维跑脚本批量创建安全组,结果规则配错了,导致端口暴露。就是通过 requestParameters 里的 IpPermissions 数组发现源 IP 是 0.0.0.0/0 的。
resources 字段是个数组,每个元素包含 ARN 和 accountId。比如创建 EC2 实例时,会列出实例本身的 ARN 以及可能关联的安全组、子网。注意:不是所有 API 都会填充这个字段,控制台的操作往往比 CLI/SDK 填充得更全。
JSON 结构示例——一句一句读
下面给一个完整的日志示例,我加了中文注释便于理解:
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AssumedRole",
"principalId": "AROAJEXAMPLE:ec2-launch-session",
"arn": "arn:aws:sts::123456789012:assumed-role/EC2-Role/ec2-launch-session",
"accountId": "123456789012",
"accessKeyId": "ASIAIOSFODNN7EXAMPLE",
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "AROAJEXAMPLE",
"arn": "arn:aws:iam::123456789012:role/EC2-Role",
"accountId": "123456789012",
"userName": "EC2-Role"
},
"webIdFederationData": null,
"attributes": {
"creationDate": "2024-10-15T08:00:00Z",
"mfaAuthenticated": "false"
}
}
},
"eventTime": "2024-10-15T08:01:23Z",
"eventSource": "ec2.amazonaws.com",
"eventName": "RunInstances",
"awsRegion": "ap-northeast-1",
"sourceIPAddress": "203.0.113.50",
"userAgent": "console.aws.amazon.com",
"requestParameters": {
"instancesSet": {
"items": [{
"instanceType": "t3.micro",
"imageId": "ami-0abcdef1234567890"
}]
},
"groupSet": {
"items": [{"groupId": "sg-12345678"}]
}
},
"responseElements": {
"instancesSet": {
"items": [{"instanceId": "i-0abcd1234efgh5678"}]
}
},
"resources": [{
"ARN": "arn:aws:ec2:ap-northeast-1:123456789012:instance/i-0abcd1234efgh5678",
"accountId": "123456789012"
}],
"readOnly": false,
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "123456789012",
"eventID": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"eventCategory": "Management"
}
小技巧: 使用 Amazon Athena 查询日志时,我会直接解析 requestParameters 里的 JSON 路径。比如查找所有设置了 0.0.0.0/0 的安全组规则。不需要写复杂的正则,用 json_extract 就行了。
日志结构关系图——一眼看穿层级
下面这张图把日志的 JSON 层级关系画了出来。我自己画图时喜欢把 userIdentity 标成蓝色,因为它是识别主体的关键。requestParameters 和 responseElements 标成橙色,表示动态数据。其他基础字段用绿色表示。
注意: 数据事件(如 S3 的 GetObject)的日志格式和这里的管理事件略有不同——eventCategory 为 Data,而且 requestParameters 里可能包含桶名和对象键。如果你开启了数据事件,记得单独分析,不要混在一起查。
字段使用技巧——我的实战经验
我个人习惯在 Athena 里建一张视图,把常用字段提取出来。比如:
SELECT
eventtime,
eventname,
sourceipaddress,
useridentity.username,
json_extract(requestparameters, '$.instanceType') AS instance_type
FROM cloudtrail_logs
WHERE eventname = 'RunInstances'
AND eventtime > current_timestamp - interval '7' day
ORDER BY eventtime DESC;
这样做的好处是查异常非常快。我曾经发现一个账号每天凌晨 3 点都有 RunInstances 和 TerminateInstances 成对出现,顺着 useridentity.sessioncontext.sessionissuer.arn 找到了一个测试用的 Automation 脚本。虽然是合法操作,但证明了日志追踪能力。
避坑指南: 我曾经犯过一个错误——直接用 readOnly = false 过滤所有写入操作,却忘了有些 API 的 readOnly 字段可能缺失(早期事件)。后来统一用 eventtype = 'AwsApiCall' AND eventname NOT LIKE 'Get%' AND eventname NOT LIKE 'Describe%' AND eventname NOT LIKE 'List%' 更靠谱。
你想想看,只要把 JSON 结构搞透了,后面不管是写查询、做告警还是对接安全分析工具,都顺理成章。嗯,这一章的内容够用了。