日志存储与检索:S3 桶存储策略、CloudWatch Logs 订阅与查询
到了这一步,你手头应该有源源不断的 KMS 审计日志流了。但日志这东西,存不好等于白查。我见过太多案例——日志全在,可要拉出来分析时,不是权限不对就是被生命周期策略删光了。这一节咱们就聊聊怎么把日志安顿好,并且能在需要的时候秒级找出来。
S3 桶存储策略:不只是把日志丢进去
很多人以为日志往 S3 一存就完事了。其实不然。KMS 审计日志的敏感度很高,谁访问过哪个密钥、从哪里调用的,这些信息一旦泄露,攻击者就能摸清你的加密资产全貌。我个人的习惯是:日志桶一定要单独建,不跟其他数据混用。
生命周期管理
审计日志有合规保留期,比如金融行业要求至少保留 7 年。你不能让它无限膨胀,也不能提前删掉。配置生命周期时,建议这样搞:
- 过渡:日志生成 30 天后,自动转为 Glacier 或 Deep Archive,降低存储成本。
- 过期删除:保留期满后自动清理,避免手动运维。
- 注意:千万别忘了加一条“禁止删除”的桶策略,我见过有人误删了整个桶,后来靠备份恢复了两天。
| 存储类别 | 适用阶段 | 成本 | 检索速度 |
|---|---|---|---|
| S3 Standard | 0-30 天内频繁查询 | 中等 | 毫秒级 |
| S3 Glacier | 30 天 - 7 年归档 | 极低 | 数分钟到数小时 |
| S3 Glacier Deep Archive | 7 年以上长期保存 | 最低 | 12 小时内 |
嗯,这里要注意:如果你需要经常回溯半年前的日志,建议保留一个“热副本”或者使用 S3 Intelligent-Tiering,否则每次从 Glacier 取数据都得等很久,排查时急死人。
桶策略与加密
桶策略是安全的第一道门。我通常会用一条显式拒绝策略,只允许特定 IAM 角色(比如安全专用角色)访问,同时禁止公共访问。还要开启S3 服务端加密(SSE-S3 或 SSE-KMS),避免日志明文存储。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyPublicRead",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::audit-logs-bucket/*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
另外,记得开启S3 访问日志,记录谁对这个桶做了什么操作。你觉得麻烦?我吃过一次亏——有次排查日志发现桶里莫名多了几个文件,就是因为没开访问日志,导致溯源花了整整两天。
CloudWatch Logs 订阅与查询
KMS 审计日志默认会送到 CloudWatch Logs 的 /aws/kms/ 日志组里。但光躺着不行,你得让它流动起来。
订阅过滤器:把日志实时推出去
订阅过滤器的本质是一个“水龙头”,它把 CloudWatch Logs 的日志流实时复制到下游目的地。我一般会考虑三种目的地:
- Lambda 函数:适合做自定义处理,比如格式转换、脱敏、推送告警。
- Amazon Elasticsearch Service(现改名为 OpenSearch):适合全文搜索和可视化分析。
- Kinesis Data Firehose:适合大规模分发到 S3、Redshift、Splunk 等。
你会问:选哪种好?我举个例子:假如你们安全团队习惯用 Kibana 看日志,那就直接推到 OpenSearch。如果只需要长期存储和偶尔用 Athena 查,那推到 S3 就够了。我个人做过一个项目,因为流量太大,直接推 S3 成本太高,后来加了 Firehose 做压缩和分桶,省了 40% 的费用。
# 示例:配置订阅过滤器到 Lambda(AWS CLI)
aws logs put-subscription-filter \
--log-group-name "/aws/kms/key" \
--filter-name "KMSLogForward" \
--filter-pattern "" \
--destination-arn "arn:aws:lambda:us-east-1:123456789012:function:KMSLogProcessor" \
--role-arn "arn:aws:iam::123456789012:role/MySubscriptionRole"
CloudWatch Logs Insights:不建索引也能搜
如果你不想额外搭建 Elasticsearch,CloudWatch Logs Insights 就是个救命稻草。它基于查询引擎,能直接跑在原始日志上,不需要预先建索引。
我常用的几个查询模式:
- 查某时间段内所有 KMS 操作:
fields @timestamp, @message | filter @logStream like /key/ | sort @timestamp desc - 统计调用次数最多的用户:
stats count() by userIdentity.arn - 定位“密钥被禁用”事件:
fields @timestamp, userIdentity.arn, eventName | filter eventName == "DisableKey"
嗯,这里有个小坑:Logs Insights 查询的数据量是按扫描的日志量计费的。如果你不限制时间范围,一次查询扫描几十 G 日志,账单可就不好看了。我建议每次查询都加上 @timestamp >= '2025-01-01T00:00:00Z' and @timestamp < '2025-01-02T00:00:00Z' 这种精确范围。
小技巧:如果你发现查询超时或太慢,可以尝试把日志组按小时分桶。CloudWatch Logs 支持跨日志组查询,但尽量保持每个组的数据量不超过 10GB,否则性能会大幅下降。
一张图看懂日志存储与检索架构
说实话,光靠文字很难把整个链路串起来。下面这张图总结了我们刚才讲的所有组件之间的关系。
核心要点:S3 桶要有明确的生命周期和加密策略,CloudWatch Logs 订阅过滤器是日志分发的枢纽,而 Logs Insights 适合临时性快速排查。三者配合好了,你才能做到“存得住、找得着、查得快”。
避坑指南:我曾经踩过的几个坑
- 订阅过滤器权限不足:创建订阅时,如果你的 Lambda 或 Firehose 角色没有
logs:PutLogEvents权限,日志根本推不过去。我被坑过一次,折腾了两个小时才发现是角色没配。 - S3 桶跨区域复制导致日志顺序乱:如果你用跨区域复制做灾备,源区域的日志和复制后的日志时间戳可能不是全局有序的。排查时要注意区分区域。
- Logs Insights 查询超时:默认查询超时时间是 15 分钟,数据量大时很容易超时。我现在的做法是先用
head 100看看数据格式,再精确限制时间范围。
警告:千万不要把 KMS 审计日志的 S3 桶设置成公开可读,哪怕只是“不小心”勾选了。我见过有公司因为桶权限配置错误,导致几百万条密钥操作记录泄露到公网,后续合规罚款高达数百万美元。
好了,关于日志存储与检索就先聊这么多。我觉得关键就一句话:想清楚你要怎么用这些日志,再决定存哪里、怎么存。下一块内容我们聊聊更具体的排查场景——怎么从这些日志里揪出“异常行为”。