iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
Kubernetes

不是背 YAML!30 天從零打造 Kubernetes 微服務:從本機實戰一路到 CKA系列 第 24 篇

Day 24|RBAC:不要讓每個人都變成 Kubernetes 管理員

  • 分享至 

  • xImage
  •  

昨天了解了 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 到底在管理什麼?

理解 RBAC 最簡單的方法,就是記住一句話:

Who can do What on Which Resource?

也就是三個問題:

誰
可以對什麼資源做什麼
 

例如:

reader
可以
list
cka-lab Namespace 裡的 Pods

拆開來就是:

Who      → reader
What     → list
Resource → pods

Kubernetes RBAC 基本上就是在描述這件事情。


第一個新名詞:Subject

RBAC 裡「誰」被稱為:

Subject

Subject 就是:

接受權限的身分。

常見有三種:

User
Group
ServiceAccount

User 可以理解為一個使用 Kubernetes 的人,例如:

Stephen Curry
developer-a
admin

Group 則是一群 User,例如:

developers
devops
qa-team

這樣就不用一個人一個人設定權限。

而第三個:

ServiceAccount

非常重要,因為它主要是給 Kubernetes 裡的程式使用的身分。


ServiceAccount 是什麼?

人類操作 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

實際建立一個 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

應該可以看到:

https://ithelp.ithome.com.tw/upload/images/20260924/20168537GcVspWlSpP.png

現在 Kubernetes 裡已經有:

ServiceAccount
reader

但是要注意:

有 Identity 不代表有權限。

現在我們只是建立「reader 這個身分」,還沒有允許它去讀取 Pods。

下一步才是建立權限。


第二個新名詞:Role

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

https://ithelp.ithome.com.tw/upload/images/20260924/20168537FDsfHXfCjI.png


Role YAML 到底在寫什麼?

其中:

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-lab Namespace 裡,允許讀取與監控 Pod。


那 apiGroups: [""] 又是什麼?

這一行初學時很容易直接照抄:

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。


Role 有了,但還差一件事

現在我們有:

ServiceAccount
reader

也有:

Role
pod-reader

但是這兩個東西目前:

完全沒有關係。

Role 只是在 Kubernetes 裡宣告:

這裡有一組
get/list/watch pods
的權限。

但是 Kubernetes 還不知道:

這組權限要給誰?

因此我們需要第三個重要物件:

RoleBinding

第三個新名詞: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

https://ithelp.ithome.com.tw/upload/images/20260924/20168537bbsegD7ZDK.png


subjects 和 roleRef 差在哪?

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

怎麼確認 reader 真的只有讀取權限?

我們不需要真的做一套 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

https://ithelp.ithome.com.tw/upload/images/20260924/201685377enmmbHCfJ.png

這裡:

--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

https://ithelp.ithome.com.tw/upload/images/20260924/20168537Cs8Lac8Jeu.png

這就證明我們的 RBAC 成功了:

list pods
→ yes

delete pods
→ no

這就是 Least Privilege 的概念:

只給 Application 真正需要的最小權限。

不是:

為了方便
↓
全部給 cluster-admin

ServiceAccount 要怎麼真的給 Pod 使用?

這也是很重要的一步。

我們前面只是建立:

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 裡最重要的用途。


Role 與 ClusterRole 到底差在哪?

接下來是 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 不只是「管理 Node」

ClusterRole 可以拿來描述:

Cluster-scoped Resource

例如:

nodes

也可以描述:

namespaced resources

例如:

pods
deployments
secrets

差別在於它本身不是屬於某個 Namespace 的物件,因此很適合拿來建立一套:

可重複使用的權限模板

例如公司可能建立:

ClusterRole
app-viewer

然後 Development、Staging、Production 各自透過 RoleBinding 使用它。


RoleBinding 與 ClusterRoleBinding

這裡一定要把:

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 好理解很多。


Secret 為什麼在 RBAC 特別危險?

例如你看到一個 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 需要什麼,就只給什麼。


實際遇到 403 Forbidden 怎麼查?

未來 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 有沒有寫錯?

通常就能很快找到問題。


最後把 RBAC 整條流程串起來

假設 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。


Day 24 小結

到目前為止,我們已經學到 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,以及不同環境之間的設定差異。
我們明天見!


上一篇
Day 23|NetworkPolicy 實戰:Pod 能互連,不代表所有 Pod 都應該互連
下一篇
Day 25|Kustomize vs Helm:YAML 開始變多之後,怎麼避免複製貼上地獄?
系列文
不是背 YAML!30 天從零打造 Kubernetes 微服務:從本機實戰一路到 CKA 共 29 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言