Audit Log必须精准记录六要素:UserIP、UserID、Action、ResourceID、Status、Timestamp,缺一不可;需物理隔离存储、独立输出、防篡改、长期可查,且所有字段须来自上下文、不可推算或省略。

Audit Log 必须包含的六要素
无论系统类型(Web、DB、OS 或 K8s),合规级 Audit Log 至少要固化以下字段,且全部来自请求或执行上下文,不可推算、不可省略:
-
UserIP:取自
X-Real-IP或X-Forwarded-For首项,不是r.RemoteAddr(后者常为反代 IP) - UserID:认证后的真实用户标识(如 UUID 或内部工号),严禁记录 token、session_id 或匿名 ID
-
Action:语义化操作名,如
file:delete、db:grant、k8s:exec,不写POST /api/v1/delete -
ResourceID:资源唯一抽象标识,如
file:7f3a1e2b、user:abc123;禁用路径(/var/data/xxx.pdf)、禁用自增 ID(id=1024) -
Status:操作结果状态,推荐用 HTTP 状态码(200/403/500)或自定义 error.Code(如
err_perm_denied),不能只写 “success”/“failed” -
Timestamp:统一使用请求进入中间件/入口函数时采集的
time.Time,避免各环节多次取时间导致顺序错乱
三类典型场景的日志记录要点
不同系统层面对 Audit Log 的实现约束不同,但核心逻辑一致:**决策与记录分离、资源绑定不可绕过、敏感字段必须脱敏**。
-
文件类操作(上传/下载/删除):中间件中提取
file_id(从 path 或 query),调用CanAccessFile(userID, fileID, "delete")做鉴权;日志中ResourceID必须是该file_id对应的数据库 UUID,而非 URL 参数原文;临时 presigned URL 要记哈希前缀(sha256(url)[:6]) -
数据库权限变更(GRANT/REVOKE):MySQL 社区版需启用
audit_log插件,并设audit_log_policy=ALL;日志中靠"command_class":"grant"字段识别,用jq 'select(.command_class=="grant")'实时过滤;query字段含明文密码时,必须限制日志文件权限(640)并禁止非授权访问 -
Linux 系统命令执行(sudo/execve):用
auditctl添加规则时,必须指定-F arch=b64 -S execve -k cmd_exec,否则看不到命令参数;监控/usr/bin/sudo比监听所有execve更精准;日志输出到/var/log/audit/audit.log,轮转配置max_log_file_action = rotate,避免单文件过大导致解析失败
日志输出与存储的硬性要求
Audit Log 不是“写进业务日志就行”,它必须物理隔离、独立管理、长期可查。
- 输出流独立:用专用 logger(如 lumberjack)写入单独路径,如
/var/log/app/audit-file.log或/var/log/audit/db-audit.log,不与业务日志混写 - 存储周期明确:等保要求最低保存 180 天,建议设
MaxAge: 180并开启压缩归档 - 访问控制严格:日志目录属主设为专用组(如
auditlog:adm),权限750;禁止普通运维账号直接读取原始文件,仅开放只读 API 或脱敏查询界面 - 防篡改机制:启用日志完整性校验(如 auditd 的
auditctl -e 2锁定规则),或定期生成 SHA256 校验和存至离线存储

















