k8s基於RBAC的認證、授權介紹和實踐

語言: CN / TW / HK

在K8S中,當我們試圖通過API與叢集資源互動時,必定經過叢集資源管理物件入口kube-apiserver。顯然不是隨隨便便來一個請求它都歡迎的,每個請求都需要經過合規檢查,包括Authentication(身份驗證)、Authorization(授權)和Admission Control(准入控制)。通過一系列驗證後才能完成互動。

Kubernetes API 請求從發起到持久化到ETCD資料庫中的過程如下:

“三個A”我們可以簡單理解為:

Authentication你是誰? 你能登入系統麼? Authorization你想做什麼? 你有相應的許可權麼? Admission Control :在apiserver中准入控制會以控制器外掛的方式存在,類似於各類web框架中的中介軟體,可以在kube-apiserver的yml中新增控制器外掛 --enable-admission-plugins 開啟。

這篇小作文我們主要來學習K8S中關於認證與授權相關的知識,看看他們是如何實現的。包含如下內容:

K8S 通過證書認證 K8S 通過RBAC 授權

一、 K8S 通過證書認證

Authentication(身份認證),即核查使用者能否進入K8s叢集。一般來說k8s中有兩類使用者,普通使用者和服務賬戶(Service Account)。

普通使用者,使用者是人,即使用者可以通過 kubectl 命令、或通過REST請求訪問 API, 但是請注意K8s不提供普通使用者管理的資源物件 ,那所謂的普通使用者哪裡的?很簡單隻要你能通過k8s身份認證策略那麼你就是一個普通使用者。而Service Account 則是針對執行在 Pod 中的程序而言的。

K8S的幾種驗證方式:

Certificate Token OpenID Web Hook

其中Certificate(證書)是在普通使用者(客戶端)中被廣泛使用的驗證方式。通過客戶端證書進行身份驗證時,客戶端必須先獲得一個有效的 x509 客戶端證書,然後Kubernetes API伺服器通過驗證這個證書來驗證你的身份。當然你的X509證書必須由叢集 CA 證書籤名。這其實就是HTTPS加密中的一部分,只不過是CA是K8S自簽名的CA證書。

首先我們通過openssl建立一個使用者私鑰

openssl genrsa -out develop1.key 2048

通過user.key 生成CSR(證書籤名請求),Kubernetes 使用證書中的 'subject' 的通用名稱(Common Name)欄位來確定使用者名稱,Organization Name 作為組。

openssl req -new -key develop1.key -out develop1.csr -subj "/CN=develop1/O=devops"

有了CSR,我們就可以把它交給K8S admin通過叢集CA簽署客戶端證書。kubeadm建立的叢集證書對儲存在master節點的 /etc/Kubernetes/pki/ 目錄中,(當然如果你是admin,也可以直接通過API的方式簽署證書)叢集包含一個根 CA,用它簽署所有叢集元件相互通訊所需的證書。

openssl x509 -req -in develop1.csr -CA /etc/kubernetes/pki/ca.crt \
-CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out develop1.crt -days 30

這樣我們獲得了一個被叢集CA簽署過的證書 develop1.crt

develop1.crt  develop1.csr  develop1.key

檢視證書內容 openssl x509 -noout -text -in develop1.crt 包含CN/O,以及證書過期時間。

好了,有了證書之後,下一步我們需要配置 kubecofnig 使 kubectl 可以正常訪問apiserver,關於 kubeconfig 可參考官方文件 organize-cluster-access-kubeconfig [1] 這裡我們以配置為主。

預設情況下, kubectl 讀取  $HOME/.kube/config 作為配置檔案。也可以通過兩種方式為  kubectl 指定配置檔案:

環境變數  KUBECONFIG 命令列引數  --kubeconfig

現在通過kubectl來建立config中的叢集入口

kubectl config set-cluster kubernetes \
--server=https://apiserver.cluster.local:6443 \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true

建立使用者入口

kubectl config set-credentials develop1 \
--client-certificate=$HOME/private_key/develop1.crt \
--client-key=$HOME/private_key/develop1.key \
--embed-certs=true

建立上下文

kubectl config set-context develop1 \
--cluster=kubernetes \
--user=develop1

指定當前context

$ kubectl config set current-context develop1
Property "current-context" set.
#檢視當前context,已繫結develop1
$ kubectl config current-context
develop1

通過 kubectl config view 檢視當前的config

這樣我們 kubectl 已經配置完畢,但是此時我們只完成了 Authentication ,並沒有獲得許可權

$ kubectl get pod
Error from server (Forbidden): pods is forbidden: User "develop1" cannot list resource "pods" in API group "" in thenamespace "default"

可以看到develop1沒有對名稱空間 defaultlist 許可權。所以接下來我們來學習 Authorization 授權相關內容。

二、K8S 通過RBAC 授權

RBAC(Role-Based Access Control)即基於角色的訪問控制,在各類大型系統如虛擬化Vcenter、各類雲服務以及眾多toB軟體訪問控制中被大量使用。關於RBAC可參考一篇譯文: [譯] 基於角色的訪問控制(RBAC):演進歷史、設計理念及簡潔實現(Tailscale, 2021) [2]

k8s作為企業內部重要雲基礎設施並不希望每個使用平臺的使用者都可以不受限制的建立、修改和刪除資源。同時伴隨著叢集節點、應用程式和團隊數量的增加,你需要一種安全措施將使用者或應用許可權控制在某個範圍內,這就K8S 在V1.8正式引入RBAC所要做的事(其他鑑權機制本文不涉及)。

K8S的RBAC 主要由Role、ClusterRole、RoleBinding 和 ClusterRoleBinding 等資源實現。模型如下:

Role、ClusterRole

角色是一組許可權規則的集合,Role 用來定義某個名稱空間內的訪問許可權,而ClusterRole 則是一個叢集作用域的資源。為啥要用兩個資源?因為Kubernetes 物件的作用域已經被劃分為叢集和名稱空間兩部分了。需要注意:角色只有授權沒有禁止的操作。

構成一個 Rule 需要宣告三部分:

apiGroups :資源所屬的API組: "" 預設為 core 組資源,如:extensions、apps、batch等。 Kubernetes API 參考文件 [3] resources :資源,如:pods、deployments、services、secrets 等。 verbs :動作,如:get、list、watch、create、delete、update 等。

現在我們來建立一個可以讀取預設名稱空間 default 的Role,它的api版本為: rbac.authorization.k8s.io/v1

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: develop-defualt
rules:
- apiGroups: [""] #core api組
resources: ["pods"]
verbs: ["get", "watch", "list"]

此時還沒有api互動許可權,所以應該通過kube-admin來建立

# kubectl apply -f role.yml
role.rbac.authorization.k8s.io/develop-defualt created

RoleBinding、ClusterRoleBinding

上面我們已經建立了一個帶許可權的角色,下一步就瞭解如何將角色關聯到使用者。角色繫結是將我們角色中定義好的許可權賦予一個或者一組使用者,即上圖Sujbect。RoleBinding 在指定的名字空間中執行授權,而 ClusterRoleBinding 在叢集範圍執行授權。

圖中展示了三種繫結方式,除了常規的繫結各自作用域的角色外,RoleBinding還可以繫結叢集級別的ClusterRole。有啥用呢?當我們要對namespace做授權時,通常可以建立namespace中的Role進行繫結,如果管理幾百個NS則需建立相應數量的NS Role,顯然不是很棒,所以我們將RoleBinding繫結到叢集的ClusterRole,只需幾個ClusterRole就可以將幾百個NS做訪問控制了。

我們將上面建立的 develop-defualt 角色做繫結:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: develop-rolebinding
namespace: default #授權的名稱空間為default
subjects:
- kind: User
name: develop1 # 繫結develop1使用者
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: develop-defualt #繫結Role
apiGroup: rbac.authorization.k8s.io

通過admin建立RoleBinding

# kubectl apply -f role-binding.yml
rolebinding.rbac.authorization.k8s.io/develop-rolebinding created

ok,此時在使用 kubectl get pod 時,就能獲得結果了。

$ kubectl get pod
NAME READY STATUS RESTARTS AGE
web-85549dcb84-nb67c 1/1 Running 0 12d
web-85549dcb84-z95sj 1/1 Running 0 12d

ServiceAccount授權和普通使用者相似,這裡不再贅述。有興趣的讀者可以參考官方文件學習。

以上我們對K8S中認證和授權做了基本介紹,以及對建立一個使用者並授權pod讀取許可權做了實踐。

希望小作文對你有些許幫助,如果內容有誤請指正。

您可以隨意轉載、修改、釋出本文,無需經過本人同意。通過部落格閱讀: iqsing.github.io [4]

References

[1] organize-cluster-access-kubeconfig:  https://kubernetes.io/zh/docs/concepts/configuration/organize-cluster-access-kubeconfig/

[2] [譯] 基於角色的訪問控制(RBAC):演進歷史、設計理念及簡潔實現(Tailscale, 2021):  https://arthurchiao.art/blog/rbac-as-it-meant-to-be-zh/

[3] Kubernetes API 參考文件:  https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#-strong-api-groups-strong-

[4] iqsing.github.io:  https://iqsing.github.io