使用 AWS CLI 的aws cloudtrail validate-logs校验 CloudTrail 日志完整性与完整性验证
【免费下载链接】aws-cliUniversal Command Line Interface for Amazon Web Services项目地址: https://gitcode.com/GitHub_Trending/aw/aws-cli
aws cloudtrail validate-logs是 AWS CLI 为 CloudTrail 服务提供的高级命令,用于校验指定时间范围内投递到 S3 的 CloudTrail 日志文件(log file)与摘要文件(digest file)是否被篡改、删除或移动。本文以官方示例文档 awscli/examples/cloudtrail/validate-logs.rst 为核心骨架,结合 awscli/customizations/cloudtrail/validation.py 源码与测试用例,讲解命令的完整用法、全部参数、输出解读以及底层校验原理。读完本文,你将能独立执行日志完整性审计、读懂各类校验输出,并将该校验能力接入自己的安全合规流程。
命令概述:为什么需要校验 CloudTrail 日志
CloudTrail 会将账号内的 API 活动记录以 gzip 压缩的 JSON 日志文件投递到你指定的 S3 存储桶。为保证日志在传输和静态存储过程中的完整性,CloudTrail 提供了Log File Validation(日志文件完整性验证)能力:它会定期生成摘要文件(digest file),其中包含签名、日志文件的 SHA-256 哈希值以及指向前一份摘要的链接,从而形成一条可追溯的“摘要链”。
validate-logs命令利用这条摘要链完成两类校验:
- 检测 CloudTrail 日志文件被修改或删除(通过比对 digest 中记录的 SHA-256 哈希与实际下载内容);
- 检测 CloudTrail 摘要文件被修改或删除(通过 SHA256withRSA 数字签名验证)。
该命令在 CLI 中是一个独立注册的高级命令,不依赖任何底层 CloudTrail API 的同名操作。其注册逻辑见 awscli/customizations/cloudtrail/init.py:inject_commands将CloudTrailValidateLogs实例注入到cloudtrail服务命令表中,键名为validate-logs,与create-subscription、update-subscription一同作为高层命令提供。
命令语法与参数详解
aws cloudtrail validate-logs --trail-arn <value> --start-time <value> [--end-time <value>] [--s3-bucket <value>] [--s3-prefix <value>] [--account-id <value>] [--verbose]参数定义与说明取自源码中的ARG_TABLE(见 validation.py):
| 参数 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|
--trail-arn | 必填 | 无 | 要校验的 Trail 的 ARN,格式如arn:aws:cloudtrail:us-east-1:123456789012:trail/Trail1。源码中的assert_cloudtrail_arn_is_valid会先做格式校验(arn:.+:cloudtrail:.+:\d{12}:trail/.+),格式非法会抛出ValueError。 |
--start-time | 必填 | 无 | UTC 时间戳,校验此时间点及之后投递的日志,格式示例20160129T19:00:00Z(对应源码常量DATE_FORMAT = '%Y%m%dT%H%M%SZ'),也接受如2015-01-08T05:21:42Z的写法。 |
--end-time | 可选 | 当前时间 | UTC 时间戳,校验此时间点及之前投递的日志。若省略则默认取当前时间。若start-time晚于end-time,源码会抛出Invalid time range specified错误。 |
--s3-bucket | 可选 | 自动获取 | 摘要文件所在的 S3 存储桶名。若不指定,CLI 会通过describe_trails自动获取(见 utils.py)。 |
--s3-prefix | 可选 | 自动获取 | 摘要文件的可选 S3 Key 前缀。若不指定,CLI 通过describe_trails自动确定。 |
--account-id | 可选 | 从 ARN 解析 | 用于组织级 Trail(organization trail)时,指定要校验的组织内成员账号 ID。源码会在组织 Trail 且未传该参数时抛出Missing required parameter for organization trail: '--account-id'。 |
--verbose | 可选 | False | 逐条显示每个 digest 文件与日志文件的校验结果(默认只显示汇总)。 |
注意:--start-time与--end-time内部都会被归一化为 UTC 时区(normalize_date),输出统一使用%Y-%m-%dT%H:%M:%SZ格式展示。
实战示例与输出解读
沿用官方示例 validate-logs.rst,校验名为Trail1的 Trail 从 2016 年 1 月 29 日 19:00 UTC 起投递的全部日志:
aws cloudtrail validate-logs --trail-arn arn:aws:cloudtrail:us-east-1:123456789012:trail/Trail1 --start-time 20160129T19:00:00Z执行成功后输出:
Validating log files for trail arn:aws:cloudtrail:us-east-1:123456789012:trail/Trail1 between 2016-01-29T19:00:00Z and 2016-01-29T22:15:43Z Results requested for 2016-01-29T19:00:00Z to 2016-01-29T22:15:43Z Results found for 2016-01-29T19:24:57Z to 2016-01-29T21:24:57Z: 3/3 digest files valid 15/15 log files valid输出结构说明(对应源码_write_startup_text、_write_summary_text、_write_ratio的实现):
- 第一行:声明校验范围,即指定 Trail、请求的起止时间。
--end-time省略时,截止时间即命令执行时刻。 Results requested for ...:再次确认用户请求的时间范围。Results found for ...:实际找到的有效摘要覆盖的时间范围。这个范围不会早于--start-time、不会晚于--end-time(_track_found_times通过max/min裁剪)。x/y digest files valid:摘要文件的校验统计(有效数/总数)。x/y log files valid:日志文件的校验统计。
若校验失败,汇总行会追加 INVALID 计数,例如3/3 digest files valid, 1/15 log files INVALID。在非 verbose 模式下,具体是哪个文件出问题会打印到stderr(_write_status(..., True)),格式为:
Log file s3://bucket/prefix/AWSLogs/... INVALID: hash value doesn't match错误信息采用制表符分隔,便于脚本解析。可能的错误类型包括:
| 错误信息片段 | 含义(对应源码回调) |
|---|---|
INVALID: hash value doesn't match | 日志内容与摘要记录的 SHA-256 不一致,日志被修改(_on_log_invalid) |
INVALID: not found | 摘要/日志在 S3 中缺失(_on_missing_digest/_on_missing_log) |
INVALID: invalid format | 文件无法 gzip 解压或 JSON 解析(InvalidDigestFormat/_on_invalid_log_format) |
INVALID: signature verification failed | 摘要数字签名验证不通过(DigestSignatureError) |
INVALID: public key not found in region ... | 指定区域内找不到对应指纹的公钥 |
INVALID: has been moved from its original location | 摘要中记录的 bucket/key 与实际存储位置不符 |
INVALID: unexpected data after end of compressed stream | gzip 压缩流末尾存在多余数据(_on_log_trailing_data) |
开启--verbose时,每个文件会单独打印一行状态,例如Digest file s3://bucket/.../xxx.json.gz valid与Log file s3://bucket/.../xxx.gz valid,便于逐条核对。
底层工作原理:摘要链、签名与哈希校验
1. 解析 Trail 信息与摘要文件定位
命令从--trail-arn出发,通过create_digest_traverser(validation.py)组装整个校验对象图:
- 若未显式指定
--s3-bucket/--s3-prefix,则调用describe_trails找到匹配 ARN 的 Trail 配置,取出S3BucketName与S3KeyPrefix; - 从 ARN 中解析出 Trail 所在区域(
trail_arn.split(':')[3])与 Trail 名称(trail_arn.split('/')[-1]); - 若未传
--account-id,从 ARN 的split(':')[4]解析账号 ID(见 utils.py)。
摘要文件在 S3 中的命名遵循固定模式(源码_create_digest_key):
AWSLogs/{account_id}/CloudTrail-Digest/{source_region}/{yyyy}/{mm}/{dd}/{account_id}_CloudTrail-Digest_{source_region}_{trail_name}_{home_region}_{YYYYMMDDTHHMMSSZ}.json.gz组织级 Trail 会在{account_id}前追加组织 ID:AWSLogs/{organization_id}/{account_id}/CloudTrail-Digest/...。另外还有一种backfill(回填)摘要,文件名在.json.gz前带有_backfill后缀,用于补录历史数据。validate-logs会在一次运行中同时校验标准摘要与 backfill 摘要(_call中分别以is_backfill=False和is_backfill=True调用两次遍历),并在汇总中分别统计。
DigestProvider.load_all_digest_keys_in_range通过一次带Marker和Prefix的 S3list_objects分页操作抓取时间范围内的所有摘要 Key,并依据文件名中的时间戳做字典序截断,将结果缓存后按标准/backfill 分成两组,避免重复的 S3 列举请求。
2. 获取公钥并验证摘要签名
每个摘要文件都是 gzip 压缩的 JSON,其中包含digestPublicKeyFingerprint、digestEndTime、digestStartTime、digestS3Bucket、digestS3Object、previousDigestSignature、logFiles等字段。PublicKeyProvider通过 CloudTrail 的list_public_keysAPI(StartTime/EndTime)按时间范围拉取公钥列表,并以指纹(Fingerprint)为键建索引。
Sha256RSADigestValidator(validation.py)负责核心签名校验:
- 从 S3 对象元数据(
Metadata)中取出signature与signature-algorithm,缺失即判定无效; - 将公钥做 Base64 解码后按PKCS#1 DER格式加载为 RSA 公钥;
- 构造待签名字符串,其格式严格对齐 Java 参考实现:
digestEndTime\nbucket/object\nSHA256(摘要原始内容)\npreviousDigestSignature(其中上一份签名若为空则以字符串null参与拼接); - 用 SHA256withRSA 算法对签名做验签,失败抛出
DigestSignatureError。
DigestTraverser._traverse_digest_chain按时间倒序从最新摘要开始,沿previousDigestS3Bucket/previousDigestS3Object指针逐份向前回溯整条摘要链;当链上某摘要缺失(NoSuchKey)或无效时,调用对应的回调并尝试在摘要列表中寻找下一条可接续的摘要。若存在on_gap(时间断档),说明该时段 Trail 曾停止记录或日志完整性验证被禁用。
3. 逐份下载日志并比对 SHA-256
验证摘要链后,命令会逐个处理logFiles列表。_download_log(validation.py)的逻辑:
- 对每个日志对象调用 S3
get_object拉取内容; - 流式 gzip 解压(每次读取 2048 字节)并边解压边滚动计算 SHA-256,避免将大文件全部加载进内存;
- 解压结束后若 gzip 流末尾仍有未消费数据,判定为
unexpected data after end of compressed stream; - 将计算出的哈希与摘要中记录的
hashValue比对,一致则计为有效日志,否则判定哈希不匹配。
S3ClientProvider负责按存储桶所在区域创建/复用 S3 客户端:它先通过get_bucket_location获取桶的区域并缓存,再为每个区域缓存一个客户端,避免重复建连。
4. 退出码
命令执行完毕后(_run_main),只要存在任意无效摘要或无效日志(包括 backfill 摘要),进程退出码即为1;全部通过则为0。这一设计让validate-logs可以直接嵌入 CI/CD 或定时脚本中,用退出码驱动告警或阻断流程。
运行前置条件与权限要求
根据源码DESCRIPTION中的明确说明,执行validate-logs需要满足以下条件:
- 在线连接 AWS:命令需要实时调用 CloudTrail、S3(以及组织场景下的 Organizations)API;
- S3 读权限:执行者必须对 Trail 引用的每个存储桶具备
s3:ListObjects、s3:GetObject、s3:GetBucketLocation权限; - 文件未被移动:摘要与日志必须仍在 CloudTrail 投递的原始 S3 位置,被移动过的文件会因“位置不匹配”被判无效;
- 组织级 Trail:需具备
organizations:DescribeOrganization权限,且用--account-id指定待校验的成员账号,否则命令会报缺少参数; - 不得从本地副本校验:已下载到本地磁盘的日志无法用 CLI 校验——命令每次执行都会重新从 S3 下载全部日志(
Log files that have been downloaded to local disk cannot be validated with the AWS CLI)。
另外需注意 digest 链的天然断档:当 Log File Validation 被禁用、CloudTrail 停止记录或 Trail 被删除时,摘要链会在一小时后断裂。例如 1 月 1 日开启、1 月 2 日禁用、1 月 10 日重新开启,则 1 月 3 日至 1 月 9 日投递的日志不会生成摘要文件。此时validate-logs会输出No log files were delivered by CloudTrail between ...的提示而非判定为篡改,属正常行为。
自动化集成建议
结合退出码机制,可将校验接入日常巡检,例如在 crontab 中每晚校验最近 24 小时日志:
aws cloudtrail validate-logs \ --trail-arn arn:aws:cloudtrail:us-east-1:123456789012:trail/Trail1 \ --start-time "$(date -u -d '1 day ago' +%Y%m%dT%H%M%SZ)" \ --verbose脚本侧可直接读取退出码:0表示所有摘要与日志均有效;非0表示存在无效项,此时 stderr 中的INVALID行即为具体违规文件,可用于触发告警或安全工单。
相关命令与延伸阅读
validate-logs依赖 Trail 与日志投递的正常运行,仓库中与其配套的示例文档包括:
- create-trail.rst:创建 Trail(含日志完整性验证的配置入口);
- describe-trails.rst:查看 Trail 的 S3 桶与前缀等配置,理解
validate-logs的自动解析来源; - list-public-keys.rst:查看用于签名验证的 CloudTrail 公钥,与
PublicKeyProvider的调用对应; - start-logging.rst 与 stop-logging.rst:控制日志记录启停,理解 digest 链断档场景。
深入源码可继续阅读:
- 命令与校验核心实现:awscli/customizations/cloudtrail/validation.py;
- 命令注册入口:awscli/customizations/cloudtrail/init.py;
- 工具函数:awscli/customizations/cloudtrail/utils.py;
- 单元测试(覆盖参数解析、遍历、签名校验等场景):tests/unit/customizations/cloudtrail/test_validation.py;
- 功能测试(端到端模拟 S3 读取与输出):tests/functional/cloudtrail/test_validation.py。
测试目录中的create_scenario、MockDigestProvider等辅助构造了包含标准摘要与 backfill 摘要的多种校验场景,是理解各分支行为的最佳样例。
【免费下载链接】aws-cliUniversal Command Line Interface for Amazon Web Services项目地址: https://gitcode.com/GitHub_Trending/aw/aws-cli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考