昨天我們看了 Security Context
與 ServiceAccount
。如何透過 Security Context 來強化 Pod 對內 的安全性,像是限制容器以非 root 身份運行、移除不必要的系統權限。接著,我們轉向了 Pod 對外 的安全性,透過 ServiceAccount 給予了 Pod 一個在叢集裡的明確「身份」。
然而,在實戰中我們有建立一個名為 dashboard-sa
的 Service Account,在加入權限之前它依然被 Kubernetes API 拒絕存取。直到我們加入了 Role
和 RoleBinding
這兩個物件,才成功地賦予了它讀取 Pod 資訊的權限。
因此今天要來看看 Kubernetes 究竟是如何管理「誰(Subject)可以對「什麼資源(Resource)」做「哪些操作(Verb)」?這背後的授權機制,就是 RBAC (Role-Based Access Control)
。
在深入看到 RBAC 的設定之前,必須先釐清 Authentication (認證) 和 Authorization (授權) 的觀念:
Authentication (認證):你是誰?
這是 API Server 收到的第一個問題,它只負責 驗證發出請求者的身份。我們以雲端環境來看的話,就像在 GCP 中,必須先透過 Google 帳號密碼登入,或是讓應用程式載入 Service Account 的金鑰檔案,GCP 才能確認「你是誰」。這個驗證身份的過程,就是 Authentication (認證)
。在 K8s 中,身份分為給真人用的 User Account
和給機器、應用程式用的 ServiceAccount
。
Authorization (授權)
當 API Server 確認身份後,第二個問題就來了。這個身份被允許做哪些事? 延續 GCP 的例子,即使成功登入,帳號是否能建立 VM、刪除 GCS 儲存桶?這就取決於你的帳號被賦予了什麼 IAM 角色 (Role),例如 Compute Admin
擁有 VM 的完整權限,而 Storage Object Viewer
則只能讀取儲存桶中的物件。這個「根據身份決定權限」的過程,就是 Authorization (授權)
。這個「決定權限邊界」的過程,就是授權。在 Kubernetes 中,RBAC 就扮演了 GCP IAM 的角色,負責為通過認證的身份(不論是 User 還是 ServiceAccount)精準地分配權限。
RBAC 的世界就是由這四種 API 物件所組成,它們兩兩一組,分別對應不同的權限作用域:
Role & RoleBinding (Namespace 級別)
Role
綁定到一個身份(Subject)上,讓這個身份在 該 Namespace 內 擁有對應權限。ClusterRole & ClusterRoleBinding (Cluster 級別)
ClusterRole
綁定到一個身份上,讓這個身份在 整個 Cluster 範圍 都擁有對應權限。要定義一條精準的權限規則,必須搞懂它的「語法」有三個欄位:
pods
, deployments
, services
, nodes
, secrets
等。get
(取得), list
(列出), watch
(監看), create
(建立), update
(更新), patch
(部分更新), delete
(刪除)。pods
, services
, configmaps
)隸屬於核心群組,在 YAML 中用 ""
(空字串) 表示。deployments
和 replicasets
隸屬於 apps
群組,networkpolicies
隸屬於 networking.k8s.io
群組。關於這邊權限的語言其實很好理解,Resources 就是在編寫 yaml 檔的 kind 欄位;Verbs 是很直覺的英文單字的操作;而 API Groups 就是 yaml 檔檔 apiVersion 欄位但是移除版本號。用這樣的方式來記就不會很複雜很難記!
我們先從 Cluster 目前的設定開始,進入 Control Plane 查看 authorization mode:
docker exec -it kind-control-plane bash
cat /etc/kubernetes/manifests/kube-apiserver.yaml
Kubernetes 本身的系統元件(像 kube-proxy、kube-scheduler、kube-controller-manager 等)並不是「特權外掛」,它們也必須透過 RBAC 拿到 API Server 的授權才能工作。
接著查看目前 Cluster 所有 Roles,代表 Kubernetes 也有用 RBAC 在管理系統元件,(像 kube-proxy
、kube-scheduler
、kube-controller-manager
等)並不是「特權外掛」,它們也必須透過 RBAC 拿到 API Server 的授權才能工作。我們可以先看一下官方是如何配置 RBAC 的:
kubectl get roles.rbac.authorization.k8s.io -A
以 kube-proxy 為例,查看他的 Role 定義:
kubectl describe roles.rbac.authorization.k8s.io -n kube-system kube-proxy
它代表 kube-proxy 這個角色可以讀取 kube-proxy 物件的 ConfigMap。
單看 Role 並不能說明誰能使用它,必須透過 RoleBinding 綁定到一個具體的「身份 (Subject)」才會生效,因此我們進一步查看這個 Role 綁定給誰:
kubectl describe rolebindings.rbac.authorization.k8s.io -n kube-system kube-proxy
這邊可以看到綁定給一個 Group,只要在那個 Group 裡面不管是 User 還是 Service Account 都具備對應 Role 的權限:
我們實戰建立一個新使用者 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
將憑證與金鑰從 Master Node 複製出來:
# 從 KinD 把 crt 和 key 拿出來
docker cp kind-control-plane:/root/sean .
新增一個使用者身份 sean,需要指定剛所建立的憑證與私有金鑰:
kubectl config set-credentials sean --client-certificate=/root/sean/sean.crt --client-key=/root/sean/sean.key
建立 Contexts:sean-context
kubectl config set-context sean-context --cluster=kind-kind --namespace=sean --user=sean
查看 Contexts,確認新的 Contexts 已被建立:
kubectl config get-contexts
嘗試以新的 sean 的身份存取 Namespace sean 的 Pods:
# 有兩種用法
# 不管在 Namespace sean 還是 default 都是 forbidden
kubectl --context=sean-context get pods -n sean
kubectl get pods --as sean
因為還沒有權限,所以被 Forbidden:
接著,我們透過 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 都被建立好了:
重新查看 Namespace sean 的 Pods:
如果嘗試建立 Deployments 或編輯 Pod,因為沒有授權,依然會被拒絕:
現在我們希望 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:
查看最終 Role 與 RoleBinding:
接下來看叢集級別的授權。列出所有 Cluster Roles:
# Cluster Roles
kubectl get clusterroles
# Describe
kubectl describe clusterroles cluster-admin
接下來我們可以查看 Cluster Role 的權限,以 cluster-admin
為例的話,他是 Kubernetes 裡面最高等級的權限之一:
在 PolicyRule
裡面,可以看到:
*.*
→ 代表所有 API 群組 (*
) 下的所有資源 (*
)。[*]
→ 代表允許所有操作(get
、list
、create
、update
、delete
...)。[*]
→ 對於非資源型 API(例如 /metrics
, /healthz
這些 endpoint)也全部允許。這表示 cluster-admin
這個 ClusterRole 對 Kubernetes 叢集的任何東西都具有 完全控制權。
看看他 Binding 的對象是:
# Cluster Roles Binding
kubectl get clusterrolebindings | grep cluster-admin
# Describe
kubectl describe clusterrolebindings.rbac.authorization.k8s.io cluster-admin
下圖可以看到這樣代表 所有屬於 system:masters
群組的使用者,自動就會擁有 cluster-admin 的最高權限。
我們最後來賦予 sean
查看 Nodes 的權限。
kubectl get nodes --as sean
可以看到因為還沒有權限所以被 forbidden:
因為 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
再次查看 Nodes 就成功了:
今天我們完整實戰了 RBAC,從系統內建的 kube-proxy Role/RoleBinding 開始,逐步拆解 Kubernetes 授權的運作方式:
透過建立新使用者 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 決定「送進來的請求」是否符合規範。