审计日志数据模型:字段、事件与JSON结构

说到KMS审计日志,很多新手第一反应就是——“不就是一堆JSON吗?”
嗯,这话对了一半。
JSON没错,但你如果不懂里面每个字段的真实含义,排查问题时你就会像无头苍蝇一样乱转。

我个人习惯把审计日志数据模型理解成“谁在什么时候对哪个密钥做了什么,结果如何”。
拆开来看,核心就那么几块。今天咱们就把这层窗户纸捅破。

核心字段结构:一条审计日志到底长什么样?

先看一条真实的KMS审计日志(JSON格式)。我简化了一些敏感信息,但核心字段都在:

{
  "eventVersion": "1.08",
  "userIdentity": {
    "type": "IAMUser",
    "arn": "arn:aws:kms:cn-north-1:123456789012:user/admin",
    "accountId": "123456789012",
    "userName": "admin"
  },
  "eventTime": "2024-03-15T08:30:00Z",
  "eventSource": "kms.amazonaws.com",
  "eventName": "Decrypt",
  "awsRegion": "cn-north-1",
  "sourceIPAddress": "203.0.113.42",
  "userAgent": "console.amazonaws.com",
  "requestParameters": {
    "keyId": "arn:aws:kms:cn-north-1:123456789012:key/mrk-1234abcd5678efgh",
    "encryptionAlgorithm": "SYMMETRIC_DEFAULT"
  },
  "responseElements": {
    "keyId": "arn:aws:kms:cn-north-1:123456789012:key/mrk-1234abcd5678efgh",
    "encryptionAlgorithm": "SYMMETRIC_DEFAULT"
  },
  "resources": [
    {
      "arn": "arn:aws:kms:cn-north-1:123456789012:key/mrk-1234abcd5678efgh",
      "accountId": "123456789012",
      "type": "AWS::KMS::Key"
    }
  ],
  "eventType": "AwsApiCall",
  "recipientAccountId": "123456789012"
}

这里面每个字段都不是摆设。我挑几个容易踩坑的来说。

字段深度解析:这些坑我替你们趟过了

字段 说明 避坑要点
eventVersion 日志格式版本,目前主流是1.08 不同版本字段可能有增减,解析时不要硬编码
userIdentity 发起请求的身份信息,含类型、ARN、用户名 这里可能是IAM用户、角色、账户根用户,注意type字段
eventName 操作名称,如Decrypt、Encrypt、CreateKey 大小写敏感,查询时注意精确匹配
requestParameters 请求参数,通常包含keyId和加密算法 Decrypt请求里不一定有明文密钥,只有密文标识
resources 涉及的资源列表,一般是目标密钥的ARN 有时会有多个资源,需要遍历处理
eventType 事件类型,常见AwsApiCall、AwsServiceEvent 很多工具只过滤AwsApiCall,会漏掉服务内部调用
我曾经踩过的坑:有一次排查密钥被解密的原因,我只看eventName是Decrypt,忽略了userIdentity里的type是“AWSService”。结果发现是某内部服务自动调用的,跟用户操作无关。查了三天才发现这个细节。所以,永远要把userIdentity.type和eventName结合起来看。

事件类型分类:四种事件,各有用途

KMS审计日志里的eventType字段,说白了就四种情况:

  • AwsApiCall — 用户或角色通过API/SDK/控制台发起的操作。最常见,占95%以上。
  • AwsServiceEvent — 其他AWS服务替用户调用的KMS操作。比如S3用KMS密钥加密对象时,日志里就是这种类型。
  • AwsConsoleAction — 通过控制台操作时产生。跟AwsApiCall有点像,但会带上控制台的具体操作路径。
  • AwsInternal — KMS内部维护操作。一般不需要分析,可以过滤掉。

我建议在做聚合分析时,把AwsServiceEvent单独拎出来看。为什么呢?因为这类操作往往跟你的业务密钥流出有关。我记得有一次,客户说“我们没人用KMS解密,但审计日志里有大量Decrypt”。一查,全是AwsServiceEvent,是数据库服务自动解密的。你想想看,如果混在一起统计,这水就浑了。

JSON格式实战:如何快速提取关键信息?

手动翻JSON太累了。我习惯写一个简单的解析流程:

// 伪代码,以Python为例
def parse_kms_log(log_json):
    event = json.loads(log_json)
    identity = event.get('userIdentity', {})
    return {
        'time': event.get('eventTime'),
        'who': identity.get('userName', identity.get('type')),
        'what': event.get('eventName'),
        'which_key': event.get('requestParameters', {}).get('keyId'),
        'source_ip': event.get('sourceIPAddress'),
        'result': event.get('responseElements', {}).get('keyId', 'N/A')
    }

为什么要注意responseElements?因为有些操作失败了,keyId可能为空。这时候你要去看errorCode字段。我补充一下:很多审计日志分析脚本只提取requestParameters,忽略了失败操作的响应信息,筛查异常时就会漏掉。

技巧:搜索时可以用eventSource == 'kms.amazonaws.com' 先缩小范围。然后按eventName分组统计,快速识别异常操作。

审计日志数据模型核心关系图

下面这张图整理了KMS审计日志的数据模型骨架:

KMS审计日志数据模型核心关系 事件主体 userIdentity 操作内容 eventName + eventType 目标资源 resources + keyId 执行 作用于 执行结果 responseElements 状态 时间位置 eventTime + region 来源信息 sourceIP + userAgent 账户归属 recipientAccountId 一条完整的KMS审计日志 = 谁(主体) + 做了什么(操作) + 对谁(资源) + 结果 + 时空上下文

你看,从左到右,从上到下,一条日志的信息流就是这样的。从主体发起操作,到操作作用于密钥资源,然后产生结果,最后带上时间、来源、账户信息。理解了这个流向,后续你再做自动化分析就轻松多了。

避坑实战清单

我总结的几个实战要点:
  • 永远检查userIdentity.type:是用户操作还是服务代理操作?这两类行为的审计排查逻辑完全不同。
  • 筛选时别只盯着eventName:建议同时看eventType和errorCode,很多隐蔽问题藏在错误日志里。
  • responseElements里的keyId可能为空:如果成功,它返回操作的密钥ID;如果失败,可能只有errorMessage。
  • 时间戳用UTC:多数环境下的KMS审计日志使用UTC时间,分析前务必跟本地时间做好换算。
实用命令:用athena或splunk查询时,可以直接用eventType + eventName做分组聚合。例如:
SELECT eventName, count(*) as count FROM kms_logs WHERE eventType='AwsApiCall' GROUP BY eventName ORDER BY count DESC

明白了模型,下一件事就是去实际环境里跑几条日志看看。我建议你先从自己的账号拉一周的KMS审计日志,手动解析一条对照本文的字段结构。嗯,真的,遇到问题的时候你会感谢今日的自己。