初次 QA
起因:2302 班级以为同学在技术交流群中探讨能够监控一些资源修改的问题
回答:可以开启审计日志记录,脚本捕捉事件筛选也可,通过 goclient 监听也可, Aqua Security、Sysdig Secure 这些产品也支持
关于此次回答基于 Auditing 的方式,将操作通过实验的方式进行演示
基本概念
Kubernetes 审计日志提供了与安全相关的、按时间顺序排列的记录集, 记录每个用户、使用 Kubernetes API 的应用以及控制面自身引发的活动。
Auditing 的来龙去脉?
审计记录最初产生于 kube-apiserver 内部。每个请求在不同执行阶段都会生成审计事件;这些审计事件会根据特定策略 被预处理并写入后端。策略确定要记录的内容和用来存储记录的后端。 当前的后端支持日志文件和 webhook。
Auditing 阶段
阶段 | 描述 |
---|---|
RequestReceived | 此阶段对应审计处理器接收到请求后,并且在委托给其余处理器之前生成的事件。 |
ResponseStarted | 在响应消息的头部发送后,响应消息体发送前生成的事件。 只有长时间运行的请求(例如 watch)才会生成这个阶段。 |
ResponseComplete | 当响应消息体完成并且没有更多数据需要传输的时候。 |
Panic | 当 panic 发生时生成。 |
审计策略
已定义的审计级别有:
审计日志 | 描述 |
---|---|
None | 符合这条规则的日志将不会记录。 |
Metadata | 记录请求的元数据(请求的用户、时间戳、资源、动词等等), 但是不记录请求或者响应的消息体。 |
Request | 记录事件的元数据和请求的消息体,但是不记录响应的消息体。 这不适用于非资源类型的请求。 |
RequestResponse | 记录事件的元数据,请求和响应的消息体。这不适用于非资源类型的请求。 |
实验记录
环境说明
## OS
[root@k8s-master01 audit-logs]# cat /etc/redhat-release
Rocky Linux release 9.3 (Blue Onyx)
## kubernetes Version
[root@k8s-master01 audit-logs]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready control-plane 25d v1.29.1
k8s-node01 Ready <none> 25d v1.29.1
k8s-node02 Ready <none> 25d v1.29.1
常见审计策略文件
# vi /etc/kubernetes/audit-policy/policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 设置机密资源的审计日志级别为Metadata
- level: Metadata
resources:
- group: ""
resources: ["secrets"]
# 设置节点的审计日志级别为RequestResponse
- level: RequestResponse
userGroups: ["system:nodes"]
# 对于其他内容,不要记录任何内容
- level: None
注意 rules 字段必须在审计策略文件中提供。没有(0)规则的策略将被视为非法配置
# 当然我们也可以使用最低限度的审计策略文件在 Metadata 级别记录所有请求
# 在 Metadata 级别为所有请求生成日志
# apiVersion: audit.k8s.io/v1beta1
# kind: Policy
# rules:
# - level: Metadata
更多Policy配置请参考:https://kubernetes.io/zh-cn/docs/reference/config-api/apiserver-audit.v1/#audit-k8s-io-v1-Policy
# 记录 deployment 变化的方式
# apiVersion: audit.k8s.io/v1
# kind: Policy
# rules:
# - level: Metadata
# resources:
# - group: apps
# resources: ["deployments"]
# verbs: ["create", "update", "delete"]
# namespace: "default"
添加审计日志
通过对 kube-apiserver.yaml 的配置开启后端审计日志
标志配置 | 描述 |
---|---|
--audit-log-path | 指定用来写入审计事件的日志文件路径。不指定此标志会禁用日志后端。 |
--audit-log-maxage | 定义保留旧审计日志文件的最大天数。 |
--audit-log-maxbackup | 定义要保留的审计日志文件的最大数量。 |
--audit-log-maxsize | 定义审计日志文件的最大大小(兆字节)。 |
--audit-policy-file | 定义审计日志文件的策略。 |
这里我们设置审计日志文件的策略/etc/kubernetes/audit-policy/policy.yaml,将审计日志写入/etc/kubernetes/audit-logs/audit.log当中(注意路径需要创建mkdir /etc/kubernetes/audit-logs/),设置最大保留2个审记日志,每个最多7兆。
spec:
containers:
- command:
- kube-apiserver
- --audit-policy-file=/etc/kubernetes/audit-policy/policy.yaml
- --audit-log-path=/etc/kubernetes/audit-logs/audit.log
- --audit-log-maxsize=7
- --audit-log-maxbackup=2
注意组要挂载相关卷
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是静态pod,所以稍微等待就可以了。(为了保险起见也可以重启kubelet)
$ systemctl daemon-reload
$ systemctl restart kubelet
我的完整 apiserver 配置信息
# cat /etc/kubernetes/manifests/kube-apiserver.yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.10.11:6443
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.10.11
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
- --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
- --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
- --etcd-servers=https://127.0.0.1:2379
- --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
- --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
- --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
- --requestheader-allowed-names=front-proxy-client
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --requestheader-extra-headers-prefix=X-Remote-Extra-
- --requestheader-group-headers=X-Remote-Group
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
- --service-cluster-ip-range=10.10.0.0/12
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
- --audit-policy-file=/etc/kubernetes/audit-policy/policy.yaml
- --audit-log-path=/etc/kubernetes/audit-logs/audit.log
- --audit-log-maxsize=7
- --audit-log-maxbackup=2
image: registry.aliyuncs.com/google_containers/kube-apiserver:v1.29.1
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
host: 192.168.10.11
path: /livez
port: 6443
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
name: kube-apiserver
readinessProbe:
failureThreshold: 3
httpGet:
host: 192.168.10.11
path: /readyz
port: 6443
scheme: HTTPS
periodSeconds: 1
timeoutSeconds: 15
resources:
requests:
cpu: 250m
startupProbe:
failureThreshold: 24
httpGet:
host: 192.168.10.11
path: /livez
port: 6443
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
volumeMounts:
- mountPath: /etc/ssl/certs
name: ca-certs
readOnly: true
- mountPath: /etc/pki
name: etc-pki
readOnly: true
- mountPath: /etc/kubernetes/pki
name: k8s-certs
readOnly: true
- mountPath: /etc/kubernetes/audit-policy/policy.yaml
name: audit-policy
readOnly: true
- mountPath: /etc/kubernetes/audit-logs
name: audit-logs
readOnly: false
hostNetwork: true
priority: 2000001000
priorityClassName: system-node-critical
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- hostPath:
path: /etc/ssl/certs
type: DirectoryOrCreate
name: ca-certs
- hostPath:
path: /etc/pki
type: DirectoryOrCreate
name: etc-pki
- hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate
name: k8s-certs
- name: audit-policy
hostPath:
path: /etc/kubernetes/audit-policy/policy.yaml
type: File
- name: audit-logs
hostPath:
path: /etc/kubernetes/audit-logs
type: DirectoryOrCreate
status: {}
审计日志解析
通过上述的配置后,将会生成如下审计日志
[root@k8s-master01 audit-logs]# ls /etc/kubernetes/audit-logs/
audit.log
[root@k8s-master01 audit-logs]# cat /etc/kubernetes/audit-logs/audit.log
{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"3f9e34f0-52e8-44bc-88fb-10ae742d2a0a","stage":"ResponseStarted","requestURI":"/api/v1/secrets?allowWatchBookmarks=true\u0026resourceVersion=100443\u0026timeout=7m55s\u0026timeoutSeconds=475\u0026watch=true","verb":"watch","user":{"username":"system:kube-controller-manager","groups":["system:authenticated"]},"sourceIPs":["192.168.10.11"],"userAgent":"kube-controller-manager/v1.29.1 (linux/amd64) kubernetes/bc401b9/shared-informers","objectRef":{"resource":"secrets","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2024-02-19T01:13:32.195666Z","stageTimestamp":"2024-02-19T01:13:32.197428Z","annotations":{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding \"system:kube-controller-manager\" of ClusterRole \"system:kube-controller-manager\" to User \"system:kube-controller-manager\""}}
分析效果
- 审计事件类型:Event
- API 版本:audit.k8s.io/v1
- 事件级别:Metadata
- 审计 ID:3f9e34f0-52e8-44bc-88fb-10ae742d2a0a
- 事件阶段:ResponseStarted
- 请求 URI:/api/v1/secrets?allowWatchBookmarks=true&resourceVersion=100443&timeout=7m55s&timeoutSeconds=475&watch=true
- HTTP 方法:watch
- 用户:system:kube-controller-manager
- 用户名:system:kube-controller-manager
- 用户组:system:authenticated
- 源 IP 地址:192.168.10.11
- 用户代理:kube-controller-manager/v1.29.1 (linux/amd64) kubernetes/bc401b9/shared-informers
- 对象引用:
- 资源:secrets
- API 版本:v1
- 响应状态:
- 状态码:200
- 元数据:{}
- 请求接收时间戳:2024-02-19T01:13:32.195666Z
- 事件阶段时间戳:2024-02-19T01:13:32.197428Z
- 注释:
- 授权决定:allow
- 授权原因:RBAC: allowed by ClusterRoleBinding "system:kube-controller-manager" of ClusterRole "system:kube-controller-manager" to User "system:kube-controller-manager"
根据这些信息,可以得出以下结论
用户 system:kube-controller-manager 通过 kube-controller-manager 用户代理向 Kubernetes API 发起了一个 watch 操作,观察 Secrets 资源的变化。
RBAC 授权允许了这个操作,授权原因是由 ClusterRoleBinding "system:kube-controller-manager" 授予的 ClusterRole "system:kube-controller-manager" 对用户 "system:kube-controller-manager" 的权限。
评论区