给 K8s 集群添加审计日志
给 K8s 集群添加审计日志
Kubernetes 审计日志(Audit Log)记录了对 apiserver 的每次 API 请求的元数据,是追溯集群操作、排查问题、满足合规要求的重要手段。默认情况下 kubeadm 部署的集群没有开启审计日志,需要手动配置。
本文记录给 kubeadm 部署的 K8s 集群添加审计日志的完整操作过程。
前置说明
审计日志通过两个东西配合工作:
- 审计策略文件(
audit-policy.yml):定义"哪些请求记、记到什么程度"的规则 - apiserver 启动参数:告诉 apiserver 策略文件在哪、日志写到哪、日志轮转策略等
审计策略中每条规则可以指定一个 level,从低到高:
| Level | 记录内容 |
|---|---|
None | 不记录 |
Metadata | 请求的元数据(用户、时间、资源、动作等),不含请求体和响应体 |
Request | 元数据 + 请求体 |
RequestResponse | 元数据 + 请求体 + 响应体 |
合理使用 None 过滤掉系统组件的高频只读请求,可以大幅减少日志量,避免审计日志本身成为存储负担。
操作步骤
1. 创建审计策略文件
在所有 master 节点上创建 /etc/kubernetes/audit-policy.yml:
apiVersion: audit.k8s.io/v1
kind: Policy
# Don't generate audit events for all requests in RequestReceived stage.
omitStages:
- "RequestReceived"
rules:
# ===============================================================
# 1. 忽略系统高频访问,减少噪音与日志量
# ===============================================================
- level: None
users:
- system:kube-proxy
- system:apiserver
- system:kube-controller-manager
- system:kube-scheduler
verbs: ["get", "list", "watch"]
- level: None
userGroups: ["system:nodes"]
verbs: ["get", "list", "watch"]
- level: None
nonResourceURLs:
- /healthz*
- /version
- /metrics
- /swagger*
- level: None
resources:
- group: "" # core
resources: ["events"]
#丢掉 operator 的操作
- level: None
users:
- "system:serviceaccount:minio-operator:minio-operator"
- "system:serviceaccount:monitor:grafana-operator"
- "system:serviceaccount:monitor:prometheus-operator"
- "system:serviceaccount:monitor:prometheus-adapter"
- "system:serviceaccount:monitor:victoria-metrics-operator"
- "system:serviceaccount:tigera-operator:tigera-operator"
- "system:serviceaccount:kubesphere-system:kubesphere"
- "system:serviceaccount:juicefs:juicefs-csi-controller-sa"
- "system:serviceaccount:juicefs:juicefs-csi-dashboard-sa"
- "system:serviceaccount:juicefs:juicefs-csi-node-sa"
- "system:serviceaccount:csi-driver-nfs:csi-nfs-controller-sa"
- "system:serviceaccount:csi-driver-nfs:csi-nfs-node-sa"
- "system:serviceaccount:longhorn-system:longhorn-service-account"
- "system:serviceaccount:longhorn-system:longhorn-support-bundle"
- "system:serviceaccount:longhorn-system:longhorn-ui-service-account"
- "system:serviceaccount:rocketmq-operator:rocketmq-operator"
- "system:serviceaccount:nvidia-gpu-operator:gpu-operator"
- "system:serviceaccount:kubeai:kubeai"
# 丢弃 kube-system 与 kube-node-lease 下的 leases update
- level: None
resources:
- group: "coordination.k8s.io"
resources: ["leases"]
namespaces:
- kube-system
- kube-node-lease
# ===============================================================
# 2. 对高危操作(删除等)记录完整请求
# ===============================================================
- level: Request
verbs: ["delete", "deletecollection"]
resources:
- group: "" # core
resources: ["namespaces", "nodes"]
- group: "apps"
resources: ["deployments", "daemonsets", "statefulsets"]
- group: "batch"
resources: ["cronjobs"]
# 针对特定命名空间的关键服务记录,如 kube-system 与含 mysql 的命名空间
namespaces:
- kube-system
- mysql
- redis
- longhorn-system
- minio
- mongodb
- bkdb
- calico-system
# ===============================================================
# 3. 对敏感资源仅记录元数据(防止泄露)
# ===============================================================
- level: Metadata
verbs: ["create", "update", "patch", "delete"]
resources:
- group: "" # core
resources: ["secrets", "configmaps", "serviceaccounts"]
- group: "authentication.k8s.io"
resources: ["tokenreviews"]
- group: "certificates.k8s.io"
resources: ["certificatesigningrequests"]
# ===============================================================
# 4. 常规资源(仅记录系统与关键业务命名空间的元数据)
# ===============================================================
- level: Metadata
verbs: ["create", "update", "patch"]
namespaces:
- kube-system
resources:
- group: "" # core
- group: "apps"
- level: None
verbs: ["get","list","watch"]
# ===============================================================
# 5. 兜底规则:记录所有其他请求的元数据
# ===============================================================
- level: Metadata
策略逻辑说明:
- 第 1 段:过滤掉系统组件(kube-proxy、controller-manager、scheduler、kubelet)的只读操作,以及健康检查、metrics 等非资源 URL 的访问;过滤掉各 operator 的日常轮询;过滤掉 kube-system 和 kube-node-lease 下的 lease 更新(心跳类操作,量极大且无审计价值)
- 第 2 段:对关键命名空间中的高危操作(delete/deletecollection)记录到
Request级别,包含请求体,方便回溯"谁删了什么" - 第 3 段:对 secrets、configmaps、serviceaccounts 等敏感资源只记
Metadata,不记录请求体内容,避免在审计日志中泄露敏感信息 - 第 4 段:kube-system 命名空间下的常规写操作记
Metadata - 第 5 段:兜底,所有未被前面规则匹配的请求都记
Metadata
注意:第 1 段中过滤的 operator ServiceAccount 列表需要根据你集群实际安装的组件来调整。可以用
kubectl get serviceaccounts --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}'查看集群中所有的 ServiceAccount,把那些高频轮询的 operator SA 加进去。
2. 修改 kube-apiserver 配置
在所有 master 节点上编辑 /etc/kubernetes/manifests/kube-apiserver.yaml,需要修改两处。
2.1 添加启动参数
在 spec.containers[0].command 列表中,找到 kube-apiserver 后面那一堆 --xxx=yyy 参数,追加以下内容:
- --audit-log-format=json
- --audit-log-maxage=7
- --audit-log-maxbackup=10
- --audit-log-maxsize=100
- --audit-log-path=/var/log/kubernetes/audit.log
- --audit-policy-file=/etc/kubernetes/audit-policy.yml
参数含义:
| 参数 | 说明 |
|---|---|
--audit-policy-file | 审计策略文件路径 |
--audit-log-path | 审计日志输出路径 |
--audit-log-format | 日志格式,json 或 legacy,推荐 json |
--audit-log-maxage | 保留多少天的旧日志文件 |
--audit-log-maxbackup | 保留多少个旧日志文件 |
--audit-log-maxsize | 单个日志文件最大大小(MB),超过后轮转 |
2.2 添加卷挂载
在 spec.containers[0].volumeMounts 中添加:
volumeMounts:
- mountPath: /etc/kubernetes
name: audit
- mountPath: /var/log/kubernetes
name: audit-log
在 spec.volumes 中添加:
volumes:
- hostPath:
path: /etc/kubernetes
type: DirectoryOrCreate
name: audit
- hostPath:
path: /var/log/kubernetes
type: DirectoryOrCreate
name: audit-log
这里将宿主机的 /etc/kubernetes 和 /var/log/kubernetes 挂载到 apiserver 容器内,使得策略文件和日志文件都落在宿主机上。DirectoryOrCreate 表示如果目录不存在会自动创建。
kube-apiserver 是以 static pod 的方式运行的,它的配置文件在
/etc/kubernetes/manifests/下。修改这个文件后,kubelet 会检测到变化并自动重启 apiserver pod,不需要手动删除 pod。
3. 重启 kubelet
修改完所有 master 节点后,在每个 master 节点上重启 kubelet:
systemctl restart kubelet
⚠️ 注意:重启会导致 apiserver 短暂不可用
kubelet 重启后会重新拉起 apiserver static pod,期间该节点的 apiserver 会有一段不可用时间(通常几十秒)。虽然多 master 集群有高可用,但仍然建议:
- 在低峰期操作
- 逐台 master 操作,等一台的 apiserver 恢复正常后再操作下一台,不要同时重启所有 master
- 操作前确认集群中没有正在进行的关键任务(如正在进行的部署、扩缩容等)
- 如果集群只有单 master,apiserver 重启期间所有
kubectl命令都会失败,需要提前告知相关团队
4. 验证
重启完成后,确认审计日志已经产生:
# 查看审计日志文件
ls -lh /var/log/kubernetes/audit.log
# 查看最新的审计记录
tail -1 /var/log/kubernetes/audit.log | jq .
正常情况下,执行一个 kubectl 命令后就能在审计日志中看到对应的记录。一条审计日志的 JSON 结构大致如下:
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/default/pods",
"verb": "list",
"user": {
"username": "kubernetes-admin",
"groups": ["system:masters", "system:authenticated"]
},
"sourceIPs": ["10.0.0.1"],
"objectRef": {
"resource": "pods",
"namespace": "default"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2026-08-24T02:00:00.000000Z",
"stageTimestamp": "2026-08-24T02:00:00.100000Z"
}
关键字段:
user.username:谁发起的请求verb:什么操作(get/list/create/update/patch/delete)objectRef:操作的目标资源sourceIPs:请求来源 IPresponseStatus.code:响应状态码requestReceivedTimestamp/stageTimestamp:请求时间和完成时间
日志轮转说明
通过 --audit-log-maxage=7、--audit-log-maxbackup=10、--audit-log-maxsize=100 三个参数,apiserver 会自动管理日志轮转:
- 单个日志文件达到 100MB 时触发轮转
- 最多保留 10 个旧文件
- 超过 7 天 的旧文件自动删除
也就是说审计日志最多占用约 100MB × 11 = 1.1GB 的磁盘空间,不会无限增长。如果集群操作量很大、审计日志增长很快,可以适当调大 maxbackup 和 maxage。
总结
整个操作的核心就是两件事:
- 放一个策略文件到所有 master 节点的
/etc/kubernetes/audit-policy.yml - 改 apiserver 配置,加上审计参数和卷挂载
策略文件是关键——好的策略能在"审计覆盖面"和"日志量"之间取得平衡。核心思路是:高危操作记详细、敏感资源记元数据、系统噪音全过滤、兜底规则保底。