Kubernetes 極大地提高了當(dāng)今生產(chǎn)中后端集群的速度和可管理性。由于靈活、可擴(kuò)展、易用,Kubernetes 已成為容器編排的事實(shí)標(biāo)準(zhǔn)。Kubernetes 還提供了一系列保護(hù)功能。而 Admission Controllers(準(zhǔn)入控制器) 是一組安全相關(guān)的插件,啟用后能進(jìn)一步使用 Kubernetes 更高級(jí)的安全功能。
什么是準(zhǔn)入控制器?
簡(jiǎn)而言之,Kubernetes 準(zhǔn)入控制器是管理和強(qiáng)制定義集群使用方式的插件??梢詫⑺鼈兛醋鲾r截(經(jīng)過(guò)認(rèn)證的)API 請(qǐng)求的守門員,可以更改請(qǐng)求對(duì)象或完全拒絕請(qǐng)求。準(zhǔn)入控制的過(guò)程分為兩步:先變異(mutate)后驗(yàn)證(validate)。舉個(gè)例子,LimitRanger 準(zhǔn)入控制器在變異階段使用默認(rèn)的資源配置來(lái)限制容器對(duì)資源的使用,并在驗(yàn)證階段確保容器的資源限制不超過(guò)預(yù)期的。值得一提的是,許多用戶認(rèn)為內(nèi)置的 Kubernetes 操作的某些方面實(shí)際上由準(zhǔn)入控制器管理。舉個(gè)例子,當(dāng)一個(gè)命名空間被刪除隨后進(jìn)入 Terminating(終止) 狀態(tài)時(shí),NamespaceLifecycle 準(zhǔn)入控制器將阻止任何對(duì)象在此命名空間內(nèi)被創(chuàng)建。
在30多種準(zhǔn)入控制器中,ValidatingAdmissionWebhooks 和 MutatingAdmissionWebhooks (從1.13版開(kāi)始兩者都處于beta狀態(tài))比較特殊。它們有著無(wú)限的靈活性,但本身并沒(méi)有實(shí)現(xiàn)任何決策邏輯,而是從集群內(nèi)運(yùn)行的 webhook 服務(wù)獲取相應(yīng)的操作。無(wú)論何時(shí)在 Kubernetes 集群中創(chuàng)建、更新或刪除資源,都允許用戶實(shí)現(xiàn)自定義邏輯。
mutating admission webhooks 可以變異(篡改)API 對(duì)象,validating admission webhooks 不行。雖然 mutating admission webhooks 也可以做到拒絕請(qǐng)求,但是 validating admission webhooks 與前者相比有兩個(gè)主要優(yōu)點(diǎn):第一,出于安全方面的考慮可能得禁用 MutatingAdmissionWebhook 準(zhǔn)入控制器(或者設(shè)置嚴(yán)格的 RBAC 限制),因?yàn)榭赡芤鸹靵y甚至有危險(xiǎn)的副作用。第二,如上圖所示,validating admission 控制器在 mutating admission 之后運(yùn)行,因此,validating admission webhook 看到的任何請(qǐng)求對(duì)象都是即將被保存到 etcd 中的最終版。
如何開(kāi)啟準(zhǔn)入控制器?
在 Kubernetes API server 的啟動(dòng)參數(shù)中帶上:
--enable-admission-plugins=ValidatingAdmissionWebhook,MutatingAdmissionWebhook
–-admission-control 在 1.10 版本中就被廢除,取而代之的是 –-enable-admission-plugins
建議默認(rèn)啟用以下準(zhǔn)入控制器:
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,Priority,ResourceQuota,PodSecurityPolicy
點(diǎn)擊官方文檔中查看中完整準(zhǔn)入控制器以及說(shuō)明。
為什么需要準(zhǔn)入控制器?
- 安全:準(zhǔn)入控制器可以通過(guò)在整個(gè)命名空間或集群中強(qiáng)制使用合理的安全基準(zhǔn)來(lái)提高安全性。內(nèi)置的 PodSecurityPolicy 準(zhǔn)入控制器是典型的例子:禁止容器以 root 身份運(yùn)行,或者確保容器的 rootfs 始終以只讀的權(quán)限掛載。當(dāng)然也可以通過(guò)基于 webkook 的準(zhǔn)入控制器來(lái)實(shí)現(xiàn):
- 只允許從特定的 registry 拉取鏡像,拒絕訪問(wèn)未知的 registry。
- 拒絕不符合安全標(biāo)準(zhǔn)的部署。
- 管控:準(zhǔn)入控制器強(qiáng)制你遵循某些格式,比如良好的標(biāo)簽、注釋、資源限制等等。
- 對(duì)不同對(duì)象強(qiáng)制執(zhí)行標(biāo)簽驗(yàn)證,確保標(biāo)簽與對(duì)象正確吻合。
- 自動(dòng)給對(duì)象添加 annotation。
- 配置管理:準(zhǔn)入控制器驗(yàn)證集群中運(yùn)行的對(duì)象的配置,防止任何顯式的錯(cuò)誤配置直接生效。
- 自動(dòng)添加或驗(yàn)證資源限制
- 確保 pod 被添加了合理的標(biāo)簽
- 確保生產(chǎn)部署中不使用最新 (latest) 的鏡像版本
通過(guò)這種方式,準(zhǔn)入控制器和策略管理有助于確保應(yīng)用程序在不斷變化的控制環(huán)境中保持合法。
編寫和部署 Admission Controller Webhook
我們用一個(gè) Kubernetes 的缺點(diǎn)來(lái)說(shuō)明如何利用準(zhǔn)入控制器 webhook 來(lái)建立自定義安全策略:許多默認(rèn)設(shè)置為了易于使用并減少?zèng)_突而優(yōu)化,不免犧牲一定的安全性。其中之一就是默認(rèn)允許容器以 root 身份運(yùn)行(而且,如果沒(méi)有在 Dockerfile 中使用 USER 命令配置,也將是這樣)。盡管容器有一定程度隔離,以 root 身份運(yùn)行還是會(huì)增加風(fēng)險(xiǎn)——這在生產(chǎn)環(huán)境中應(yīng)當(dāng)被避免。之前被曝光的 runC 漏洞 (CVE-2019-5736),只有在以 root 身份運(yùn)行容器時(shí)才會(huì)搞事。
你可以使用自定義 mutating admission controller webhook 來(lái)應(yīng)用更安全的默認(rèn)配置:除非明確要求,webhook 將確保 pod 以非 root 用戶運(yùn)行(如果沒(méi)有明確說(shuō)明,我們將分配 uid 為1234)。注意,這個(gè)設(shè)置不會(huì)阻止你在集群中部署任何工作負(fù)載,包括那些需要以 root 身份運(yùn)行的合法應(yīng)用。只需要在部署配置中明確啟用此風(fēng)險(xiǎn)程序操作模式。
repo: https://github.com/stackrox/admission-controller-webhook-demo
Mutating Webhook Configuration
創(chuàng)建 MutatingWebhookConfiguration 對(duì)象來(lái)定義 mutating admission controller webhook:
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
name: demo-webhook
webhooks:
- name: webhook-server.webhook-demo.svc
clientConfig:
service:
name: webhook-server
namespace: webhook-demo
path: "/mutate"
caBundle: ${CA_PEM_B64}
rules:
- operations: [ "CREATE" ]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
這份配置定義了 webhook-server.webhook-demo.svc 這個(gè) webhook,當(dāng) pod 創(chuàng)建時(shí) Kubernetes API server 將發(fā)送 HTTP POST 請(qǐng)求至 /mutate 路徑。
Webhook REST API
API server 向指定接口發(fā)送 HTTP POST 請(qǐng)求,請(qǐng)求體中帶上 JSON 格式的 AdmissionReview(Request 字段)。同樣響應(yīng)也是 JSON 格式的 AdmissionReview(Response 字段)。
demo repo 中包含了一個(gè)序列化/反序列化的函數(shù),你只需要專注于實(shí)現(xiàn)操作 Kubernetes API 對(duì)象的邏輯就行了。在這個(gè)例子中,實(shí)現(xiàn)準(zhǔn)入控制器邏輯的函數(shù)是 applySecurityDefaults,并在 HTTPS 服務(wù)中與 /mutate 路由綁定:
mux := http.NewServeMux()
mux.Handle("/mutate", admitFuncHandler(applySecurityDefaults))
server := &http.Server{
Addr: ":8443",
Handler: mux,
}
log.Fatal(server.ListenAndServeTLS(certPath, keyPath))
創(chuàng)建一個(gè) Service 對(duì)象來(lái)將443端口映射至容器的8443端口:
apiVersion: v1
kind: Service
metadata:
name: webhook-server
namespace: webhook-demo
spec:
selector:
app: webhook-server # specified by the deployment/pod
ports:
- port: 443
targetPort: webhook-api # name of port 8443 of the container
對(duì)象變異邏輯
mutating admission controller webhook 通過(guò) JSON 補(bǔ)丁 來(lái)變異。下面的 Go 數(shù)據(jù)結(jié)構(gòu)大致描述了一下:
type patchOperation struct {
Op string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value,omitempty"`
}
要把 pod 的 .spec.securityContext.runAsNonRoot 字段設(shè)置為 true,我們構(gòu)建下面的 patchOperation 對(duì)象:
patches = append(patches, patchOperation{
Op: "add",
Path: "/spec/securityContext/runAsNonRoot",
Value: true,
})
TLS 證書
由于必須走 HTTPS,需要提供 TLS 證書。自簽名證書也可以(由一個(gè)自簽名的 CA 簽名),但是我們需要 Kubernetes 在于 webhook 服務(wù)器通信時(shí)指定相應(yīng)的 CA 證書。此外,證書的 CN 要和 Kubernetes API server 所使用的服務(wù)器名稱匹配,內(nèi)部的 Service 域名為 ..svc,在我們的例子中為 webhook-server.webhook-demo.svc。由于自簽名 TLS 證書的生成方法 Google 上一大把,我們就在示例中引用相應(yīng)的 shell 腳本了。
前面的 Webbook 配置包含了占位符 ${CA_PEM_B64}。在我們創(chuàng)建它之前,需要替換成 BASE64 編碼后的 CA PEM 證書。openssl base64 -A 命令可以做到。
測(cè)試
測(cè)試案例:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-463909.html
- 未指定安全上下文的 pod。我們期望這個(gè) pod 以 uid 為1234的非 root 用戶身份運(yùn)行。
- 指定安全上下文的 pod,顯示地以 root 用戶運(yùn)行。
- 配置沖突的 pod,指定了必須以非 root 用戶運(yùn)行,但是 uid 為0。
通過(guò)執(zhí)行 kubectl create -f examples/.yaml 來(lái)創(chuàng)建這些 pod。在前兩個(gè)例子中,驗(yàn)證用戶身份:
$ kubectl create -f examples/pod-with-defaults.yaml
$ kubectl logs pod-with-defaults
I am running as user 1234
第三個(gè)例子中,創(chuàng)建操作會(huì)被拒絕:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-463909.html
$ kubectl create -f examples/pod-with-conflict.yaml
Error from server (InternalError): error when creating "examples/pod-with-conflict.yaml": Internal error occurred: admission webhook "webhook-server.webhook-demo.svc" denied the request: runAsNonRoot specified, but runAsUser set to 0 (the root user)
引用
- https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
- https://docs.okd.io/latest/architecture/additional_concepts/dynamic_admission_controllers.html
- https://kubernetes.io/blog/2018/01/extensible-admission-is-beta/
- https://medium.com/ibm-cloud/diving-into-kubernetes-mutatingadmissionwebhook-6ef3c5695f74
- https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/test/images/webhook/main.go
- https://github.com/istio/istio
- https://www.stackrox.com/post/2019/02/the-runc-vulnerability-a-deep-dive-on-protecting-yourself/
到了這里,關(guān)于Kubernetes 準(zhǔn)入控制器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!