应逐行读取k8s审计日志并用json.unmarshal解析每行json,避免整文件解析报错;关键告警场景包括删secrets、非管理员创建rbac、失败越权请求及authorization决策为forbid;时间戳以event.timestamp为准,需确保节点ntp同步。

如何用 encoding/json 直接解析 Audit Log 的原始 JSON 行
K8s audit log 是纯文本流,每行一个 JSON 对象,不能直接 json.Unmarshal 整个文件。常见错误是试图读完整文件再解析,结果 panic:invalid character '\n' looking for beginning of value。
正确做法是一行一行读,对每行单独解码:
- 用
bufio.Scanner逐行读取,避免内存爆炸(audit log 动辄 GB 级) - 每行用
json.Unmarshal解到结构体,别用map[string]interface{}—— 后续字段提取和类型判断太容易出错 - 注意:K8s 1.20+ 的 audit log 默认启用
omitEmpty,部分字段可能为null或缺失,结构体字段必须用指针或omitempty标签处理
type AuditEvent struct {
Level string `json:"level"`
Verb string `json:"verb"`
User struct {
Username string `json:"username"`
Groups []string `json:"groups"`
} `json:"user"`
RequestURI string `json:"requestURI"`
ObjectRef struct {
Resource string `json:"resource"`
Name string `json:"name"`
Namespace string `json:"namespace"`
} `json:"objectRef"`
}
哪些字段组合最值得实时告警
不是所有 audit event 都有安全意义。真正该触发告警的,是「高权限操作 + 敏感资源 + 异常上下文」三者叠加。
比如 delete 操作本身不危险,但这些组合要立刻盯住:
立即学习“go语言免费学习笔记(深入)”;
-
verb == "delete"且objectRef.resource == "secrets"(删密钥) -
verb == "create"且user.groups包含"system:masters"以外的组,同时requestURI包含/apis/rbac.authorization.k8s.io/(非管理员创建 RBAC) -
level == "RequestResponse"且responseStatus.code >= 400且user.username不在白名单里(失败的越权尝试)
别漏掉 annotations["authorization.k8s.io/decision"] == "forbid" —— 这是 API Server 明确拒绝的请求,说明有人在试探边界。
time.Now().Sub(event.Timestamp) 延迟大?小心时钟不同步
audit log 的 timestamp 字段是 K8s API Server 写入日志时的时间,不是事件发生时间,但仍是唯一可比的时间锚点。如果你发现 event.Timestamp 比本地时间慢几分钟,别急着优化代码。
真实原因是节点时钟漂移 —— audit log 来自 control plane 节点,而你的解析程序可能跑在 worker 节点或外部机器上。K8s 官方文档明确要求所有节点启用 NTP 同步,否则:audit log 时间戳不可用于精确时序分析。
- 检查各节点
ntpq -p输出,确认 offset - 避免用
time.Since(event.Timestamp)判断“实时性”,它只反映你这台机器和 API Server 的时钟差 - 如需做窗口聚合(比如“5 分钟内 delete secrets > 3 次”),统一用
event.Timestamp做分桶,别混入本地时间
为什么不用 kubectl logs 直接看 audit log
因为 audit log 默认不进容器 stdout,它写在 API Server 宿主机的文件里(如 /var/log/kubernetes/audit.log),kubectl logs 根本看不到。
想拿到数据,只有三种路子:
- 在 API Server 启动参数加
--audit-log-path=/var/log/kubernetes/audit.log,然后用 filebeat/rsyslog 推送到中心存储(推荐) - SSH 登到 master 节点,
tail -f /var/log/kubernetes/audit.log | go run parser.go(仅调试) - 启用 webhook backend,把审计事件发到你自己的 HTTP 服务 —— 但要注意,webhook 失败会导致请求被阻塞(
failurePolicy: Fail默认值)
最后提醒一句:audit log 默认不记录 request body,敏感操作如 create secret 只能看到“谁在什么时候创建了 secret”,看不到内容。真要审计内容,得显式配置 policy 规则并设 omitStages: [],否则连 base64 编码的 data 都不会出现。










