审计日志核心三要素:谁、何时、做了什么?
审计日志到底要记什么?说白了,三个要素缺一不可:谁(主体)、何时(时间)、做了什么(操作)。我做过好几个 KMS 的合规项目,发现很多团队一开始只记了“操作成功”或“失败”,结果取证时根本对不上号。嗯,这期我们就聊聊这三个要素该怎么落地。
1. 谁(Who)—— 主体身份
“谁”不只是一个用户名。真正的生产环境里,操作来源可能五花八门:
- IAM 用户(AK/SK 或密码登录)
- 服务角色(EC2 实例扮演的 Role)
- 应用程序(通过 SDK 调用的 Client ID)
- 匿名访问(某些公开接口,但要慎用)
我个人习惯在审计日志里记录三个维度:user_id、user_type、source_ip。为什么不只记一个 ID?因为我遇到过这样的情况:同一个用户换了 IP,事后排查发现是 被盗用。你想想看,如果只记了用户名,根本看不出“谁从哪来”。
session_id 或 request_id 也带上,能串联出完整的操作链路。
2. 何时(When)—— 时间戳
时间戳看着简单,坑却不少。我建议至少记录两个时间:
- 服务端接收时间(KMS 收到请求的时刻)
- 操作完成时间(实际执行完的时刻)
为什么?我曾经遇到一个场景:客户端和服务器时钟差了 20 秒,用户坚持说自己在 10:00:00 发起了密钥轮换,但日志显示 10:00:20 才收到请求。扯皮了很久。最后我们强制所有审计日志使用 UTC 时间,并且在字段里标明时区偏移。
3. 做了什么(What)—— 操作详情
“做了什么”不止是操作名称。一串完整的操作记录应该包括:
- 操作类型(Encrypt、Decrypt、GenerateDataKey……)
- 资源标识(密钥 ID、别名、CMK ARN)
- 请求参数(加密上下文、密钥规格等关键入参)
- 结果状态(成功 / 失败 / 部分成功,以及错误码)
- 返回对象摘要(比如仅记录密文的哈希,不记录明文)
这里要特别提醒:千万不要把明文密钥或数据记录进审计日志。我在 code review 时见过一个 SDK 踩了雷——开发图方便,直接把 Encrypt 明文给打进了日志。幸好是测试环境,否则就是严重安全事故。
典型审计日志结构
下面是我在项目里常用的 JSON 结构(基于 AWS CloudTrail 格式改编):
{
"version": "1.0",
"eventTime": "2025-03-15T08:12:00Z",
"userIdentity": {
"type": "IAMUser",
"principalId": "AIDA123456789",
"arn": "arn:aws:iam::123456789012:user/admin",
"accountId": "123456789012",
"accessKeyId": "AKIAIOSFODNN7EXAMPLE"
},
"eventSource": "kms.amazonaws.com",
"eventName": "Encrypt",
"awsRegion": "us-east-1",
"sourceIPAddress": "203.0.113.10",
"userAgent": "aws-cli/2.0",
"requestParameters": {
"keyId": "arn:aws:kms:us-east-1:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
"encryptionContext": {"department": "finance"}
},
"responseElements": {
"keyId": "arn:aws:kms:us-east-1:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
"ciphertextBlob": "AQICAHh7...(仅展示哈希,非完整明文)"
},
"eventType": "AwsApiCall",
"recipientAccountId": "123456789012"
}
这个结构把“谁、何时、做了什么”都囊括了。注意我特意省略了 ciphertextBlob 的完整值,只放个哈希标识。这是安全红线。
三要素对比表
| 要素 | 关键字段示例 | 常见错误 | 最佳实践 |
|---|---|---|---|
| Who | userIdentity.type, sourceIPAddress |
只记用户名,忽略角色/来源 IP | 记录 IAM 类型 + 身份 ARN + IP |
| When | eventTime (ISO 8601 UTC), requestDuration |
使用本地时间,无时区 | 强制 UTC,记录精度到毫秒 |
| What | eventName, requestParameters, responseElements |
记录明文密钥或敏感数据 | 只记录元数据,永远不要记录明文 |
三要素的联动关系
上面三个要素不是孤立的。举个例子:一个解密操作(What)发生在午夜(When),发起方却是一个本该禁用 IAM 用户(Who)——这就是典型的安全告警信号。我建议在审计日志分析时,把这三点做成一个“三元组”,方便做关联分析。
这个图展示了三要素如何串联成一个完整的审计事件。实际做日志聚合时,我通常会用 userIdentity.arn + eventTime + eventName 做 联合主键,方便去重和排序。
常见的审计日志“四不像”
下面是我遇到过的两个典型反面教材,你对比着看:
- 只记功能,不记身份。 有次客户说“我们 KMS 审计日志相当详细”,结果一看,全部是
{"action":"encrypt","time":"...","status":"ok"}—— 没 IP、没用户、没资源 ID。等于白记。 - 时间戳格式混乱。 同一个日志文件里,既有
"2025-03-15T08:00:00Z",又有"03/15/2025 08:00:00 UTC+8"。解析脚本天天报错。
选型时需要关注的要素
当你在对比不同 KMS(AWS KMS、Azure Key Vault、HashiCorp Vault、自建等)时,可以按以下清单逐项检查:
- 是否支持记录 完整的身份信息(包括 IAM 角色、服务账户)?
- 时间戳的精度和格式是否可以自定义?
- 操作详情中是否包含 请求参数(密钥 ID、加密上下文等)?
- 失败操作是否有独立的错误码和失败原因?
- 是否支持审计日志的 不可篡改(如写入 S3 Object Lock 或日志存储加密)?
嗯,这部分内容比较多,但理解了三要素之后,后面的章节我们看各家产品对比时会轻松很多。记住:谁、何时、做了什么——这是审计日志的“黄金三角”,缺哪个角,你就等着事后头痛吧。