4. CloudTrail 日志结构:JSON 文件与关键字段解析

拿到 CloudTrail 日志,你打开一看,是一堆 JSON 文件。很多人第一反应:“这玩意儿怎么读?”

说实话,我第一次看的时候也懵。密密麻麻的键值对,光字段就几十个。但别慌,真正需要你关注的,其实就那么几个核心字段。今天我就带你把这些字段一个一个掰开来看。

4.1 日志文件长什么样?

CloudTrail 默认把日志写到 S3 桶里,路径像这样:

AWSLogs/123456789012/CloudTrail/us-east-1/2025/01/15/123456789012_CloudTrail_us-east-1_20250115T0000Z_abcd1234.json.gz

每个文件是一个经过 Gzip 压缩的 JSON 数组。我刚开始查问题时,忘了先用 gunzip 解压,直接在编辑器里打开看到一堆乱码——嗯,这个坑我踩过两次。

解压后的结构大概是这样:

{
  "Records": [
    {
      "eventVersion": "1.08",
      "userIdentity": { ... },
      "eventTime": "2025-01-15T10:30:00Z",
      "eventSource": "ec2.amazonaws.com",
      "eventName": "RunInstances",
      "awsRegion": "us-east-1",
      "sourceIPAddress": "203.0.113.42",
      "userAgent": "console.amazonaws.com",
      "requestParameters": { ... },
      "responseElements": { ... },
      "resources": [ ... ],
      "readOnly": false,
      "eventID": "abcdef12-3456-7890-abcd-ef1234567890",
      "eventType": "AwsApiCall",
      "managementEvent": true
    },
    ...
  ]
}

注意最外层是一个 Records 数组。每个元素是一次 API 调用的完整记录。我习惯把每个事件看作一张“安检照片” —— 谁、什么时间、从哪来、干了什么事、结果如何,全部拍下来。

4.2 你必须记住的七个关键字段

下面这张表是我从实战中整理出来的。你只要把这几列吃透,99% 的审计场景都能搞定。

字段名 含义 用途
eventID 事件唯一标识(UUID) 去重、追踪、与第三方系统关联
eventSource 服务域名(如 ec2.amazonaws.com) 判断是哪个 AWS 服务触发了事件
eventName API 操作名称(如 RunInstances) 识别具体操作类型
userIdentity 调用者身份信息(JSON 对象) 定位“谁干的”
eventTime 事件发生时间(ISO 8601 格式) 时间线分析、告警触发
sourceIPAddress 来源 IP 地址 判断是否来自异常位置
requestParameters API 请求参数(JSON 对象) 查看具体做了哪些操作(如创建了什么实例、多大规格)

我个人的习惯:在 Athena 建表查询时,优先把这 7 个字段做成索引列。查询效率能提升 3-5 倍。

4.3 深度解析:eventID —— 事件身份证

每个 eventID 是全局唯一的 UUID 字符串。你可能会问:“这有什么用?我查日志又不靠它定位。”

用处大了去了。我遇到过这样的情况:同一个 API 调用因为网络重试,被 CloudTrail 记录了两次,数据对不上。这时候靠 eventID 去重就行。另外,如果你需要把 CloudTrail 日志和第三方 SIEM(比如 Splunk)联动,eventID 就是完美的关联键。

小技巧:把 eventID 当主键建表,加上 eventTime 做排序键,查询结果永远按时间排好。

4.4 深度解析:eventSource —— 谁家的 API?

eventSource 的格式是 服务名.amazonaws.com。比如:

  • ec2.amazonaws.com —— EC2 操作
  • iam.amazonaws.com —— IAM 操作
  • s3.amazonaws.com —— S3 操作
  • sts.amazonaws.com —— 安全令牌服务

这里有个小坑:跨区域服务调用可能产生多个 eventSource。比如 us-east-1 的 EC2 调用 us-west-2 的 S3,查日志时千万别只盯着一个区域看。

4.5 深度解析:eventName —— 干了什么?

这是最直观的字段,直接告诉你操作名。比如 RunInstances、DeleteBucket、AttachRolePolicy。

注意命名规范:

  • 创建类:Create*、Run*、Put*
  • 删除类:Delete*、Terminate*
  • 修改类:Update*、Modify*、Attach*
  • 读取类:Get*、Describe*、List*

我一般这么用:监控告警时只盯 创建类 和 删除类,读取类基本不告警(因为太频繁)。

4.6 深度解析:userIdentity —— 谁干的?

这个字段是一个嵌套的 JSON 对象。我把它拆成四种常见类型:

类型 说明 典型场景
IAM 用户 直接使用长期凭证调用 API 人类开发者登录控制台或使用 CLI
IAM 角色 通过 AssumeRole 获取临时凭证 EC2 实例上的应用程序、Lambda 函数
根用户 使用 AWS 账号根凭证(极度危险) 极少情况,出现基本就是安全事件
联合身份 通过 SAML 或 Web Identity 登录 企业员工通过 SSO 访问

userIdentity 内部还包含 arn、accountId、userName 等子字段。举个 IAM 用户的例子:

{
  "type": "IAMUser",
  "principalId": "AIDACKCEVSQ6C2EXAMPLE",
  "arn": "arn:aws:iam::123456789012:user/admin",
  "accountId": "123456789012",
  "userName": "admin"
}

避坑指南:我曾经查过一个安全事件,发现 userIdentity.type 显示 AssumedRole,但 roleName 居然是 AdminRole。后来发现是某台被攻破的 EC2 上跑的恶意程序窃取了角色令牌。所以 千万不要只看 userName,一定要检查 principalId。

4.7 深度解析:其他重要字段速览

  • awsRegion:事件发生的区域。注意有些全局服务(如 IAM)会标记为 us-east-1。
  • sourceIPAddress:来源 IP。如果看到来自你根本不用的区域的 IP,基本就是异常。
  • userAgent:客户端信息。比如 console.amazonaws.com(控制台)、aws-sdk-java(SDK)、signin.amazonaws.com(登录)。
  • readOnly:布尔值。true 表示只读操作(如 Describe 类), false 表示写操作。
  • resources:操作涉及到的资源列表(ARN 数组)。比如删除 S3 桶,这里会列出被删的桶 ARN。
  • managementEvent:布尔值。true 表示管理事件(控制台操作、API 调用),false 表示数据事件(S3 GetObject、Lambda Invoke 等)。

我个人的习惯:做基线分析时,我会把 readOnly = false 的事件全部单独拿出来分析。因为所有“写操作”才是真正的风险点。

4.8 知识结构:CloudTrail 日志核心框架

下面这张图我把上面讲的核心字段和它们的关联关系画了出来,方便你复习。

CloudTrail 日志核心字段结构 CloudTrail 日志 JSON 结构 CloudTrail Log (JSON) Records [ ] 事件记录 (JSON Object) eventID eventSource eventName userIdentity eventTime sourceIPAddress requestParameters type / arn / userName 核心思路:从 Records 数组展开,先定位七个基础字段,再深入 userIdentity 判断身份类型

从图中可以看出,你只需要抓住这 7 个字段,就能完成 80% 以上的审计需求。每次分析日志时,先在脑子里过一遍这张图,就能快速找到关键线索。

4.9 实战经验:一次误删 S3 桶的排查过程

讲个真实案例。有次客户反馈说“生产环境的 S3 桶突然被删了”。我直接用 Athena 查 CloudTrail:

SELECT eventTime, eventName, userIdentity.userName, sourceIPAddress, requestParameters
FROM cloudtrail_logs
WHERE eventSource = 's3.amazonaws.com'
  AND eventName = 'DeleteBucket'
  AND eventTime > '2025-01-01T00:00:00Z'
ORDER BY eventTime DESC
LIMIT 10;

结果出来很快—— eventName 是 DeleteBucket,userIdentity.userName 是 deploy-bot,sourceIPAddress 是内部 CI 服务器的 IP。

发现是某个 Jenkins 脚本写错了环境变量。后面我们加了一条告警规则:任何删除 S3 桶的操作,立刻发通知到安全群。

这里的关键点:如果你不熟悉 CloudTrail 字段,第一步就得翻官方文档。而你对这几个关键字段有感觉后,30 秒就能定位问题。

4.10 总结与贴士

  • eventID —— 唯一去重,必建索引
  • eventSource —— 快速锁定服务范围,别被跨区域绕晕
  • eventName —— 只关注写操作类事件
  • userIdentity —— 细看 type 和 principalId,不要只看 userName
  • eventTime —— 配合排序,轻松做时间线
  • sourceIPAddress —— 结合地理位置,异常检测利器
  • requestParameters —— 深挖操作细节

我的建议:初学者可以先在 CloudTrail 控制台的“事件历史”里翻几个日志样本,对照本文的字段说明,逐项看一遍。复制一段 JSON 到本地编辑器里,高亮显示,会很有帮助。