iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
DevOps

30 天挑戰 CKAD 認證!菜鳥的 Kubernetes 學習日記系列 第 19

【Day19】扮演 Kubernetes 的權限總管:RBAC 授權機制

  • 分享至 

  • xImage
  •  

gh

前情提要

昨天我們看了 Security ContextServiceAccount。如何透過 Security Context 來強化 Pod 對內 的安全性,像是限制容器以非 root 身份運行、移除不必要的系統權限。接著,我們轉向了 Pod 對外 的安全性,透過 ServiceAccount 給予了 Pod 一個在叢集裡的明確「身份」。

然而,在實戰中我們有建立一個名為 dashboard-sa 的 Service Account,在加入權限之前它依然被 Kubernetes API 拒絕存取。直到我們加入了 RoleRoleBinding 這兩個物件,才成功地賦予了它讀取 Pod 資訊的權限。

因此今天要來看看 Kubernetes 究竟是如何管理「誰(Subject)可以對「什麼資源(Resource)」做「哪些操作(Verb)」?這背後的授權機制,就是 RBAC (Role-Based Access Control)

Authentication (認證) vs. Authorization (授權)

在深入看到 RBAC 的設定之前,必須先釐清 Authentication (認證) 和 Authorization (授權) 的觀念:

  1. Authentication (認證):你是誰?
    這是 API Server 收到的第一個問題,它只負責 驗證發出請求者的身份。我們以雲端環境來看的話,就像在 GCP 中,必須先透過 Google 帳號密碼登入,或是讓應用程式載入 Service Account 的金鑰檔案,GCP 才能確認「你是誰」。這個驗證身份的過程,就是 Authentication (認證)。在 K8s 中,身份分為給真人用的 User Account 和給機器、應用程式用的 ServiceAccount

  2. Authorization (授權)
    當 API Server 確認身份後,第二個問題就來了。這個身份被允許做哪些事? 延續 GCP 的例子,即使成功登入,帳號是否能建立 VM、刪除 GCS 儲存桶?這就取決於你的帳號被賦予了什麼 IAM 角色 (Role),例如 Compute Admin 擁有 VM 的完整權限,而 Storage Object Viewer 則只能讀取儲存桶中的物件。這個「根據身份決定權限」的過程,就是 Authorization (授權)。這個「決定權限邊界」的過程,就是授權。在 Kubernetes 中,RBAC 就扮演了 GCP IAM 的角色,負責為通過認證的身份(不論是 User 還是 ServiceAccount)精準地分配權限。

RBAC 的四大核心 API 物件

RBAC 的世界就是由這四種 API 物件所組成,它們兩兩一組,分別對應不同的權限作用域:

  • Role & RoleBinding (Namespace 級別)

    • Role:定義一組權限規則,但它的權力 僅限於單一 Namespace 之內
    • RoleBinding:把 Role 綁定到一個身份(Subject)上,讓這個身份在 該 Namespace 內 擁有對應權限。
  • ClusterRole & ClusterRoleBinding (Cluster 級別)

    • ClusterRole:定義一組權限規則,權力範圍是 整個 Cluster
    • ClusterRoleBinding:把 ClusterRole 綁定到一個身份上,讓這個身份在 整個 Cluster 範圍 都擁有對應權限。

權限語言:API Groups, Resources, Verbs

要定義一條精準的權限規則,必須搞懂它的「語法」有三個欄位:

  • Resources:你要操作的「資源」是什麼。常見的資源有 pods, deployments, services, nodes, secrets 等。
  • Verbs:你要執行的「操作」是什麼。常見的動詞有 get (取得), list (列出), watch (監看), create (建立), update (更新), patch (部分更新), delete (刪除)。
  • API Groups:你要操作的資源隸屬於哪個「API 群組」。Kubernetes 的 API 為了便於管理,被分成了不同的群組。
    • 核心資源(如 pods, services, configmaps)隸屬於核心群組,在 YAML 中用 "" (空字串) 表示。
    • 其他資源則有自己的命名群組,例如 deploymentsreplicasets 隸屬於 apps 群組,networkpolicies 隸屬於 networking.k8s.io 群組。

關於這邊權限的語言其實很好理解,Resources 就是在編寫 yaml 檔的 kind 欄位;Verbs 是很直覺的英文單字的操作;而 API Groups 就是 yaml 檔檔 apiVersion 欄位但是移除版本號。用這樣的方式來記就不會很複雜很難記!

實戰 🔥

Roles & Binding Roles

我們先從 Cluster 目前的設定開始,進入 Control Plane 查看 authorization mode:

docker exec -it kind-control-plane bash

cat /etc/kubernetes/manifests/kube-apiserver.yaml

gh

Kubernetes 本身的系統元件(像 kube-proxy、kube-scheduler、kube-controller-manager 等)並不是「特權外掛」,它們也必須透過 RBAC 拿到 API Server 的授權才能工作。

接著查看目前 Cluster 所有 Roles,代表 Kubernetes 也有用 RBAC 在管理系統元件,(像 kube-proxykube-schedulerkube-controller-manager 等)並不是「特權外掛」,它們也必須透過 RBAC 拿到 API Server 的授權才能工作。我們可以先看一下官方是如何配置 RBAC 的:

kubectl get roles.rbac.authorization.k8s.io -A

gh

kube-proxy 為例,查看他的 Role 定義:

kubectl describe roles.rbac.authorization.k8s.io -n kube-system kube-proxy

它代表 kube-proxy 這個角色可以讀取 kube-proxy 物件的 ConfigMap。

gh

單看 Role 並不能說明誰能使用它,必須透過 RoleBinding 綁定到一個具體的「身份 (Subject)」才會生效,因此我們進一步查看這個 Role 綁定給誰:

kubectl describe rolebindings.rbac.authorization.k8s.io -n kube-system kube-proxy

這邊可以看到綁定給一個 Group,只要在那個 Group 裡面不管是 User 還是 Service Account 都具備對應 Role 的權限:

gh

建立 User Account 與 Namespace

我們實戰建立一個新使用者 sean,並給他自己的 Namespace。
這部分比較偏向「底層驗證 (kubeconfig)」範疇,所以會先帶過,明天再深入 kubeconfig。

# 建立 Namespace
kubectl create ns sean

進入 KinD 的 Control Plane 節點:

# 因為我是 KinD,所以先進入 Master Node
docker exec -it kind-control-plane bash

建立金鑰與憑證,模擬一個使用者身份:

# 建立資料夾
mkdir -p /root/sean
cd /root/sean

# 產生 private key
openssl genrsa -out 695.key 2048

# 產生簽署請求 Certificate Signing Request(CSR)
# CN 為帳號名稱,O 為群組
openssl req -new -key 695.key -out 695.csr -subj "/CN=sean/O=ithome"

# 產生憑證
# 找尋 K8s Cluster 的私鑰與 CA 憑證,如此 K8s 才會核淮並產生新的憑證。
openssl x509 -req -in sean.csr \
  -CA /etc/kubernetes/pki/ca.crt \
  -CAkey /etc/kubernetes/pki/ca.key \
  -CAcreateserial \
  -out sean.crt \
  -days 500

gh

將憑證與金鑰從 Master Node 複製出來:

# 從 KinD 把 crt 和 key 拿出來
docker cp kind-control-plane:/root/sean .

gh

新增一個使用者身份 sean,需要指定剛所建立的憑證與私有金鑰:

kubectl config set-credentials sean --client-certificate=/root/sean/sean.crt --client-key=/root/sean/sean.key

gh

建立 Contexts:sean-context

kubectl config set-context sean-context --cluster=kind-kind --namespace=sean --user=sean

gh

查看 Contexts,確認新的 Contexts 已被建立:

kubectl config get-contexts

gh

嘗試以新的 sean 的身份存取 Namespace sean 的 Pods:

# 有兩種用法
# 不管在 Namespace sean 還是 default 都是 forbidden
kubectl --context=sean-context get pods -n sean

kubectl get pods --as sean

因為還沒有權限,所以被 Forbidden:

gh

接著,我們透過 Role 和 RoleBinding 給予 sean 查看 Pods 的權限,這邊都會在 Namespace sean 底下進行。另外,為了 CKAD 考試效率會常用命令式,但實務上使用聲明式會比較好。

命令式:

# Role
kubectl create role sean --namespace=sean --verb=list,watch,get --resource=pods

# Role Binding
kubectl create rolebinding sean-binding --namespace=sean --role=sean --user=sean

聲明式:

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

# Role Binding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: sean-binding
  namespace: sean
subjects:
- kind: User
  name: sean
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: sean
  apiGroup: rbac.authorization.k8s.io

可以看到 Role 和 Binding 都被建立好了:

gh

重新查看 Namespace sean 的 Pods:

gh

如果嘗試建立 Deployments 或編輯 Pod,因為沒有授權,依然會被拒絕:

gh
gh

現在我們希望 sean 依舊能查看 Pod,同時有權限建立和查看 Deployment。
因此編輯 Role,加上 apps 群組下的 Deployments:

kubectl edit roles.rbac.authorization.k8s.io -n sean sean
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: "2025-09-26T17:54:44Z"
  name: sean
  namespace: sean
  resourceVersion: "355808"
  uid: 12f70cb7-79f7-4454-a345-062c969747b3
rules:
- apiGroups:
  - ""
  resourceNames:
  - sean-nginx
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - apps
  resources:
  - deployments
  verbs:
  - list
  - get
  - watch
  - create
  - delete

測試用 sean 在 Namespace sean 建立 Deployment:

kubectl create deployment sean-nginx --image=nginx -n sean --as sean

我在加上建立 deployment 權限的同時,在 Pods 有指定 resourceNames,等於說 User sean 只能查看名叫 sean-nginx 的 Pod,其餘 Pod 一樣都會是 forbidden:

gh

查看最終 Role 與 RoleBinding:

gh

Cluster Roles & Cluster Roles Binding

接下來看叢集級別的授權。列出所有 Cluster Roles:

# Cluster Roles
kubectl get clusterroles

# Describe
kubectl describe clusterroles cluster-admin

接下來我們可以查看 Cluster Role 的權限,以 cluster-admin 為例的話,他是 Kubernetes 裡面最高等級的權限之一:

PolicyRule 裡面,可以看到:

  • Resources: *.* → 代表所有 API 群組 (*) 下的所有資源 (*)。
  • Verbs: [*] → 代表允許所有操作(getlistcreateupdatedelete...)。
  • Non-Resource URLs: [*] → 對於非資源型 API(例如 /metrics, /healthz 這些 endpoint)也全部允許。

這表示 cluster-admin 這個 ClusterRole 對 Kubernetes 叢集的任何東西都具有 完全控制權

gh

看看他 Binding 的對象是:

# Cluster Roles Binding
kubectl get clusterrolebindings | grep cluster-admin

# Describe
kubectl describe clusterrolebindings.rbac.authorization.k8s.io cluster-admin 

下圖可以看到這樣代表 所有屬於 system:masters 群組的使用者,自動就會擁有 cluster-admin 的最高權限。

gh

我們最後來賦予 sean 查看 Nodes 的權限。

kubectl get nodes --as sean

可以看到因為還沒有權限所以被 forbidden:

gh

因為 Node 是 Cluster 級資源,所以需要建立 ClusterRole,另外要記得 Cluster Role 是屬於 Namespace 等級的物件,因此不需要指定 Namespace:

命令式:

# Cluster Role
kubectl create clusterrole sean-cluster-role --verb=get,list,watch --resource=nodes

# Cluster Role Binding
kubectl create clusterrolebinding sean-cluster-role-binding --clusterrole=sean-cluster-role --user=sean

聲明式:

# Cluster Role
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: sean-cluster-role
rules:
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - list
  - watch

---

# Cluster Role Binding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: sean-cluster-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: sean-cluster-role
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: sean

gh

再次查看 Nodes 就成功了:

gh

總結

今天我們完整實戰了 RBAC,從系統內建的 kube-proxy Role/RoleBinding 開始,逐步拆解 Kubernetes 授權的運作方式:

  • Role / RoleBinding:專注於 Namespace 級別的權限。
  • ClusterRole / ClusterRoleBinding:擴展到整個 Cluster。

透過建立新使用者 sean,我們親身體驗了「預設拒絕,明確授權」的安全原則。剛建立的帳號什麼都不能做,直到綁定合適的 Role,才被允許存取 Pods;而進一步建立 ClusterRole 之後,才能查詢到 Node。這也呼應了 RBAC 的核心:把身份與權限拆開,然後用精準的權限設定去組合

RBAC 解決了「認證之後,誰能做什麼」的問題。但這還不是完整的 Kubernetes 安全控制鏈條。在一個請求真正抵達 Pod 或控制平面之前,還有一道把關者,就是 Admission Controllers。它們負責「攔截」所有送進 API Server 的請求,決定要不要放行、要不要修改,甚至要不要丟出警告。再加上後來演進出的 Validating & Mutating Admission Webhooks,我們就能針對自訂需求,讓叢集在「部署」的那一刻就開始落實策略。

因此,明天將會看到 KubeConfig 與 Admission Controllers。從 KubeConfig 定義使用者、憑證、Context,到 RBAC 決定「進來的人」能做什麼,最後 Admission Controllers 決定「送進來的請求」是否符合規範。

下一篇文章:掌握 KubeConfig:Clusters、Users 與 Contexts 的三角關係


上一篇
【Day18】Kubernetes 權限基礎:Security Context 容器安全與 ServiceAccount
下一篇
【Day20】掌握 KubeConfig:Clusters、Users 與 Contexts 的三角關係
系列文
30 天挑戰 CKAD 認證!菜鳥的 Kubernetes 學習日記21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言