搞懂K8s的鑒權(quán)
前言
本文介紹K8s中的鑒權(quán)模塊。對其4種鑒權(quán)模式都進行了概述講解。結(jié)合例子著重對大家日常中使用最多的RBAC鑒權(quán)模式進行了說明。
鑒權(quán)概述
《搞懂K8s認證》中,我們提到不論是通過kubectl客戶端還是REST請求訪問K8s集群,最終都需要經(jīng)過API Server來進行資源的操作并通過Etcd。整個過程如下圖1所示,可以分成4個階段:
圖1 K8s API請求訪問過程
請求發(fā)起方進行K8s API請求,經(jīng)過Authentication(認證)、Authorization(鑒權(quán))、AdmissionControl(準入控制)三個階段的校驗,最后把請求轉(zhuǎn)化為對K8s對象的變更操作持久化至etcd中。
其中認證主要解決的是請求來源能否訪問的問題。即通過了認證,那么可以認為它是一個合法的請求對象。那么如何去決定請求對象能訪問哪些資源以及對這些資源能進行哪些操作,便是鑒權(quán)所要完成的事情了。
鑒權(quán)的最終目的,是區(qū)分請求對象,限定操作的影響范圍,讓其使用最小的權(quán)限完成自己所要進行操作,從而進一步保證安全。權(quán)限控制的劃分方式有許多種,K8s中提供了4種鑒權(quán)模式,分別為Node、ABAC、RBAC和Webhook。
默認情況下,我們可以從/etc/kubernates/manifests/kube-apiserver.yaml文件中查看apiserver啟動時認證模式,片段如圖2所示:
圖2 kube-apiserver的認證參數(shù)
其中可以使用的參數(shù)如表1所示:
表1 鑒權(quán)模塊參數(shù)標識表
參數(shù)配置 | 含義 | 一般的使用場景 |
--authorization-mode=ABAC | 使用基于屬性的訪問控制(ABAC) | 根據(jù)用戶的用戶名或者組名來控制其對集群資源的訪問權(quán)限,適用于較小的組織或開發(fā)團隊 |
--authorization-mode=RBAC | 使用基于角色的訪問控制(RBAC) | 自定義ServiceAccount,綁定資源根據(jù)角色來控制資源的訪問權(quán)限,適用于較大型的組織或者開發(fā)運維團隊 |
--authorization-mode=Webhook | 使用HTTP回調(diào)模式,允許你使用遠程REST端點管理鑒權(quán) | 將鑒權(quán)角色交給外部服務(wù)進行處理,根據(jù)自身需求,定制和擴展鑒權(quán)策略,如自定義Webhook鑒權(quán)模塊對跨云平臺的應(yīng)用進行集中的的訪問控制 |
--authorization-mode=Node | 針對kubelet發(fā)出的API請求執(zhí)行鑒權(quán) | 驗證節(jié)點身份,確保只有經(jīng)過身份驗證且具有所需權(quán)限的Node才能連接到K8s集群 |
--authorization-mode=AlwaysDeny | 阻止所有請求 | 一般僅用作測試 |
--authorization-mode=AlwaysAllow | 允許所有請求 | 不需要API請求進行鑒權(quán)的場景 |
如圖2所示,可以同時配置多個鑒權(quán)模塊(多個模塊之間使用逗號分隔),排在靠前的模塊優(yōu)先執(zhí)行,任何模式允許或拒接請求,則立即返回該決定,并不會與其他鑒權(quán)模塊協(xié)商。
Node鑒權(quán)
Node鑒權(quán)是一種特殊用途的鑒權(quán)模式,旨在對kubelet發(fā)出API請求進行授權(quán)。Node鑒權(quán)允許kubelet執(zhí)行API的操作分成讀和寫兩部分。讀取操作控制范圍為:services、endpoints、nodes、pods以及綁定到kubelet節(jié)點 Pod相關(guān)的secret、configmap、pvc和持久卷。寫入操作的范圍主要是節(jié)點和節(jié)點狀態(tài)、Pod和Pod狀態(tài)以及事件,若要限制kubelet只能修改自己的節(jié)點,則還需要在Apiserver啟動時,開啟NodeRestriction準入插件(見圖2第二個紅框)。
開啟Node鑒權(quán)模塊后,kubellet為了獲取授權(quán),必須使用一個特定規(guī)則的憑據(jù),如圖3所示:
圖3 kubelet的證書憑據(jù)
從圖中我們看到,kubelet使用了一個證書憑據(jù),其中O=system:nodes表示其所在組,CN=system:node:paas-cnp-k8s-kce-01表示其用戶名,滿足了Node鑒權(quán)模塊要求的組名必須為system:nodes,用戶名必須為system:node:<nodeName>的要求。其中<nodeName>默認由hostname或kubelet --hostname-override選項提供指定,其必須與kubelet提供的主機名稱精確匹配。
system:nodes是K8s的內(nèi)置用戶組,我們可以通過其默認的ClusterRoleBinding,如圖4所示:
圖4 system:nodes的ClusterRoleBinding內(nèi)容
我們可以發(fā)現(xiàn),它指示指向了system:node這個ClusterRole,并沒有subjects的內(nèi)容,即其沒有綁定system:node:paas-cnp-k8s-kce-01用戶也沒有綁定system:nodes組。其正是因為K8s基于 Node鑒權(quán)模塊來限制kubelet只能讀取和修改本節(jié)點上的資源,并不是使用 RBAC來鑒權(quán)(涉及到部分RBAC的內(nèi)容,下文會進行詳解)。
ABAC鑒權(quán)
基于屬性的訪問控制,K8s中可以表述將訪問策略授予用戶或者組。與RBAC不同的點在于,其策略是由任何類型的屬性(用戶屬性、資源屬性、對象、環(huán)境等)進行描述。
啟用ABAC模式,類似于圖2需要在apiserver啟動時指定--authorization-mode=ABAC以及--authorization-policy-file=<策略文件路徑> 。圖5是K8s官網(wǎng)給出的一個策略樣例文件:
圖5 ABAC策略實例文件內(nèi)容
文件中每行都是一個JSON對象,其中版本控制屬性"apiVersion": "abac.authorization.kubernetes.io/v1beta1"和"kind": "Policy"可以理解成固定寫法,是被K8s本身所使用,便于以后進行版本控制和轉(zhuǎn)換。spec部分,其中user,來自于--token-auth-file的用戶字符串,其指定的user名稱必須與這個文件中的字符串相匹配;group,必須與經(jīng)過身份驗證的用戶的一個組匹配, system:authenticated 匹配所有經(jīng)過身份驗證的請求。 system:unauthenticated 匹配所有未經(jīng)過身份驗證的請求。其他的匹配屬性,主要描述被訪問的訪問,分為資源屬性和非資源屬性(其具體定義可參見官網(wǎng))。readonly,主要限制是否只允許對資源進行 get、list 和 watch 操作,非資源屬性只進行g(shù)et操作。
例如:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "alice", "namespace": "*", "resource": "*", "apiGroup": "*"}}
表示用戶alice可以對所有namespace下的所有資源進行任何操作;
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "bob", "namespace": "projectCaribou", "resource": "pods", "readonly": true}}
表示用戶bob只能對namespace為projectCaribou的Pod進行l(wèi)ist、get和watch操作。
對于ServiceAccount的ABAC管控。Service Account會自動生成一個ABAC用戶名,其格式為:system:serviceaccount:<namespace>:<serviceaccountname>,創(chuàng)建新的命名空間時,K8s會為我們在當前namespace下創(chuàng)建一個名為default的ServiceAccount,如果現(xiàn)在假定我們需要namespace為test名為default的ServiceAccount具有該namespace下的全部權(quán)限,則可以添加這樣一條規(guī)則:
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"system:serviceaccount:test:default","namespace":"test","resource":"*","apiGroup":"*"}}
我們發(fā)現(xiàn),ABAC雖然對用戶訪問進行了一定的劃分,但是如果添加了新的ABAC策略,則需要重啟API Server以使其生效,資源的訪問權(quán)限細粒度也只控制到了是否只讀,當用戶規(guī)模增大時,這是遠遠不能滿足需求的。對于較大組織的團隊進行更加細粒度的管控,就需要使用到K8s的RBAC鑒權(quán)模塊了。
RBAC鑒權(quán)
啟用RBAC鑒權(quán),可以如圖2所示,在--authorization-mode的啟動參數(shù)中包含RBAC即可。相對于其他訪問控制方式,RBAC具有如下優(yōu)勢:
- 對集群中的資源和非資源權(quán)限均有完整的覆蓋。
- RBAC由幾個API對象完成。同其他API對象一樣,可以用kubectl或API進行操作和調(diào)整,不必重新啟動ApiServer。
K8s的RBAC主要闡述解決了主體(subject)是什么角色的問題。其中主體就是K8s中的用戶,包含了常規(guī)用戶(User、Group,平時常用的kubectl命令都是普通用戶執(zhí)行的)和服務(wù)賬戶(ServiceAccount,主要用于集群進程與K8s的API通信)。角色決定了能夠?qū)Y源進行什么樣的操作,RBAC中我們可以定義namespace級別的Role也可以定義集群級別的ClusterRole。最后K8s再通過RoleBinding和ClusterRoleBinding把用戶和角色的關(guān)系進行關(guān)聯(lián)綁定,其中RoleBinding既可以綁定Role也可以綁定ClusterRole,ClusterRole指定綁定ClusterRole,最終實現(xiàn)了不同用戶對不同資源進行特定操作的控制。Role針對特定的命名空間,ClusterRole在整個集群范圍內(nèi)都生效,所以后者訪問范圍也更大,能夠限制訪問Node等資源。其關(guān)系圖如圖6所示:
圖6 RBAC整體關(guān)系圖
現(xiàn)在假設(shè)你所在部門使用名為rbac-team的命名空間工作,現(xiàn)在要為部署流水線創(chuàng)建一個新的ClusterRole名為deployment-clusterrole,且僅允許創(chuàng)建Deployment、StatefulSet、DaemonSet三種資源,同時在rbac-team這個命名空間下創(chuàng)建一個新的ServiceAccount名為cicd-test使用這個ClusterRole。K8s中我們可以使用kubectl客戶端或者API資源的方式來實現(xiàn)這個RBAC的功能。
Kubectl客戶端方式。
- 第一步,我們可以先執(zhí)行命令:kubectl create clusterrole deployment-clusterrole --verb=create --resource=deployments,statefulsets,daemonsets 創(chuàng)建所需的ClusterRole,其中--verb代表可以執(zhí)行的操作,--reasource代表授權(quán)操作的資源范圍;
- 第二步,執(zhí)行命令:kubectl -n rbac-team create serviceaccount cicd-test創(chuàng)建要求的ServiceAccount;
- 第三步,限于rbac-test中綁定所需權(quán)限,執(zhí)行命令:kubectl -n rbac-team create rolebinding cicd-rolebinding --clusterrole=deployment-clusterrole --serviceaccount=rbac-team:cicd-test,對新創(chuàng)建的ServiceAccount與我們的ClusterRole進行綁定。
Api資源的方式。
- 第一步,準備ClusterRole的資源描述,創(chuàng)建名為cr-deployment.yaml的文件,如圖7所示:
圖7 deployment-clusterrole資源
其中verbs用于限定可執(zhí)行的操作,可配置參數(shù)有:“get”, “l(fā)ist”, “watch”, “create”, “update”, “patch”, “delete”, “exec”。resources用于限定可訪問的資源范圍,可配置參數(shù)有:“services”, “endpoints”, “pods”,“secrets”,“configmaps”,“crontabs”,“deployments”,“jobs”,“nodes”,“rolebindings”,“clusterroles”,“daemonsets”,“replicasets”,“statefulsets”,“horizontalpodautoscalers”,“replicationcontrollers”,“cronjobs”。apiGroups用于劃分訪問的資源組,可配置參數(shù)有:“”,“apps”, “autoscaling”, “batch”。
- 第二步,準備ServiceAccount的資源描述,創(chuàng)建名為sa-cicd.yaml的文件,如圖8所示:
圖8 sa-cicd資源
- 第三步,準備RoleBinding的資源描述,創(chuàng)建名為rb-cicd.yaml的文件,如圖9所示:
圖9 rolebinding資源
將前面兩步的clusterrole和ServiceAccount進行綁定,其中subjects指明了被授權(quán)的主體,當被授權(quán)對象是User或者Group時,可以使用類似如下片段subjects即可(Group的話只需要將kind的值改為Group):
- kind: User
name: "test-user"
apiGroup: rbac.authorization.k8s.io
- 第四步,使用kubectl -f 分別應(yīng)用上述資源,完成主體(subject)、角色的創(chuàng)建與綁定。
當K8s的進程資源需要使用上述身份憑證進行權(quán)限劃分時,只需要在資源聲明文件中進行配置即可,如圖9所示:
圖10 pod資源使用ServiceAccount
為特定應(yīng)用的Service Account賦權(quán)進行權(quán)限管控也是最安全的最值得推薦的。
APIServer默認的ClusterRole和ClusterRoleBinding對象,其中很多是以"system:"為前綴的,對這些對象的改動可能造成集群故障。例如Node鑒權(quán)模塊提到的system:node,這個ClusterRole為kubelet定義了權(quán)限,如果這個集群角色被改動了,kubelet就會停止工作。
所有默認的ClusterRole和RoleBinding都會用標簽kubernetes.io/bootstrapping: rbac-defaults進行標記。
Webhook鑒權(quán)
啟用Webhook模式的方式與ABAC模式相似,我們需要在apiserver啟動時指定--authorization-mode=ABAC以及一個HTTP配置文件用以指定策略嗎,可以通過參數(shù)--authorization-webhook-config-file=<策略文件路徑>,策略文件配置使用的是kubeconfig文件的格式。users部分表示APIServer的webhook,cluster代表著遠程服務(wù)。圖11部分是K8s官網(wǎng)給出的一個示例。
圖11 Webhook的策略配置示例
當進行認證時,API服務(wù)器會生成一個JSON對象來描述這個動作,對于一個資源類型的請求,其內(nèi)容主要包含了需要被訪問的資源或請求特征,如圖12所示:
圖12 資源類型的Webhook鑒權(quán)請求示例
從圖12中我們可以看到,這個請求是User名為jane,Group為group1、gourp2為主體,請求的資源為命名空間為kittensandpoines下的pods資源,資源所屬group為unicorn.example.org,請求的執(zhí)行操作為get這個資源信息。若我們的Webhook服務(wù)URL同意了這個請求,則可以返回如圖13格式的響應(yīng)體。
圖13 Webhook請求同意響應(yīng)示例
從圖13中我們可以看出,我們只需要填充SubjectAccessReview的status對象信息的值即可。若要拒絕請求,則可以返回圖14或圖15的響應(yīng)。
圖14 Webhook請求拒絕響應(yīng)示例1
圖15 Webhook請求拒絕響應(yīng)示例2
圖14和圖15都是對請求進行拒絕,都給出了拒絕通過的原因,差別在于圖14的拒絕響應(yīng)中增加了denied:true的信息,其表示當我們配置多了多個鑒權(quán)模塊的時候,當這個響應(yīng)返回時立即拒絕請求。(默認當存在多個鑒權(quán)模塊,Webhook拒絕后可以再通過其他模塊進行鑒權(quán),只有當其他模塊也不通過或者不存在時,才禁止訪問)
對于非資源的路徑訪問,生成的JSON請求示例如圖16所示:
圖16 非資源的路徑請求的Webhook鑒權(quán)請求示例
總結(jié)
鑒權(quán)主要是解決“誰可以對什么資源進行哪些操作”的問題。K8s的鑒權(quán)模塊主要有4個,發(fā)生在鑒權(quán)認證階段的第二階段。Node模塊主要針對kubelet需要訪問APIServer的場景;ABAC主要針對User和Group的常規(guī)用戶,控制力度較粗;RBAC即可以用于常規(guī)用戶也可以針對ServiceAccount進行管控,且管控力度十分細膩,是常用的K8s鑒權(quán)方式;Webhook主要用于定制自定義的鑒權(quán)邏輯,可用于跨云的集中式鑒權(quán)。
參考文獻:
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/node/
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/abac/
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/rbac/
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/webhook/ https://www.cnblogs.com/maiblogs/p/16271997.html
https://cloud.tencent.com/developer/article/2149852