審計日誌能夠記錄全部對 apiserver 接口的調用,讓咱們可以很是清晰的知道集羣到底發生了什麼事情,經過記錄的日誌能夠查到所發生的事件、操做的用戶和時間。kubernetes 在 v1.7 中支持了日誌審計功能(Alpha),在 v1.8 中爲 Beta 版本,v1.12 爲 GA 版本。php
kubernetes feature-gates 中的功能 Alpha 版本默認爲 false,到 Beta 版本時默認爲 true,因此 v1.8 會默認啓用審計日誌的功能。linux
1、審計日誌的策略
一、日誌記錄階段
kube-apiserver 是負責接收及相應用戶請求的一個組件,每個請求都會有幾個階段,每一個階段都有對應的日誌,當前支持的階段有:git
RequestReceived - apiserver 在接收到請求後且在將該請求下發以前會生成對應的審計日誌。github
ResponseStarted - 在響應 header 發送後並在響應 body 發送前生成日誌。這個階段僅爲長時間運行的請求生成(例如 watch)。web
ResponseComplete - 當響應 body 發送完而且再也不發送數據。json
Panic - 當有 panic 發生時生成。後端
也就是說對 apiserver 的每個請求理論上會有三個階段的審計日誌生成。api
二、日誌記錄級別
當前支持的日誌記錄級別有:安全
None - 不記錄日誌。ruby
Metadata - 只記錄 Request 的一些 metadata (例如 user, timestamp, resource, verb 等),但不記錄 Request 或 Response 的body。
Request - 記錄 Request 的 metadata 和 body。
RequestResponse - 最全記錄方式,會記錄全部的 metadata、Request 和 Response 的 body。
三、日誌記錄策略
在記錄日誌的時候儘可能只記錄所須要的信息,不須要的日誌儘量不記錄,避免形成系統資源的浪費。
一個請求不要重複記錄,每一個請求有三個階段,只記錄其中須要的階段
不要記錄全部的資源,不要記錄一個資源的全部子資源
系統的請求不須要記錄,kubelet、kube-proxy、kube-scheduler、kube-controller-manager 等對 kube-apiserver 的請求不須要記錄
對一些認證信息(secerts、configmaps、token 等)的 body 不記錄
k8s 審計日誌的一個示例:
{
"kind": "EventList",
"apiVersion": "audit.k8s.io/v1beta1",
"Items": [
{
"Level": "Request",
"AuditID": "793e7ae2-5ca7-4ad3-a632-19708d2f8265",
"Stage": "RequestReceived",
"RequestURI": "/api/v1/namespaces/default/pods/test-pre-sf-de7cc-0",
"Verb": "get",
"User": {
"Username": "system:unsecured",
"UID": "",
"Groups": [
"system:masters",
"system:authenticated"
],
"Extra": null
},
"ImpersonatedUser": null,
"SourceIPs": [
"192.168.1.11"
],
"UserAgent": "kube-scheduler/v1.12.2 (linux/amd64) kubernetes/73f3294/scheduler",
"ObjectRef": {
"Resource": "pods",
"Namespace": "default",
"Name": "test-pre-sf-de7cc-0",
"UID": "",
"APIGroup": "",
"APIVersion": "v1",
"ResourceVersion": "",
"Subresource": ""
},
"ResponseStatus": null,
"RequestObject": null,
"ResponseObject": null,
"RequestReceivedTimestamp": "2019-01-11T06:51:43.528703Z",
"StageTimestamp": "2019-01-11T06:51:43.528703Z",
"Annotations": null
}
]
}
2、啓用審計日誌
當前的審計日誌支持兩種收集方式:保存爲日誌文件和調用自定義的 webhook,在 v1.13 中還支持動態的 webhook。
一、將審計日誌以 json 格式保存到本地文件
apiserver 配置文件的 KUBE_API_ARGS 中須要添加以下參數:
--audit-policy-file=/etc/kubernetes/audit-policy.yaml --audit-log-path=/var/log/kube-audit --audit-log-format=json
日誌保存到本地後再經過 fluentd 等其餘組件進行收集。
還有其餘幾個選項能夠指定保留審計日誌文件的最大天數、文件的最大數量、文件的大小等。
二、將審計日誌打到後端指定的 webhook
--audit-policy-file=/etc/kubernetes/audit-policy.yaml --audit-webhook-config-file=/etc/kubernetes/audit-webhook-kubeconfig
webhook 配置文件其實是一個 kubeconfig,apiserver 會將審計日誌發送 到指定的 webhook 後,webhook 接收到日誌後能夠再分發到 kafka 或其餘組件進行收集。
audit-webhook-kubeconfig
示例:
apiVersion: v1
clusters:
- cluster:
server: http://127.0.0.1:8081/audit/webhook
name: metric
contexts:
- context:
cluster: metric
user: ""
name: default-context
current-context: default-context
kind: Config
preferences: {}
users: []
前面提到過,apiserver 的每個請求會記錄三個階段的審計日誌,可是在實際中並非須要全部的審計日誌,官方也說明了啓用審計日誌會增長 apiserver 對內存的使用量。
Note: The audit logging feature increases the memory consumption of the API server because some context required for auditing is stored for each request. Additionally, memory consumption depends on the audit logging configuration.
audit-policy.yaml
配置示例:
apiVersion: audit.k8s.io/v1
kind: Policy
# ResponseStarted 階段不記錄
omitStages:
- "ResponseStarted"
rules:
# 記錄用戶對 pod 和 statefulset 的操做
- level: RequestResponse
resources:
- group: ""
resources: ["pods","pods/status"]
- group: "apps"
resources: ["statefulsets","statefulsets/scale"]
# kube-controller-manager、kube-scheduler 等已經認證過身份的請求不須要記錄
- level: None
userGroups: ["system:authenticated"]
nonResourceURLs:
- "/api*"
- "/version"
# 對 config、secret、token 等認證信息不記錄請求體和返回體
- level: Metadata
resources:
- group: "" # core API group
resources: ["secrets", "configmaps"]
官方提供兩個參考示例:
Use fluentd to collect and distribute audit events from log file
Use logstash to collect and distribute audit events from webhook backend
三、subresource 說明
kubernetes 每一個資源對象都有 subresource,經過調用 master 的 api 能夠獲取 kubernetes 中全部的 resource 以及對應的 subresource,好比 pod 有 logs、exec 等 subresource。
獲取全部 resource( 1.10 以後使用):
$ curl 127.0.0.1:8080/openapi/v2
參考:
https://kubernetes.io/docs/concepts/overview/kubernetes-api/
3、webhook 的一個簡單示例
package main
import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
"github.com/emicklei/go-restful"
"github.com/gosoon/glog"
"k8s.io/apiserver/pkg/apis/audit"
)
func main() {
// NewContainer creates a new Container using a new ServeMux and default router (CurlyRouter)
container := restful.NewContainer()
ws := new(restful.WebService)
ws.Path("/audit").
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.POST("/webhook").To(AuditWebhook))
//WebService ws2被添加到container2中
container.Add(ws)
server := &http.Server{
Addr: ":8081",
Handler: container,
}
//go consumer()
log.Fatal(server.ListenAndServe())
}
func AuditWebhook(req *restful.Request, resp *restful.Response) {
body, err := ioutil.ReadAll(req.Request.Body)
if err != nil {
glog.Errorf("read body err is: %v", err)
}
var eventList audit.EventList
err = json.Unmarshal(body, &eventList)
if err != nil {
glog.Errorf("unmarshal failed with:%v,body is :\n", err, string(body))
return
}
for _, event := range eventList.Items {
jsonBytes, err := json.Marshal(event)
if err != nil {
glog.Infof("marshal failed with:%v,event is \n %+v", err, event)
}
// 消費日誌
asyncProducer(string(jsonBytes))
}
resp.AddHeader("Content-Type", "application/json")
resp.WriteEntity("success")
}
完整代碼請參考:
https://github.com/gosoon/k8s-audit-webhook
4、總結
本文主要介紹了 kubernetes 的日誌審計功能,kubernetes 最近也被爆出多個安全漏洞,安全問題是每一個團隊不可忽視的,kubernetes 雖然被多數公司用做私有云,但日誌審計也是不可或缺的。
參考:
https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
ttps://kubernetes.io/docs/tasks/debug-application-cluster/audit/
阿里雲 Kubernetes 審計日誌方案
本文分享自微信公衆號 - 田飛雨(kubeConChina)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。