开头语
写在前面:如有问题,以你为准,
目前24年应届生,各位大佬轻喷,部分资料与图片来自网络
内容较长,页面右上角目录方便跳转
基本
介绍
在Kubernetes集群中,API Server的审计日志记录了哪些用户、哪些服务请求操作集群资源,并且可以编写不同规则 控制忽略、存储的操作日志。
审计日志采用SON格式输出,每条日志都包含丰富的元数据,例如请求的URL、HTTP方法、客户端来源等,你可以使 用监控服务来分析API流量,以检测趋势或河能存在的安全隐患。
- 管理节点(controller--manager、.scheduler)
- 工作节点(kubelet、.kube-proxy)
- 集群服务(CoreDNS、Calico、HPA等)
- kubectl、.APl、Dashboard
事件 阶段
yaml 解析
https://kubernetes.io/zh-cn/docs/tasks/debug/debug-cluster/audit/
audit-policy
修改配置后是需要删除apiserver容器,等待自动pod自动进行创建
apiVersion: audit.k8s.io/v1 # 这是必填项。
kind: Policy
# 不要在 RequestReceived 阶段为任何请求生成审计事件。
omitStages:
- "RequestReceived"
rules:
# 在日志中用 RequestResponse 级别记录 Pod 变化。
- level: RequestResponse
resources:
- group: ""
# 资源 "pods" 不匹配对任何 Pod 子资源的请求,
# 这与 RBAC 策略一致。
resources: ["pods"]
# 在日志中按 Metadata 级别记录 "pods/log"、"pods/status" 请求
- level: Metadata
resources:
- group: ""
resources: ["pods/log", "pods/status"]
# 不要在日志中记录对名为 "controller-leader" 的 configmap 的请求。
- level: None
resources:
- group: ""
resources: ["configmaps"]
resourceNames: ["controller-leader"]
# 不要在日志中记录由 "system:kube-proxy" 发出的对端点或服务的监测请求。
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: "" # core API 组
resources: ["endpoints", "services"]
# 不要在日志中记录对某些非资源 URL 路径的已认证请求。
- level: None
userGroups: ["system:authenticated"]
nonResourceURLs:
- "/api*" # 通配符匹配。
- "/version"
# 在日志中记录 kube-system 中 configmap 变更的请求消息体。
- level: Request
resources:
- group: "" # core API 组
resources: ["configmaps"]
# 这个规则仅适用于 "kube-system" 名字空间中的资源。
# 空字符串 "" 可用于选择非名字空间作用域的资源。
namespaces: ["kube-system"]
# 在日志中用 Metadata 级别记录所有其他名字空间中的 configmap 和 secret 变更。
- level: Metadata
resources:
- group: "" # core API 组
resources: ["secrets", "configmaps"]
# 在日志中以 Request 级别记录所有其他 core 和 extensions 组中的资源操作。
- level: Request
resources:
- group: "" # core API 组
- group: "extensions" # 不应包括在内的组版本。
# 一个抓取所有的规则,将在日志中以 Metadata 级别记录所有其他请求。
- level: Metadata
# 符合此规则的 watch 等长时间运行的请求将不会
# 在 RequestReceived 阶段生成审计事件。
omitStages:
- "RequestReceived"
示例
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
# namespaces: ["default"] # 执行命名空间
verbs: ["create","delete"] # 指定相关操作
resources: # 执行资源
- group: ""
resources: ["pods"]
# resourceNames: ["controller-leader"] 指定资源名
- level: None
[root@master audit]# ps -ef | grep apiserver
root 831053 831034 0 10:27 ?
root 2791437 2791419 71 21:09 ? 00:00:08 kube-apiserver --advertise-address=
[root@master audit]# kill -9 2791437
[root@master audit]# kubectl get pod -A
[root@master ~]# kubectl delete pod web1666
pod "web1666" deleted
[root@master audit]# tail -f /var/log/audit/k8s_audit.log
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "c52213b1-0bd6-4790-80ae-7c5aeb159ab9",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/default/pods/web1666",
"verb": "delete",
"user": {
"username": "system:node:node1",
"groups": [
"system:nodes",
"system:authenticated"
]
},
"sourceIPs": [
"192.168.100.51"
],
"userAgent": "kubelet/v1.28.1 (linux/amd64) kubernetes/8dc49c4",
"objectRef": {
"resource": "pods",
"namespace": "default",
"name": "web1666",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2023-11-21T02:11:53.435596Z",
"stageTimestamp": "2023-11-21T02:11:53.444542Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": ""
}
}
审计日志
开启
审计日志支持写入本地文件和Vebhook (发送到外部HTTP API) 两种方式。
vi /etc/kubernetes/manifests/kube-apiserver.yaml
---audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml
--audit-log-path=/var/log/audit/k8s_audit.log
---audit-log-maxage=30
---audit-log-maxbackup=10
---audit-log-maxsize=100
注:使用hostpath数据卷将宿主机/etc/kubernetes/,audit目录挂载到容器中
mkdir /etc/kubernetes/audit
touch /var/log/audit/k8s_audit.log
apiserver.yaml 需要修改内容
volumeMounts:
- mountPath: /etc/kubernetes/audit
name: audit
readOnly: true
- mountPath: /var/log/audit/k8s_audit.log
name: audit-log-file
volumes:
- hostPath:
path: /etc/kubernetes/audit
type: DirectoryOrCreate
name: audit
- hostPath:
path: /var/log/audit/k8s_audit.log
type: File
name: audit-log-file
解析
日志内容
[root@master kubernetes]# tail -1 /var/log/audit/k8s_audit.log | jq
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "95279099-833a-4a79-b942-9cd5da761cc6",
"stage": "ResponseComplete", # 在那个阶段处理
"requestURI": "/healthz",
"verb": "get",
"user": {
"username": "system:serviceaccount:calico-system:calico-kube-controllers",
"uid": "47d3e62f-edcf-4938-b988-ae0b14e40666",
"groups": [
"system:serviceaccounts",
"system:serviceaccounts:calico-system",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/pod-name": [
"calico-kube-controllers-6b7b9c649d-xllqh"
],
"authentication.kubernetes.io/pod-uid": [
"fbf6ee10-fd48-4e64-bd03-31995dedbe6a"
]
}
},
"sourceIPs": [
"10.244.219.105"
],
"userAgent": "kube-controllers/v0.0.0 (linux/amd64) kubernetes/$Format",
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2023-11-20T09:06:54.725743Z",
"stageTimestamp": "2023-11-20T09:06:54.727333Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"system:public-info-viewer\" of ClusterRole \"system:public-info-viewer\" to Group \"system:authenticated\""
}
}
内容解析
- 事件基本信息:
- kind: 表示事件的类型,这里是 "Event"。
- apiVersion: 表示 Kubernetes 审计 API 的版本,这里是 "audit.k8s.io/v1"。
- level: 表示事件的级别,这里是 "Metadata"。
- auditID: 事件的唯一标识符。
- stage: 表示事件发生的阶段,这里是 "ResponseComplete",表示 API 请求的响应已经完成。
- 请求信息:
- verb: 表示请求的动作,这里是 "get",表示是一个 GET 请求。
- user: 提供有关执行请求的用户的详细信息,包括用户名、UID、用户组等。
- sourceIPs: 表示请求的来源 IP 地址。
- userAgent: 表示发起请求的用户代理信息,这里是 "kube-controllers/v0.0.0 (linux/amd64) kubernetes/$Format"。
示例
[root@master ~]# docker run -d --name web1666 nginx:1.17.1
[root@master kubernetes]# cat /var/log/audit/k8s_audit.log | grep web1666 | jq
日志收集与呈现方案
K8S 日志为什么以 stdout 和 stderr 的方式输出
文件描述符 作用 例子(c语言)
0 (stdin) 标准输入 fscanf(stdin,"%s",str);
1 (stdout) 标准输出 fprintf(stdout,"%s\n","hello");
2 (stderror) 标准错误输出 fprintf(stderr,"%s\n","error");
1. 简单方便,可以直接使用语言自带的标准库,打印出信息(比如c语言的printf, fprintf函数)作为日志的输入源,不用额外的再建立一个文件。
2. 易管理,可以将容器的标准输出stdout, stderr重定向到log-file.log。 比如将上面的test.c文件编译后,执行 ./a.out >> a.log 2>&1,就会将标准输出存放到a.log里
nginx 导出日志到logs
使用 volumes 中的 emptyDir: {}
yaml 如图