020-K8S-审计

一、概述

Kubernetes 审计(Auditing) 功能提供了与安全相关的、按时间顺序排列的记录集, 记录每个用户、使用 Kubernetes API 的应用以及控制面自身引发的活动(所有访问kube-apiserver服务的客户端)。

审计功能使得集群管理员能够回答以下问题:

  • 发生了什么?
  • 什么时候发生的?
  • 谁触发的?
  • 活动发生在哪个(些)对象上?
  • 在哪观察到的?
  • 它从哪触发的?
  • 活动的后续处理行为是什么?

这对平台管理者来说十分重要,能够回答一些在故障时候出现的问题。哪个用户,从哪个ip上,发起了什么请求。如删除了一个命名空间,导致这个命名空间下的所有pod被回收,对故障进行复盘。

Kubernetes 审计功能由 kube-apiserver 服务提供。每个请求在不同执行阶段都会生成审计事件;这些审计事件会根据特定策略被预处理并写入后端。策略确定要记录的内容,当前的后端支持日志文件和 webhook。

每个请求都可被记录其相关的 阶段(stage)。已定义的阶段有:

  • RequestReceived - 此阶段对应审计处理器接收到请求后,并且在委托给处理器处理之前生成的事件。
  • ResponseStarted - 在响应消息的头部发送后,响应消息体发送前生成的事件。 只有长时间运行的请求(例如 watch)才会生成这个阶段。
  • ResponseComplete - 当响应消息体完成并且没有更多数据需要传输的时候。
  • Panic - 当 panic 发生时生成。

审计的4个阶段

审计日志记录功能会增加 API server 的内存消耗,因为需要为每个请求存储审计所需的某些上下文。 此外,内存消耗取决于审计日志记录的配置。

Kubernetes 审计是一种监控和记录 Kubernetes 集群中资源操作的方法,用于确保集群的安全性和符合性。通过审计,管理员可以跟踪对集群资源的访问和修改,以便在发生安全事件时进行调查和响应。Kubernetes 提供了审计日志记录的框架,允许管理员自定义审计策略,以确定哪些资源操作应该被记录。

二、审计策略简介

审计策略定义了关于应记录哪些事件以及应包含哪些数据的规则。 审计策略对象结构定义在 audit.k8s.io API 组。 处理事件时,将按顺序与规则列表进行比较。第一个匹配规则设置事件的审计级别(Audit Level),审计级别(Audit Level)可以理解为记录什么? 已定义的审计级别有:

  • None - 符合这条规则的日志将不会记录。
  • Metadata - 记录请求的元数据(请求的用户、时间戳、资源、动词等等), 但是不记录请求或者响应的消息体。
  • Request - 记录事件的元数据和请求的消息体,但是不记录响应的消息体。 这不适用于非资源类型的请求。
  • RequestResponse - 记录事件的元数据,请求和响应的消息体。这不适用于非资源类型的请求。

你可以使用 --audit-policy-file 标志将包含策略的文件传递给 kube-apiserver。 如果不设置该标志,则不记录事件。 注意 rules 字段 必须 在审计策略文件中提供。没有(0)规则的策略将被视为非法配置。

审计策略定义了哪些资源操作应该被审计以及审计记录的格式。在 Kubernetes 中,审计策略通过 Admission Controllers 实现,可以通过 Webhook 的方式进行集成。审计策略可以根据资源的类型、操作的类型和用户身份等信息进行过滤,以满足不同场景下的审计需求。

三、启用审计

1. 创建审计策略文件

# 创建文件夹,用于存放审计日志策略文件,和日志文件
$ mkdir /etc/kubernetes/audit-policy /etc/kubernetes/audit-logs

# 编辑审计策略(仅是示例)
$ cat /etc/kubernetes/audit-policy/policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # 设置机密资源的审计日志级别为Metadata
  - level: Metadata
    resources:
      - group: ""
        resources: ["pods"]
    namespaces: ["default"]             # 默认就是default命名空间
  # 设置节点的审计日志级别为RequestResponse
  - level: RequestResponse
    userGroups: ["system:nodes"]
  # 对于其他内容,不要记录任何内容
  - level: None

2. 添加审计日志

审计日志参数如下:

  • –audit-log-path 指定用来写入审计事件的日志文件路径。不指定此标志会禁用日志后端。- 意味着标准化
  • –audit-log-maxage 定义保留旧审计日志文件的最大天数
  • –audit-log-maxbackup 定义要保留的审计日志文件的最大数量
  • –audit-log-maxsize 定义审计日志文件轮转之前的最大大小(兆字节)
# 修改 kube-apiserver.yaml,添加添加审计日志配置
$ vim /etc/kubernetes/manifests/kube-apiserver.yaml

# 配置审计日志参数
spec:
  containers:
  - command:
    - --audit-policy-file=/etc/kubernetes/audit-policy/policy.yaml	# 审计策略文件
    - --audit-log-path=/etc/kubernetes/audit-logs/audit.log			# 审计日志文件
    - --audit-log-maxsize=10										# 单个日志最大 10MB
    - --audit-log-maxbackup=20										# 最多保留20个日志文件


# 挂载存储卷,将审计策略文件和日志文件挂载到容器内的指定路径
volumeMounts:
- mountPath: /etc/kubernetes/audit-policy/policy.yaml
  name: audit-policy
  readOnly: true
- mountPath: /etc/kubernetes/audit-logs
  name: audit-logs
  readOnly: false


# 声明挂载卷
  volumes:
  - name: audit-policy
    hostPath:
      path: /etc/kubernetes/audit-policy/policy.yaml
      type: File
  - name: audit-logs
    hostPath:
      path: /etc/kubernetes/audit-logs
      type: DirectoryOrCreate

配置审计日志参数

挂载存储卷

声明挂载卷

保存 kube-apiserver.yaml 文件后,等待生效(为了保险起见也可以重启 kubelet )。

$ systemctl daemon-reload
$ systemctl restart kubelet

3. 查看审计日志

3.1 创建测试 Pod

$ kubectl run audit-demo --image=nginx:1.29.0 --image-pull-policy=IfNotPresent

3.2 查看日志

$ tail -1000f /etc/kubernetes/audit-logs/audit.log | grep audit-demo -A 10

{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"3943a216-8452-45d9-a127-6ab2e58e4fa0","stage":"RequestReceived","requestURI":"/api/v1/namespaces/default/pods/audit-demo","verb":"get","user":{"username":"system:serviceaccount:kube-system:calico-cni-plugin","uid":"3d9a2a4d-8207-4e57-ae9e-23e4e1a943be","groups":["system:serviceaccounts","system:serviceaccounts:kube-system","system:authenticated"]},"sourceIPs":["10.20.1.140"],"userAgent":"calico/v0.0.0 (linux/amd64) kubernetes/$Format","objectRef":{"resource":"pods","namespace":"default","name":"audit-demo","apiVersion":"v1"},"requestReceivedTimestamp":"2025-08-10T08:05:13.977141Z","stageTimestamp":"2025-08-10T08:05:13.977141Z"}
{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"3943a216-8452-45d9-a127-6ab2e58e4fa0","stage":"ResponseComplete","requestURI":"/api/v1/namespaces/default/pods/audit-demo","verb":"get","user":{"username":"system:serviceaccount:kube-system:calico-cni-plugin","uid":"3d9a2a4d-8207-4e57-ae9e-23e4e1a943be","groups":["system:serviceaccounts","system:serviceaccounts:kube-system","system:authenticated"]},"sourceIPs":["10.20.1.140"],"userAgent":"calico/v0.0.0 (linux/amd64) kubernetes/$Format","objectRef":{"resource":"pods","namespace":"default","name":"audit-demo","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2025-08-10T08:05:13.977141Z","stageTimestamp":"2025-08-10T08:05:13.979410Z","annotations":{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding \"calico-cni-plugin\" of ClusterRole \"calico-cni-plugin\" to ServiceAccount \"calico-cni-plugin/kube-system\""}}
{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"8c1f6ae3-edb9-41cf-a73a-633ad406d270","stage":"RequestReceived","requestURI":"/api/v1/namespaces/default/pods/audit-demo","verb":"get","user":{"username":"system:serviceaccount:kube-system:calico-cni-plugin","uid":"3d9a2a4d-8207-4e57-ae9e-23e4e1a943be","groups":["system:serviceaccounts","system:serviceaccounts:kube-system","system:authenticated"]},"sourceIPs":["10.20.1.140"],"userAgent":"calico/v0.0.0 (linux/amd64) kubernetes/$Format","objectRef":{"resource":"pods","namespace":"default","name":"audit-demo","apiVersion":"v1"},"requestReceivedTimestamp":"2025-08-10T08:05:13.984952Z","stageTimestamp":"2025-08-10T08:05:13.984952Z"}

3.3 日志解析

审计日志解析

四、审计策略案例实践

# 创建命名空间
$ kubectl create ns audit
namespace/audit created

$ kubectl get ns | grep audit
audit             Active   11m

1. 只记录 audit 命名空间里的日志

修改审计策略,现在配置只记录某个命名空间里的审计日志,namespaces: [“audit”] 表示只记录 audit 命名空间里的日志。

apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:                     # 记录审计阶段为:ResponseStarted
  - "ResponseStarted"
rules:
  - level: Metadata             # 设置机密资源的审计日志级别为Metadata
    resources:
      - group: ""
    namespaces: ["audit"]       # 只记录该命名空间的日志

重启 kubelet , 让策略生效

$ systemctl daemon-reload && systemctl restart kubelet

清空 audit.log

$ > /etc/kubernetes/audit-logs/audit.log

查看审计日志,只记录了audit 命名空间的操作,default 命名空间的操作没有记录。

$ tail -100f /etc/kubernetes/audit-logs/audit.log
{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"RequestResponse","auditID":"2205c680-4877-4498-b40f-459b2779afa8","stage":"ResponseComplete","requestURI":"/apis/node.k8s.io/v1/runtimeclasses?allowWatchBookmarks=true\u0026resourceVersion=2798746\u0026timeout=9m18s\u0026timeoutSeconds=558\u0026watch=true","verb":"watch","user":{"username":"system:node:k8s-master01","groups":["system:nodes","system:authenticated"]},"sourceIPs":["10.20.1.139"],"userAgent":"kubelet/v1.29.15 (linux/amd64) kubernetes/0d0f172","objectRef":{"resource":"runtimeclasses","apiGroup":"node.k8s.io","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2025-08-11T02:06:30.212676Z","stageTimestamp":"2025-08-11T02:08:29.706126Z","annotations":{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":""}}

{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"RequestResponse","auditID":"4a54a59a-fa98-43e7-a004-f14b9d4bd6eb","stage":"ResponseComplete","requestURI":"/api/v1/nodes?allowWatchBookmarks=true\u0026fieldSelector=metadata.name%3Dk8s-master01\u0026resourceVersion=2798755\u0026timeout=6m45s\u0026timeoutSeconds=405\u0026watch=true","verb":"watch","user":{"username":"system:node:k8s-master01","groups":["system:nodes","system:authenticated"]},"sourceIPs":["10.20.1.139"],"userAgent":"kubelet/v1.29.15 (linux/amd64) kubernetes/0d0f172","objectRef":{"resource":"nodes","name":"k8s-master01","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2025-08-11T02:06:31.945964Z","stageTimestamp":"2025-08-11T02:08:29.706028Z","annotations":{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":""}}

{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"RequestResponse","auditID":"9dcf6bb7-51f5-45d0-a7b6-f352e455c736","stage":"ResponseComplete","requestURI":"/api/v1/services?allowWatchBookmarks=true\u0026resourceVersion=2798746\u0026timeout=8m41s\u0026timeoutSeconds=521\u0026watch=true","verb":"watch","user":{"username":"system:node:k8s-master01","groups":["system:nodes","system:authenticated"]},"sourceIPs":["10.20.1.139"],"userAgent":"kubelet/v1.29.15 (linux/amd64) kubernetes/0d0f172","objectRef":{"resource":"services","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2025-08-11T02:06:29.952827Z","stageTimestamp":"2025-08-11T02:08:29.706023Z","annotations":{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":""}}

2. 只记录 audit 命名空间的 pods 操作日志

修改审计策略,该审计策略表示只记录 audit 命名空间的 pods 操作

apiVersion: audit.k8s.io/v1     # 只记录audit命名空间的pods操作日志
kind: Policy
omitStages:                     # 记录审计阶段为:ResponseStarted
  - "ResponseStarted"
rules:
  - level: Metadata             # 设置机密资源的审计日志级别为Metadata
    resources:
      - group: ""
        resources: ["pods"]
    namespaces: ["audit"]       # 只记录该命名空间的日志

3. 只记录 audit 命名空间的 pods,services,deployments 操作日志

编辑审计策略文件,表示只记录 audit 命名空间的 pods,services,deployments 操作,因为 deployments 的 apiVersion 的父级为 apps,所以需要 group: “apps” 。

apiVersion: audit.k8s.io/v1     # 只记录audit命名空间的pods,services,deployments操作日志
kind: Policy
omitStages:                     # 记录审计阶段为:ResponseStarted
  - "ResponseStarted"
rules:
  - level: Metadata             # 设置机密资源的审计日志级别为Metadata
    resources:
      - group: ""
        resources: ["pods","services"]
      - group: "apps"
        resources: ["deployments"]
    namespaces: ["audit"]       # 只记录该命名空间的日志

4. 只记录 audit 命名空间的 pods 操作,审计级别为 RequestResponse

编辑审计策略文件,表示只记录 audit 命名空间的 pods 操作,审计级别为 RequestResponse,记录事件的元数据,请求和响应的消息体。

apiVersion: audit.k8s.io/v1     # 只记录audit命名空间的pods,services,deployments操作日志
kind: Policy
omitStages:                     # 记录审计阶段为:ResponseStarted
  - "ResponseStarted"
rules:
  - level: RequestResponse             # 设置机密资源的审计日志级别为 RequestResponse
    resources:
      - group: ""
        resources: ["pods"]
    namespaces: ["audit"]       # 只记录该命名空间的日志

5. 只记录 audit 命名空间下的 dev 用户的 pods 操作,其他用户操作不记录

参考:https://georgechan95.github.io/blog/424f1119.html

编辑审计策略文件,设置审计策略:只记录 audit 命名空间下的 george 用户的 pods 操作,其他用户的操作不记录。

apiVersion: audit.k8s.io/v1     # 只记录audit命名空间的pods,services,deployments操作日志
kind: Policy
omitStages:                     # 记录审计阶段为:ResponseStarted
  - "ResponseStarted"
rules:
  - level: Metadata             # 设置机密资源的审计日志级别为 Metadata
    users: ["george"]           # 只记录 george 用户的操作
    resources:
      - group: ""
        resources: ["pods"]
    namespaces: ["audit"]       # 只记录该命名空间的日志

6. rules 规则是从上往下匹配的,第一条规则已经匹配了,第二条就不匹配了

编辑审计策略文件,有两条策略,一条是:apiVersion 为 group: “” 的操作不记录日志,另外一条是:只记录 audit 命名空间下 george 用户的 pod 操作。

apiVersion: audit.k8s.io/v1 # This is required.
kind: Policy
# Don't generate audit events for all requests in RequestReceived stage.
omitStages:
  - "ResponseStarted"
rules:
  # apiVersion为 group: "" 的操作不记录日志
  - level: None
    resources:
    - group: ""
  # 只记录 audit 命名空间下 george 用户的 pod 操作
  - level: Metadata
    users: ["george"]
    resources:
    - group: ""
      resources: ["pods"]
    namespaces: ["audit"]

查看审计日志,可以发现在客户端使用 george 用户查询 pod 和使用管理员用户查看 pod 都没有生成审计日志,rules 规则是从上往下匹配的,第一条规则已经匹配了,第二条就不匹配了。

7. 在 Metadata 级别为所有请求生成日志

编辑审计策略文件,在 Metadata 级别为所有请求生成日志。

apiVersion: audit.k8s.io/v1beta1
kind: Policy
rules:
- level: Metadata

五、总结

实施审计策略可以帮助管理员监控和记录集群中的资源操作,确保集群的安全性和符合性。通过启用审计 Admission Controller 和配置相应的审计策略,我们可以灵活地控制审计记录的格式和范围。

参考链接

https://kubernetes.io/zh-cn/docs/tasks/debug/debug-cluster/audit/

https://kubernetes.io/zh-cn/docs/reference/config-api/apiserver-audit.v1/#audit-k8s-io-v1-Event

https://www.cnblogs.com/renshengdezheli/p/18266120

https://www.cnblogs.com/tencent-cloud-native/p/14097545.html


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com