给 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:请求来源 IP
  • responseStatus.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。

总结

整个操作的核心就是两件事:

  1. 放一个策略文件到所有 master 节点的 /etc/kubernetes/audit-policy.yml
  2. 改 apiserver 配置,加上审计参数和卷挂载

策略文件是关键——好的策略能在"审计覆盖面"和"日志量"之间取得平衡。核心思路是:高危操作记详细、敏感资源记元数据、系统噪音全过滤、兜底规则保底。