昨天了解了 NetworkPolicy 如何控管 Pod 之間的網路通訊,
今天我們要接著來看集群安全管理的另一大支柱 —— RBAC 權限控管!
到目前為止,我們在自己的 kind Cluster 裡執行:
kubectl get pods
kubectl delete pod
kubectl delete deployment
kubectl create deployment
幾乎都不會遇到權限問題。
這是因為 kind 建立給我們使用的 kubeconfig,通常讓目前這個使用者擁有非常高的 Cluster 權限。
在自己的學習環境這樣很方便,但到了 Production 就非常危險。
真實環境裡不可能讓:
每一位 Engineer
每一個 Application
每一個 CI/CD Job
全部擁有:
Cluster Admin
否則一個程式寫錯、憑證外洩,甚至只是不小心下錯:
kubectl delete ...
都有可能影響整個 Cluster。
因此 Kubernetes 提供一套非常重要的權限管理機制:
RBAC
全名是:
Role-Based Access Control
中文可以理解成:
以「角色」為基礎的存取權限控制。
簡單來說,我們不是直接讓某個人「什麼都能做」,而是先定義一組權限,再決定要把這組權限交給誰。
理解 RBAC 最簡單的方法,就是記住一句話:
Who can do What on Which Resource?
也就是三個問題:
誰
可以對什麼資源做什麼
例如:
reader
可以
list
cka-lab Namespace 裡的 Pods
拆開來就是:
Who → reader
What → list
Resource → pods
Kubernetes RBAC 基本上就是在描述這件事情。
RBAC 裡「誰」被稱為:
Subject
Subject 就是:
接受權限的身分。
常見有三種:
User
Group
ServiceAccount
User 可以理解為一個使用 Kubernetes 的人,例如:
Stephen Curry
developer-a
admin
Group 則是一群 User,例如:
developers
devops
qa-team
這樣就不用一個人一個人設定權限。
而第三個:
ServiceAccount
非常重要,因為它主要是給 Kubernetes 裡的程式使用的身分。
人類操作 Kubernetes 時有自己的 Identity。
例如你現在執行:
kubectl get pods
kubectl 會透過 kubeconfig 裡的 Credential,讓 Kubernetes API Server 知道:
「現在是誰在發送這個 Request?」
但問題來了。
如果今天不是人在呼叫 Kubernetes API,而是一個 Pod 裡面的程式呢?
例如:
Prometheus
Monitoring Agent
Operator
CI Runner
自製 Backend
它們有時候也需要呼叫 Kubernetes API。
例如 Monitoring Application 可能需要:
list pods
get pods
watch pods
來知道有哪些 Pod 正在執行。
但我們絕對不希望它還能:
delete pods
delete deployments
get secrets
因此 Kubernetes 提供:
ServiceAccount
可以把它理解成:
給 Kubernetes Workload 使用的 Identity。
也就是:
人類
↓
User
Pod / Application
↓
ServiceAccount
我們直接來做一次。
先確認 cka-lab Namespace 還存在:
kubectl get namespace cka-lab
如果沒有,就建立:
kubectl create namespace cka-lab
接著建立一個叫:
reader
的 ServiceAccount:
kubectl create serviceaccount \
reader \
-n cka-lab
確認:
kubectl get serviceaccount \
-n cka-lab
應該可以看到:

現在 Kubernetes 裡已經有:
ServiceAccount
reader
但是要注意:
有 Identity 不代表有權限。
現在我們只是建立「reader 這個身分」,還沒有允許它去讀取 Pods。
下一步才是建立權限。
Kubernetes RBAC 裡:
Role
代表:
一組權限規則。
例如我們想定義:
可以 get Pod
可以 list Pod
可以 watch Pod
但是:
不可以 create
不可以 update
不可以 delete
就可以建立一個 Role。
建立:
vim pod-reader-role.yaml
內容:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: cka-lab
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
套用:
kubectl apply -f pod-reader-role.yaml
確認:
kubectl get role \
-n cka-lab
應該看到:
pod-reader

其中:
resources:
- pods
代表這個權限是針對:
Pod Resource
而:
verbs:
- get
- list
- watch
verbs 就是:
允許執行哪些 Kubernetes API Action。
三個動作雖然都像「讀取」,其實不太一樣。
get
通常是取得某一個 Resource。
例如:
kubectl get pod api-xxxxx
而:
list
是列出一群 Resource:
kubectl get pods
watch 則是持續監聽 Resource 的變化,例如 Controller 或 Monitoring Application 很常使用。
所以這個 Role 的意思就是:
在
cka-labNamespace 裡,允許讀取與監控 Pod。
這一行初學時很容易直接照抄:
apiGroups:
- ""
其實 Kubernetes API 裡的 Resource 會被分類到不同的:
API Group
例如 Deployment 屬於:
apps
所以如果要控制 Deployment,可能會寫:
apiGroups:
- apps
resources:
- deployments
但是 Pod、Service、Secret、ConfigMap 等最早期的核心 Kubernetes Resource 屬於:
Core API Group
Core API Group 在 RBAC YAML 裡不是寫:
core
而是使用:
apiGroups:
- ""
所以:
apiGroups:
- ""
resources:
- pods
其實就是在說:
Core API Group 裡面的 Pods。
現在我們有:
ServiceAccount
reader
也有:
Role
pod-reader
但是這兩個東西目前:
完全沒有關係。
Role 只是在 Kubernetes 裡宣告:
這裡有一組
get/list/watch pods
的權限。
但是 Kubernetes 還不知道:
這組權限要給誰?
因此我們需要第三個重要物件:
RoleBinding
Binding 就是:
綁定
因此:
RoleBinding
就是:
把某個 Role 的權限綁給某個 Subject。
建立:
vim reader-binding.yaml
內容:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: reader-binding
namespace: cka-lab
subjects:
- kind: ServiceAccount
name: reader
namespace: cka-lab
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader
套用:
kubectl apply -f reader-binding.yaml
確認:
kubectl get rolebinding \
-n cka-lab

RoleBinding 最重要就是看這兩塊。
第一塊:
subjects:
- kind: ServiceAccount
name: reader
namespace: cka-lab
是在回答:
權限要給誰?
答案:
cka-lab 裡面的 reader ServiceAccount
第二塊:
roleRef:
kind: Role
name: pod-reader
是在回答:
要給它哪一組權限?
答案:
pod-reader Role
所以整條關係其實就是:
ServiceAccount
reader
│
│ Subject
▼
RoleBinding
reader-binding
│
│ roleRef
▼
Role
pod-reader
│
▼
get / list / watch
pods
這張圖非常重要。
因為 RBAC 不要背一堆 YAML,真正要理解的是:
Identity
↓
Binding
↓
Permission
我們不需要真的做一套 Login 系統。
Kubernetes 提供一個非常好用的指令:
kubectl auth can-i
意思就是:
「這個 Identity 可以做這件事情嗎?」
測試 reader 能不能:
list pods
執行:
kubectl auth can-i \
list pods \
--as=system:serviceaccount:cka-lab:reader \
-n cka-lab
應該得到:
yes

這裡:
--as
代表:
Impersonation
Impersonation 可以理解成:
暫時模擬另一個 Identity 發出 Request。
ServiceAccount 在 Kubernetes 裡的完整 Username 格式是:
system:serviceaccount:<namespace>:<serviceaccount>
所以 reader 就是:
system:serviceaccount:cka-lab:reader
我們的 Role 裡只有:
verbs:
- get
- list
- watch
完全沒有:
delete
所以測試:
kubectl auth can-i \
delete pods \
--as=system:serviceaccount:cka-lab:reader \
-n cka-lab
應該得到:
no

這就證明我們的 RBAC 成功了:
list pods
→ yes
delete pods
→ no
這就是 Least Privilege 的概念:
只給 Application 真正需要的最小權限。
不是:
為了方便
↓
全部給 cluster-admin
這也是很重要的一步。
我們前面只是建立:
reader ServiceAccount
但是 Pod 不會因為它存在就自動使用它。
需要在 Pod 裡指定:
serviceAccountName: reader
例如:
apiVersion: v1
kind: Pod
metadata:
name: reader-app
namespace: cka-lab
spec:
serviceAccountName: reader
containers:
- name: app
image: nginx:1.27
建立:
kubectl apply -f reader-app.yaml
此時:
reader-app Pod
執行 Kubernetes API Request 時所代表的 Identity,就是:
ServiceAccount
reader
因此它取得的 Kubernetes API 權限,也就是我們剛剛透過 RoleBinding 給 reader 的:
get
list
watch
pods
而不是 Cluster Admin。
這才是 ServiceAccount 在真實 Application 裡最重要的用途。
接下來是 RBAC 最容易混亂的地方。
我們目前建立的是:
Role
Role 永遠屬於某個:
Namespace
例如:
kind: Role
metadata:
namespace: cka-lab
代表它描述的是:
cka-lab Namespace
裡面的權限。
例如:
cka-lab 裡可以 list pods
但 Kubernetes 有些 Resource 根本不屬於 Namespace。
最經典的就是:
Node
執行:
kubectl get nodes
你不需要寫:
-n cka-lab
因為 Node 是:
Cluster-scoped Resource
不是 Namespace Resource。
這時就不能用普通 Role 描述這種 Cluster Scope 的權限,而要使用:
ClusterRole
ClusterRole 可以拿來描述:
Cluster-scoped Resource
例如:
nodes
也可以描述:
namespaced resources
例如:
pods
deployments
secrets
差別在於它本身不是屬於某個 Namespace 的物件,因此很適合拿來建立一套:
可重複使用的權限模板
例如公司可能建立:
ClusterRole
app-viewer
然後 Development、Staging、Production 各自透過 RoleBinding 使用它。
這裡一定要把:
Role
ClusterRole
RoleBinding
ClusterRoleBinding
分開理解。
不要看到 ClusterRole 就認為一定要搭配:
ClusterRoleBinding
其實不是。
例如:
ClusterRole
pod-reader
可以透過:
RoleBinding
綁到 cka-lab。
那麼它的權限仍然只會作用於:
cka-lab Namespace
如果同一個 ClusterRole 改成透過:
ClusterRoleBinding
授權,才會變成 Cluster-wide。
所以可以這樣理解:
Role
= Namespace 裡定義權限
ClusterRole
= Cluster 層級定義一組可使用的權限
而真正決定:
「授權在哪裡生效」
還要看 Binding。
RoleBinding
→ 某個 Namespace
ClusterRoleBinding
→ 整個 Cluster
這樣就比死背四個 Definition 好理解很多。
例如你看到一個 Role:
resources:
- secrets
verbs:
- get
- list
千萬不要覺得:
「只是 read-only,應該沒關係吧?」
Secret 裡可能放:
Database Password
API Token
Private Credential
Certificate
Cloud Credential
所以:
不能修改 Secret
並不代表這個權限安全。
只要可以:
get secrets
就可能已經能取得非常敏感的 Credential。
因此 Production 做 RBAC 最重要的原則就是:
Least Privilege
也就是:
Application 需要什麼,就只給什麼。
未來 Application 呼叫 Kubernetes API 時,你很可能會遇到:
403 Forbidden
例如:
User "system:serviceaccount:cka-lab:reader"
cannot delete resource "pods"
這個錯誤其實非常有價值。
它已經告訴我們:
Request 已經到 Kubernetes API Server
Identity 也已經被辨識
但是 Authorization 不允許這個 Action
因此這種情況第一時間不應該先去亂查:
Service
Ingress
NetworkPolicy
DNS
而是先查:
kubectl auth can-i ...
例如:
kubectl auth can-i \
delete pods \
--as=system:serviceaccount:cka-lab:reader \
-n cka-lab
如果得到:
no
接下來依序確認:
現在是哪個 Identity?
Pod 使用哪個 ServiceAccount?
Role 裡有沒有這個 Resource?
verbs 裡有沒有需要的 Action?
RoleBinding 有沒有綁對 Subject?
Namespace 有沒有寫錯?
通常就能很快找到問題。
假設 Monitoring Pod 想取得 Pod 清單:
Monitoring Pod
│
▼
ServiceAccount
reader
│
▼
RoleBinding
reader-binding
│
▼
Role
pod-reader
│
▼
list pods
當它送出:
GET Kubernetes API
Kubernetes 就會檢查:
你是誰?
↓
reader
你想做什麼?
↓
list
你要操作什麼?
↓
pods
你的 Role 有沒有允許?
↓
有
結果
↓
Allowed
如果 reader 改成要求:
delete pods
則:
Role 沒有 delete
↓
Denied
↓
403 Forbidden
理解這個流程之後,RBAC 就不再只是四種很像的 YAML。
到目前為止,我們已經學到 Kubernetes 安全性的兩個完全不同層面。
前一天的:
NetworkPolicy
處理的是:
哪些 Pod 可以跟哪些 Pod 通訊?
今天的:
RBAC
處理的是:
哪個 Identity 可以對 Kubernetes API 做哪些事情?
例如:
NetworkPolicy
frontend
│
▼
api
控制的是 Network Traffic。
而:
RBAC
reader
│
▼
list pods
控制的是 Kubernetes API Permission。
兩者不要混在一起。
到現在,我們的 Application 已經開始接近真正 Production Kubernetes 的樣子:
Deployment
Service
Ingress
ConfigMap / Secret
PVC
StatefulSet
Job / CronJob
NetworkPolicy
RBAC
但接下來又會碰到另一個非常實際的 DevOps 問題。
我們現在已經累積了一大堆:
deployment.yaml
service.yaml
configmap.yaml
secret.yaml
networkpolicy.yaml
role.yaml
rolebinding.yaml
...
如果今天有:
Development
Staging
Production
而三個環境只有:
Image Tag
Replica
Domain
Resource Limit
Config
不一樣,難道要把所有 YAML:
Copy 三份?
當然不是。
這就是下一個 Kubernetes 非常重要的主題:
Kustomize
Helm
也就是:
如何管理大量 Kubernetes YAML,以及不同環境之間的設定差異。
我們明天見!