使用Webhook為Kubernetes實現(xiàn)基于標(biāo)簽的權(quán)限控制
Kubernetes支持名稱空間級別的權(quán)限控制。但是,有時這不能滿足我們的要求。例如,在Akraino ICN項目中,我們有一些高級權(quán)限要求:多個用戶可以在同一名稱空間中創(chuàng)建,更新或刪除一種資源,但不能更新或刪除其他人創(chuàng)建的對象。
為了滿足這一要求,我們使用Webhook在Kubernetes中設(shè)計并實現(xiàn)了基于標(biāo)簽的權(quán)限控制機制。通常,webhooks用于驗證資源或設(shè)置資源的默認(rèn)值。在本文中,我們使用webhook來控制權(quán)限。
許可系統(tǒng)的設(shè)計
在Kubernetes中,用戶或服務(wù)帳戶可以綁定到一個或多個角色。每個角色定義其權(quán)限規(guī)則。例如,以下定義要求sdewan-test角色可以在默認(rèn)名稱空間中創(chuàng)建或更新類型為Mwan3Rule的自定義資源實例(CR),并且可以獲取Mwan3Policy CR。
- apiVersion: rbac.authorization.k8s.io/v1
- kind: Role
- metadata:
- Annotations:
- name: sdewan-test
- namespace: default
- rules:
- - apiGroups:
- - ""
- resources:
- - mwan3rules
- verbs:
- - create
- - update
- - apiGroups:
- - ""
- resources:
- - mwan3policies
- verbs:
- - get
我們使用json格式的注釋sdewan-bucket-type-permission擴展了角色。
在注釋中,我們可以定義基于標(biāo)簽的權(quán)限。例如,下面顯示的角色擴展了sdewan-test角色權(quán)限:sdewan-test只能創(chuàng)建/更新帶有標(biāo)簽sdewan-bucket-type=app-intent或sdewan-bucket-type=k8s-service的Mwan3Rule(json鍵指定自定義資源類型)CR。而且它只能獲得帶有標(biāo)簽sdewan-bucket-type=app-intent的Mwan3Policy CR。
實際上,我們也支持通配符匹配。例如,我們可以使用mwan3*來同時匹配mwan3policies和mwan3rules。
- apiVersion: rbac.authorization.k8s.io/v1
- kind: Role
- metadata:
- annotations:
- sdewan-bucket-type-permission: |-
- { "mwan3rules": ["app-intent", "k8s-service"],
- "mwan3policies": ["app-intent"] }
- name: sdewan-test
- namespace: default
- rules:
- - apiGroups:
- - ""
- resources:
- - mwan3rules
- verbs:
- - create
- - update
- - apiGroups:
- - ""
- resources:
- - mwan3policies
- verbs:
- - get
Kubernetes Webhook負(fù)責(zé)解析角色注釋。讓我用簡單的詞來描述什么是準(zhǔn)入webhook。我們可以將webhook視為Web服務(wù),通常它在Kubernetes集群中作為pod運行。
當(dāng)Kubernetes api收到請求時,kube-api可以在將對象保存到etcd中之前調(diào)用webhook API。如果webhook返回allowed=true,則kube-api繼續(xù)將對象持久保存到etcd中。否則,kube-api拒絕該請求。
Webhook請求主體具有一個名為userInfo的字段,該字段指示誰在發(fā)出Kubernetes api請求。從用戶信息中,webhook可以獲取角色信息,然后獲取角色注釋。通過將注釋中描述的標(biāo)簽級別權(quán)限與CR標(biāo)簽進行比較,webhook可以決定是否允許該請求。
實施權(quán)限控制系統(tǒng)
我們已經(jīng)通過Akraino ICN項目中的kubebuilder框架實現(xiàn)了基于標(biāo)簽的權(quán)限系統(tǒng)。這里的假設(shè)是已經(jīng)實現(xiàn)了一些自定義資源定義(CRD)(例如Mwan3Policy和Mwan3Rule)和相應(yīng)的控制器。
Kubebuilder可以生成基本的CRD,控制器代碼和Webhook代碼。要創(chuàng)建一個新的webhook,我們運行以下kubebuilder命令:
- kubebuilder create webhook --group batch --version v1 --kind CronJob --programmatic-validation
此命令利用controller-runtime builder來創(chuàng)建驗證Webhook。該命令還會創(chuàng)建webhook server,該server接受來自kube-api服務(wù)器的https請求。它甚至生成解析http請求正文并將其轉(zhuǎn)換為CRD結(jié)構(gòu)實例的代碼。
開發(fā)人員只需要編寫代碼來驗證CRD實例內(nèi)容。這對于大多數(shù)Webhook情況都是有用的。但這不能滿足我們的要求,因為我們需要位于https請求正文中的UserInfo而不是CRD實例。
我們重用了kubebuilder生成的webhook server,但自己實現(xiàn)了處理程序。上圖顯示了處理程序的處理流程。處理程序接受“ admission.Request”作為輸入,其中包含UserInfo。在處理程序中,我們獲得用戶角色信息和CR標(biāo)簽。
- 獲取用戶角色信息。
userinfo在請求正文中。為了從userinfo獲取角色信息,處理程序必須向kube-api請求用戶的角色信息。處理程序使用serviceaccount令牌作為身份驗證將請求發(fā)送到kube-api。首先,處理程序發(fā)送一個請求以獲取用戶的角色綁定信息。然后,它發(fā)送第二個請求以從角色綁定信息中獲取角色信息。默認(rèn)情況下,角色綁定資源在“ .subjects”字段上沒有索引器,這意味著我們無法在kube-api請求中過濾角色綁定,除非我們?yōu)榻巧壎ㄌ砑右韵滤饕鳎?/p>
- err = mgr.GetFieldIndexer().IndexField(context.Background(), &rbacv1.RoleBinding{}, ".subjects", func(rawObj runtime.Object) []string {
- var fieldValues []string
- rolebinding := rawObj.(*rbacv1.RoleBinding)
- for _, subject := range rolebinding.Subjects {
- if subject.Kind == "ServiceAccount" {
- fieldValues = append(fieldValues, fmt.Sprintf("system:serviceaccount:%s:%s", subject.Namespace, subject.Name))
- } else {
- fieldValues = append(fieldValues, subject.Name)
- }
- }
- return fieldValues
- 獲取CR信息
來自用戶的請求可能是創(chuàng)建,更新或刪除資源。對于創(chuàng)建或更新請求,處理程序從請求正文中提取CR信息。對于刪除請求,處理程序只能獲取CR名稱,而不能獲取整個實例。因此需要調(diào)用kube-api來獲取CR信息
- 考慮角色和ClusterRole
除了角色外,還可以在ClusterRole中定義用戶權(quán)限。區(qū)別在于,角色始終在單個名稱空間中定義權(quán)限,而ClusterRole可以在整個群集中定義權(quán)限。因此,我們還需要檢查ClusterRole中的注釋。解析角色信息時,我們只關(guān)心與CR具有相同名稱空間的角色。
測試與實驗
現(xiàn)在,我要介紹如何測試和試驗基于標(biāo)簽的權(quán)限。在ICN中,此功能是通過kubebuilder與某些CRD/控制器一起開發(fā)的。Webhook支持https,但不支持http。因此,我們需要Webhook server的認(rèn)證。
我們使用cert-manager插件來填充Webhook server的證書。同時,我們還將證書注入到webhook配置中,以便kube-api在發(fā)送webhook請求時可以使用證書。對于開發(fā)或本地測試用例,其中Webhook從本地而不是Pod運行,我們需要手動配置證書。
一旦建立了網(wǎng)絡(luò)連接,我們就可以為測試創(chuàng)建角色和角色綁定。讓我們創(chuàng)建以下角色并將其綁定到用戶。
- apiVersion: rbac.authorization.k8s.io/v1
- kind: Role
- metadata:
- namespace: default
- name: create-intent
- annotations:
- sdewan-bucket-type-permission: |-
- { "mwan3policies": ["app-intent"] }
- rules:
- - apiGroups: ["batch.sdewan.akraino.org"]
- resources: ["mwan3policies"]
- verbs: ["get", "watch", "list", "delete", "create"]
允許用戶創(chuàng)建標(biāo)簽為“sdewan-bucket-type:app-intent”的mwan3policies,但不能創(chuàng)建其他標(biāo)簽。這里一個具體的例子是,用戶可以創(chuàng)建下面左邊的CR,而不是下面右邊的CR。
如果我們嘗試創(chuàng)建下面右邊的CR,則會收到錯誤消息“Error from server (Your roles don't have the permission): error when creating "config/samples/batch_v1alpha1_mwan3policy.yaml"。
結(jié)論
Webhook是kubernetes的一個很好的功能,它賦予kubernetes更大的靈活性。開發(fā)人員可以使用它來實現(xiàn)許多有用的功能。
Controller-runtime項目提供了builder工具,通過它我們可以輕松創(chuàng)建兩種類型的Webhook:驗證Webhook和Mutating Webhook。驗證Webhook用于驗證kube-api的資源,而Muting Webhook可以更新資源字段的值,例如設(shè)置默認(rèn)值。
有時,這兩種類型的Webhook都不符合我們的要求。例如,在本文中,我們需要獲取不在資源正文中的userinfo。在這種情況下,我們需要自行開發(fā)大多數(shù)處理程序代碼,而不是使用builder工具。
參考鏈接:
Kubebuilder book: https://book.kubebuilder.io/introduction.html
Controller-runtime doc: https://github.com/kubernetes-sigs/controller-runtime/blob/master/pkg/doc.go
Akraino SDEWAN agent design: https://wiki.akraino.org/display/AK/Sdewan+config+Agent
Label based permission control patch: https://gerrit.akraino.org/r/c/icn/sdwan/+/3509
*本文部分內(nèi)容翻譯自https://01.org/kubernetes/blogs/chengli3/2020/implement-label-based-permission-control-kubernetes-using-webhook,如有侵權(quán)請聯(lián)系刪除