使用 Role 管理 Kubernetes Namespace 權限
Kubernetes 的 RBAC(Role-Based Access Control)可以用來控管「誰」可以在「哪個範圍」對「哪些資源」執行「哪些操作」。這篇文章會示範如何建立一個名為 dockertest-user 的使用者,並透過 Role 與 RoleBinding 限制它只能在 dockertest namespace 中讀取 Pod。
這次的目標很單純:dockertest-user 可以在 dockertest namespace 內執行 get、list、watch Pod,但不能刪除 Pod,也不能跨到其他 namespace 查詢資源。
RBAC 的基本概念
在開始操作前,先快速整理這次會用到的幾個物件:
Role:定義某個 namespace 內允許操作的資源與動作。RoleBinding:把Role綁定到指定的使用者、群組或 ServiceAccount。CertificateSigningRequest:讓 Kubernetes 簽發 client certificate,讓使用者可以透過憑證向 API Server 驗證身分。Context:在 kubeconfig 中指定要使用的 cluster、user 與預設 namespace。
Role vs ClusterRole
Role 與 ClusterRole 都是用來定義權限規則,差別在於作用範圍不同。
| 類型 | 作用範圍 | 適合情境 |
|---|---|---|
Role |
單一 namespace | 只想管理某個 namespace 內的資源,例如只允許使用者讀取 dockertest namespace 的 Pod。 |
ClusterRole |
整個 cluster | 需要管理 cluster-wide 資源,或想建立可重複套用到不同 namespace 的權限範本。 |
Role 一定屬於某個 namespace,因此它只能描述該 namespace 內的資源權限。像這篇文章使用的 dockertest-role,就是只允許操作 dockertest namespace 中的 Pod。
ClusterRole 不屬於任何 namespace,因此可以用來管理節點(Node)、Namespace、PersistentVolume 等 cluster-wide 資源。除此之外,ClusterRole 也可以描述一般 namespaced resource 的權限,例如 Pod、Service、Deployment。這種做法常用在想把同一組權限重複套用到不同 namespace 的情境。
RoleBinding vs ClusterRoleBinding
RoleBinding 與 ClusterRoleBinding 都是用來把權限授予指定對象,差別同樣在於授權範圍。
| 類型 | 作用範圍 | 可以綁定的角色 | 授權結果 |
|---|---|---|---|
RoleBinding |
單一 namespace | Role 或 ClusterRole |
只在該 namespace 內授權。 |
ClusterRoleBinding |
整個 cluster | ClusterRole |
在整個 cluster 範圍授權。 |
RoleBinding 最常見的用法,是把某個 namespace 裡的 Role 綁定給使用者、群組或 ServiceAccount。它也可以綁定 ClusterRole,但授權效果仍然會被限制在 RoleBinding 所在的 namespace 中。
ClusterRoleBinding 則會把 ClusterRole 的權限授予整個 cluster 範圍。這代表如果某個 ClusterRole 允許讀取 Pod,透過 ClusterRoleBinding 綁定後,使用者就可能在所有 namespace 中讀取 Pod。因此使用 ClusterRoleBinding 時要更謹慎,避免不小心給出過大的權限。
簡單來說,如果權限只需要限制在單一 namespace,優先使用 Role 搭配 RoleBinding;如果真的需要跨 namespace 或管理 cluster-wide 資源,再考慮使用 ClusterRole 與 ClusterRoleBinding。
建立使用者憑證
Kubernetes 本身沒有一般帳號密碼式的 User 物件。若要建立一般使用者,可以透過 client certificate 讓 Kubernetes 依照憑證中的 CN 辨識使用者名稱。
先產生 dockertest-user 的私鑰:
1 | openssl genrsa -out dockertest-user.key 2048 |
接著用這把私鑰產生 CSR,這裡的 /CN=dockertest-user 很重要,因為 Kubernetes 之後會把它視為使用者名稱。
1 | openssl req -new -key dockertest-user.key -out dockertest-user.csr -subj "/CN=dockertest-user" |
CSR 檔案建立後,要先轉成 base64 字串,再放進 Kubernetes 的 CertificateSigningRequest 設定檔中。
1 | cat dockertest-user.csr | base64 -w 0; echo "" |
建立 CertificateSigningRequest
dockertest_rbac_v1.yml 是用來送出 CSR 的設定檔,其中 signerName 使用 kubernetes.io/kube-apiserver-client,代表這張憑證會用於 Kubernetes API Server 的 client authentication。
1 | apiVersion: certificates.k8s.io/v1 |
套用設定檔後,Kubernetes 會建立一筆待核准的 CSR。
1 | kubectl apply -f dockertest_rbac_v1.yml |
接著由具備管理權限的使用者核准這筆 CSR。
1 | kubectl certificate approve dockertest-csr |
核准完成後,可以查看 CSR 狀態,並把 Kubernetes 簽發好的憑證匯出成 dockertest-user.crt。
1 | kubectl get csr |
到這裡,dockertest-user.key 是使用者私鑰,dockertest-user.crt 則是 Kubernetes 簽發後可用來連線 API Server 的 client certificate。
建立 kubeconfig context
接著要讓 kubectl 知道如何使用這組憑證。這次使用的 context 設定檔為 $HOME/.kube/dockertest-config:
1 | apiVersion: v1 |
需要注意的是,這份 dockertest-config 不是完整的 kubeconfig。它只定義了 dockertest-user 與 dockertest-context,但 cluster: minikube 的詳細連線資訊仍然來自原本的 $HOME/.kube/config。
也就是說,如果只用 --kubeconfig dockertest-config 指定這個檔案,kubectl 會找不到 minikube cluster 的完整設定。正確做法是先保留原本的 kubeconfig,再透過 KUBECONFIG 把備份檔和這份額外設定檔一起載入,最後輸出成新的單一 kubeconfig。
1 | cd $HOME/.kube |
KUBECONFIG 使用多個檔案時,只是讓目前 shell 中的 kubectl 以串聯方式讀取設定;它不會自動把多個檔案寫回成單一檔案。因此這裡先把原本的 config 備份成 config.bak,再用 config.bak 加上 dockertest-config 作為輸入,透過 kubectl config view --flatten 重新產生合併後的 config。
合併完成後,新的 $HOME/.kube/config 會同時包含原本的 minikube context,以及新增的 dockertest-context。如果想確認差異,可以像截圖中一樣分別查看 config.bak 與 config,確認新的 config 已經多出 dockertest-user 與 dockertest-context。
確認設定合併完成後,可以查看目前是否已有 dockertest-context,並切換到這個 context。
1 | kubectl config get-contexts |
此時如果直接查詢資源,會看到一連串 Forbidden。這代表 dockertest-user 已經通過憑證驗證,但還沒有被授權操作任何 Kubernetes 資源。
建立 Role
接著建立 Role,限制 dockertest-user 只能在 dockertest namespace 中讀取 Pod。
dockertest_role_v1.yml 的內容如下:
1 | apiVersion: rbac.authorization.k8s.io/v1 |
這裡有幾個重點:
namespace: dockertest表示這個 Role 只在dockertestnamespace 內有效。resources: ["pods"]表示只授權 Pod,不包含 Service、Deployment 或其他資源。verbs: ["get", "list", "watch"]表示只能讀取,不能建立、修改或刪除。
建立 RoleBinding
Role 只定義權限本身,還需要透過 RoleBinding 把權限授予指定使用者。
dockertest_rolebinding_v1.yml 的內容如下:
1 | apiVersion: rbac.authorization.k8s.io/v1 |
subjects.name 必須和憑證中的 CN 一致。前面產生 CSR 時使用的是 /CN=dockertest-user,因此這裡也要填入 dockertest-user。
依序套用 Role 與 RoleBinding:
1 | kubectl apply -f dockertest_role_v1.yml |
驗證權限
建立完成後,可以用 kubectl auth can-i 先檢查授權結果。
1 | kubectl auth can-i list pods -n dockertest --as dockertest-user |
結果可以看到:
dockertest-user可以在dockertestnamespace 列出 Pod。dockertest-user不能刪除 Pod。dockertest-user不能在argocdnamespace 列出 Pod。
最後切換到 dockertest-context 後,直接執行 kubectl get pods,可以成功看到 dockertest namespace 內的 Pod。
1 | kubectl config use-context dockertest-context |
小結
這次的流程從憑證驗證開始,再透過 RBAC 控制授權範圍。整體步驟可以整理成:
- 產生
dockertest-user.key與dockertest-user.csr。 - 建立並核准 Kubernetes
CertificateSigningRequest。 - 匯出 Kubernetes 簽發的
dockertest-user.crt。 - 建立使用
dockertest-user的 kubeconfig context。 - 建立
Role定義可操作的資源與 verbs。 - 建立
RoleBinding將 Role 綁定到dockertest-user。 - 使用
kubectl auth can-i與實際kubectl get pods驗證結果。
在 Kubernetes RBAC 中,Role 負責描述權限,RoleBinding 負責指定權限要給誰。只要掌握這個拆分方式,就能更清楚地管理不同使用者或服務帳號在 namespace 內的操作範圍。