iT邦幫忙

2025 iThome 鐵人賽

DAY 10
2
DevOps

賢者大叔的容器修煉手札系列 第 10

Secret 權限控制 - ServiceAccount 與 RBAC 🎭

  • 分享至 

  • xImage
  •  

賢者大叔的容器修煉手札系列 第 10 篇

Secret 權限控制 - ServiceAccount 與 RBAC 🎭

還記得昨天我們學會了 Secret 的基本使用嗎?但是各位,光會用 Secret 還不夠!就像銀行不能讓所有員工都能打開所有保險箱一樣,我們需要精確的權限控制。今天我們要學習 K8s 的身份認證與授權系統:ServiceAccount 和 RBAC!
想像你是一家跨國企業的 IT 安全主管,公司有開發團隊、測試團隊、運維團隊、安全稽核團隊,每個團隊都需要不同程度的 Secret 訪問權限。如何確保「開發人員只能看開發環境的密碼」、「稽核人員能看但不能改」、「運維人員能管理但要留下記錄」?這就是今天要解決的企業級挑戰!

今日學習目標 🎯

✅ 理解 ServiceAccount:Kubernetes 的身份證系統

✅ 掌握 RBAC 權限控制:Role、ClusterRole、RoleBinding 的設計藝術

✅ 實作企業權限分級:為不同角色設計精確的 Secret 權限

RBAC 的三層架構 🏗️

https://ithelp.ithome.com.tw/upload/images/20250824/20104930cccj6CB4V3.png

跟一般系統做 RBAC 一樣,先建立身份ServiceAccount。接著定義角色Role跟對應的資源存取Resource或功能權限。接著就能把角色綁訂Binding給所需的身份上。

https://ithelp.ithome.com.tw/upload/images/20250824/20104930OBhW0pHkj0.png
圖: K8s RBAC 元件之間的關係圖

命名空間內的權限鏈條:

Secret → ServiceAccount → RoleBinding → Role
   ↓           ↓              ↓         ↓
機密資料    身份認證        權限綁定    具體權限

實際運作流程:

  1. Secret 存儲敏感資料(密碼、API Key 等)
  2. ServiceAccount 提供身份認證,讓 Pod 有明確的身份
  3. Role 定義具體的權限(能做什麼操作)
  4. RoleBinding 將 ServiceAccount 和 Role 綁定起來
  5. ClusterRole 定義跨命名空間的權限
  6. ClusterRoleBinding 將 ServiceAccount 和 ClusterRole 綁定

介紹 ServiceAccount

Kubernetes 的身份證系統 🆔
想像你走進一家大型企業,沒有員工證就無法進入任何辦公區域。ServiceAccount 就是 Kubernetes 世界中的「員工證系統」!

沒有 ServiceAccount 的災難場景

# 😱 災難場景:所有 Pod 都使用預設權限
kubectl get pods --all-namespaces
# 任何 Pod 都能看到所有命名空間的資源

kubectl get secrets --all-namespaces  
# 任何應用都能看到所有 Secret!

kubectl delete deployment critical-payment-service
# 甚至能刪除關鍵服務!

這會造成什麼問題?

  • 🔴 權限過度授予:每個應用都有管理員權限

  • 🔴 無法追蹤責任:不知道是誰執行了什麼操作

  • 🔴 安全風險巨大:一個應用被攻破,整個集群淪陷

  • 🔴 合規要求無法滿足:無法滿足金融業的審計要求

ServiceAccount 的基本結構

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account        # 帳戶名稱
  namespace: my-namespace         # 所屬命名空間
  labels:                         # 標籤分類
    team: development
    role: api-service
    security-level: medium
  annotations:                    # 註解資訊
    description: "API服務專用帳戶"
    created-by: "devops-team"
automountServiceAccountToken: true  # 是否自動掛載 Token
secrets:                           # 關聯的 Secret
- name: my-service-account-token
imagePullSecrets:                  # 鏡像拉取密鑰
- name: registry-secret

賢者金融科技集團的 ServiceAccount 設計 🏦

根據我們的企業場景,讓我們為每個角色設計專屬的 ServiceAccount:

  1. 開發人員 ServiceAccount 👨‍💻
# dev-team-serviceaccount.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dev-team-sa
  namespace: dev-env
  labels:     # 🏷️ 標籤
    team: development  # 🏷️ 用於分類和查詢
    role: developer
    security-level: basic  # 🏷️ 管理用途
    environment: development
automountServiceAccountToken: true
  1. 應用服務 ServiceAccount 🎯
# app-service-serviceaccount.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: payment-api-sa
  namespace: prod-env
  labels:
    team: development
    role: application
    security-level: restricted
    app: payment-api
    environment: production
automountServiceAccountToken: true

  1. 運維人員 ServiceAccount 🚀
# devops-team-serviceaccount.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: devops-team-sa
  namespace: kube-system
  labels:
    team: devops
    role: admin
    security-level: high
    scope: cluster-wide
automountServiceAccountToken: true

Role & ClusterRole

一個角色包含了一套表示一組權限的規則,權限以純粹的累加形式累積(沒有"否定"的規則)。

Role︰一個 Role 對象只能對用於授予對單一 namespace 中資源的訪問權限。
ClusterRole︰對整個 K8s cluster 內有效的角色。

https://ithelp.ithome.com.tw/upload/images/20250824/20104930gHqcSCC9AE.png

Role 的基本結構

apiVersion: rbac.authorization.k8s.io/v1
kind: Role                        # 定義 Role
metadata:
  namespace: dev-env              # 🎯 只在此命名空間生效
  name: developer-role
  labels:
    team: development
    security-level: basic
rules:                            # 📋 權限規則列表
- apiGroups: [""]                 # 🔗 API 群組
  resources: ["secrets"]          # 📦 資源類型
  resourceNames: ["dev-db-secret"] # 🎯 特定資源名稱(可選)
  verbs: ["get", "list"]          # ⚡ 允許的操作
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch"]

ClusterRole 的基本結構

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: devops-engineer-role    # 🌍 集群級別,不需要 namespace
  labels:
    team: devops
    security-level: high
rules:
# 集群資源權限
- apiGroups: [""]
  resources: ["nodes", "namespaces"]
  verbs: ["get", "list", "watch"]

# 跨命名空間資源權限
- apiGroups: [""]
  resources: ["secrets", "configmaps"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

# 應用管理權限
- apiGroups: ["apps"]
  resources: ["deployments", "daemonsets", "statefulsets"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

其中能給予的操作權限 Verbs 有︰

  verbs:
    - "get"         # 獲取單個資源
    - "list"        # 列出資源列表
    - "watch"       # 監聽資源變化
    - "create"      # 建立資源
    - "update"      # 更新資源
    - "patch"       # 部分更新資源
    - "delete"      # 刪除資源
    - "deletecollection"  # 批量刪除

RoleBinding 與 ClusterRoleBinding

設定規則決定將哪個用戶綁訂到哪個 Role 或 ClusterRole 上。

RoleBinding的基本結構

單個命名間空級別的權限控制:

RoleBinding   ↔   Role
       ↓           ↓
單個命名空間綁定  該命名空間權限
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: dev-env              # 🎯 綁定生效的命名空間
  name: dev-team-binding
  labels:
    team: development
    environment: development
subjects:                         # 👥 被綁定的主體(誰獲得權限)
- kind: ServiceAccount            # 主體類型:ServiceAccount
  name: dev-team-sa               # ServiceAccount 名稱
  namespace: dev-env              # ServiceAccount 所在命名空間
- kind: User                      # 主體類型:User
  name: john.developer@company.com
  apiGroup: rbac.authorization.k8s.io
- kind: Group                     # 主體類型:Group
  name: development-team
  apiGroup: rbac.authorization.k8s.io
roleRef:                          # 🎭 被綁定的角色(什麼權限)
  kind: Role                      # 角色類型
  name: developer-role            # 角色名稱
  apiGroup: rbac.authorization.k8s.io

ClusterRoleBinding

集群級別的權限控制:

ClusterRoleBinding ↔ ClusterRole
       ↓                 ↓
   跨命名空間綁定      跨命名空間權限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: devops-team-binding       # 🌍 集群級別,不需要 namespace
  labels:
    team: devops
    security-level: high
subjects:                         # 👥 被綁定的主體
- kind: ServiceAccount
  name: devops-team-sa
  namespace: kube-system          # ServiceAccount 仍需指定命名空間
- kind: User
  name: ops.lead@sagetech.com
  apiGroup: rbac.authorization.k8s.io
- kind: Group
  name: devops-team
  apiGroup: rbac.authorization.k8s.io
roleRef:                          # 🎭 只能綁定 ClusterRole
  kind: ClusterRole
  name: devops-engineer-role
  apiGroup: rbac.authorization.k8s.io

權限範圍對比:

類型 作用範圍 使用場景
Role + RoleBinding 單一命名空間 開發環境、測試環境的權限控制
ClusterRole + ClusterRoleBinding 整個集群 運維人員、監控系統的跨環境權限

實戰

場景設定:賢者金融科技集團
你是「賢者金融科技集團」的 DevOps 架構師,需要為以下角色設計權限:

👨‍💻 開發人員:只能讀取開發環境的 Secret
🔧 測試人員:可以管理測試環境的 Secret
🚀 運維人員:可以管理所有環境的 Secret
👔 安全稽核:可以查看所有 Secret,但不能修改
🎯 應用服務:只能讀取自己需要的特定 Secret

所以我們就能設計開發人員、測試人員、應用服務,都只給予一般的 Role角色。
並且開發人員能對自己管理的資源進行CRUD,而應用服務只能讀取。
然而運維人員可能就需要對全部的namespace進行管理,就能給予ClusterRole的角色。

開發人員 Role 👨‍💻

# 🎯 開發環境的開發人員權限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev-env
  name: developer-role
  labels:
    team: development
    environment: development
    security-level: basic
rules:
# Secret 權限:只能讀取開發相關的 Secret
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: 
    - "dev-database-config"
    - "dev-redis-config"
    - "dev-api-keys"
    - "dev-jwt-secret"
  verbs: ["get", "list"]

# ConfigMap 權限:可以完全管理配置
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

# Pod 權限:可以查看和調試
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/exec"]
  verbs: ["get", "list", "create", "delete"]

# Service 權限:可以管理服務
- apiGroups: [""]
  resources: ["services", "endpoints"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

# Deployment 權限:可以管理部署
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

應用服務 Role 🤖

# 🎯 運營環境的應用服務權限(最小權限原則)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: prod-env
  name: payment-app-role
  labels:
    app: payment-api
    environment: production
    security-level: restricted
rules:
# Secret 權限:只能讀取自己需要的 Secret
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames:
    - "payment-db-secret"      # 資料庫連線密碼
    - "payment-api-keys"       # API 金鑰
    - "payment-jwt-secret"     # JWT 簽名密鑰
  verbs: ["get"]               # 只能讀取,不能修改

# ConfigMap 權限:只能讀取配置
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames:
    - "payment-app-config"
    - "payment-feature-flags"
  verbs: ["get"]

# 自我監控權限:只能查看自己的狀態
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
  # 注意:這裡沒有 resourceNames,但會在 RoleBinding 中限制

運維工程師 ClusterRole 🚀

  # 🎯 運維工程師的集群管理權限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: devops-engineer-role
  labels:
    team: devops
    security-level: high
    scope: cluster-wide
rules:
# 集群基礎設施權限
- apiGroups: [""]
  resources: ["nodes", "namespaces"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]

# Secret 管理權限(排除超級管理員 Secret)
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]
  # 注意:會在 ClusterRoleBinding 中進一步限制

# ConfigMap 管理權限
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

# 應用部署權限
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets", "daemonsets", "statefulsets"]
  verbs: ["get", "list", "create", "update", "patch", "delete", "watch"]

# 服務管理權限
- apiGroups: [""]
  resources: ["services", "endpoints"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

# 存儲管理權限
- apiGroups: [""]
  resources: ["persistentvolumes", "persistentvolumeclaims"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

# 監控權限
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/exec"]
  verbs: ["get", "list", "watch"]

# 事件查看權限
- apiGroups: [""]
  resources: ["events"]
  verbs: ["get", "list", "watch"]

當我們ServiceAccount、RoleRoleBinding 都設定好後。最後一步就是將ServiceAccount 設定到Pod`身上.這樣該 Pod 就有能力去存取 Secret了!

apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-api
  namespace: prod-env
spec:
  template:
    spec:
      serviceAccountName: payment-api-sa  # 🎯 使用我們創建的 ServiceAccount
      containers:
      - name: payment-api
        image: payment-api:v1.0
        env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: payment-db-secret     # 現在有權限讀取這個 Secret
              key: password

驗證檢查權限

能透過kubectl auth can-i <verb> <resource> [options] 該指令,來協助我們驗證權限。

檢查 ServiceAccount 的 Secret 權限 🔐

> kubectl auth can-i get secrets --as=system:serviceaccount:prod-env:payment-api-sa -n prod-env

yes

因為payment-api-sa 通過 RoleBinding 綁定到 payment-app-role,該角色有權限讀取特定的 Secret。

指令組成部分:

部分 說明 作用
kubectl auth can-i 權限檢查子命令 🔍 檢查是否有執行特定操作的權限
get 動作/動詞 (verb) ⚡ 要檢查的操作類型
secrets 資源類型 (resource) 📦 要操作的 Kubernetes 資源
--as=system:serviceaccount:prod-env:payment-api-sa 身份模擬 🎭 模擬特定身份執行檢查
-n prod-env 命名空間 🏠 指定檢查的命名空間範圍

總結

架構設計的思維與分層思考問題的能力

架構設計的思維︰

服務邊界清晰化,設計出服務邊界後,就能思考該給予怎樣的資源存取權限。
又因為每個服務都有明確的ServiceAccount,就能有精確的 RBAC 規則,以及所有操作紀錄就能有身份紀錄了。

傳統單體應用:
┌─────────────────────────────┐
│     所有功能共享權限          │
│  ❌ 權限邊界模糊             │
└─────────────────────────────┘

微服務架構:
┌─────────┐ ┌─────────┐ ┌─────────┐
│支付服務  │ │用戶服務  │ │訂單服務  │
│專屬權限  │ │專屬權限  │ │專屬權限  │
└─────────┘ └─────────┘ └─────────┘

###分層思考的核心能力:

  1. 抽象化思維 🧠
  • 從具體的「誰能讀取密碼」抽象到「身份-權限-資源」模型
  • 理解系統設計的本質:分離關注點
  1. 系統化設計 🎯
  • 不是頭痛醫頭,而是整體規劃權限體系
  • 考慮擴展性:新增角色時不需要重新設計
  1. 安全思維 🔒
  • 預設拒絕 (Deny by Default)
  • 最小權限原則 (Principle of Least Privilege)
  • 職責分離 (Separation of Duties)
    https://ithelp.ithome.com.tw/upload/images/20250824/20104930pA68E6CjCz.png

https://ithelp.ithome.com.tw/upload/images/20250824/20104930123YHzPRxy.png


上一篇
Secret 基礎 - 守護你的機密資料
下一篇
Service 基礎 - Pod 間溝通的穩定橋樑 🌉
系列文
賢者大叔的容器修煉手札17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言