Kubernetes 配置管理的核心機制

當台灣的企業將應用程式遷移到 Kubernetes 平台時,如何管理應用程式的配置資訊與敏感資料成為首要挑戰。在傳統的單體應用時代,開發者習慣將配置參數寫在配置檔案中,隨著應用程式一起打包部署。然而在容器化與微服務架構下,這種方式會導致每次修改配置都需要重新建置映像檔,不僅浪費時間也違背了容器不可變基礎設施的設計原則。Kubernetes 透過 ConfigMap 與 Secret 兩種資源物件提供了優雅的解決方案,讓配置與程式碼完全分離。

ConfigMap 專門用於儲存非敏感的配置資料,例如應用程式的執行環境設定、功能開關、外部服務的連線位址等資訊。這些資料以鍵值對的形式儲存在 Kubernetes 的 etcd 資料庫中,可以透過多種方式注入到容器內部。Secret 則專門處理敏感資訊,例如資料庫密碼、API 金鑰、TLS 憑證等需要保護的資料。雖然 Secret 在 Kubernetes 中預設只是進行 Base64 編碼而非真正的加密,但它提供了與 ConfigMap 不同的存取控制機制,並且可以整合外部的密鑰管理系統實現更高等級的安全保護。

當系統管理員建立 ConfigMap 或 Secret 之後,需要將這些配置資料注入到 Pod 中供容器使用。Kubernetes 提供了兩種主要的注入方式。第一種是將 ConfigMap 或 Secret 掛載為 Volume,這種方式會在容器的檔案系統中建立一個目錄,ConfigMap 或 Secret 中的每個鍵會成為目錄中的一個檔案,檔案內容就是對應的值。這種方式特別適合需要讀取完整配置檔案的應用程式,例如 Nginx 的配置檔、應用程式的 JSON 或 YAML 格式配置等。第二種方式是將 ConfigMap 或 Secret 的資料注入為環境變數,容器內的應用程式可以透過標準的環境變數讀取介面取得配置值。這種方式符合十二要素應用程式的設計原則,讓應用程式能夠輕鬆適應不同的執行環境。

# ConfigMap 範例:MySQL 資料庫配置
# 儲存非敏感的資料庫連線資訊

apiVersion: v1
kind: ConfigMap
metadata:
  # ConfigMap 的名稱,後續在 Pod 中參照時使用
  name: mysql-config
  # 命名空間,ConfigMap 必須與使用它的 Pod 在相同命名空間
  namespace: default
data:
  # 鍵值對格式儲存配置資料
  # mysqldb: 資料庫名稱
  mysqldb: myappdb1
  
  # user: 資料庫使用者名稱
  # 注意這裡是應用程式層級的使用者,非 root 帳號
  user: mysqluser1
  
  # 可以加入更多配置項目
  # 例如資料庫連接埠、字元集等
  # port: "3306"
  # charset: "utf8mb4"

---
# Secret 範例:MySQL 敏感資料
# 儲存需要保護的密碼資訊

apiVersion: v1
kind: Secret
metadata:
  # Secret 的名稱
  name: mysql-secret
  namespace: default
# type 指定 Secret 的類型
# Opaque 是最常用的類型,表示任意的使用者定義資料
# 其他類型包括 kubernetes.io/service-account-token、kubernetes.io/dockerconfigjson 等
type: Opaque
data:
  # Secret 的資料必須經過 Base64 編碼
  # 注意:Base64 不是加密,只是編碼
  # 任何取得 Secret 的人都可以輕易解碼
  
  # rootpassword: root 使用者的密碼(Base64 編碼後)
  # 實際值可透過命令產生:echo -n 'actual_password' | base64
  rootpassword: YWRtJasdhaW4=
  
  # userpassword: 應用程式使用者的密碼(Base64 編碼後)
  userpassword: MWYyZDigKJGUyfgKJBmU2N2Rm
  
  # 生產環境建議:
  # 1. 使用 HashiCorp Vault 等外部密鑰管理系統
  # 2. 啟用 Kubernetes 的 Secret 加密機制
  # 3. 透過 RBAC 嚴格控制 Secret 的存取權限

---
# Deployment 範例:使用 ConfigMap 與 Secret
# 展示如何將配置與敏感資料注入到容器中

apiVersion: apps/v1
kind: Deployment
metadata:
  # Deployment 名稱
  name: myapp-db-deploy
  namespace: default
spec:
  # 副本數量
  replicas: 1
  
  # 選擇器定義這個 Deployment 管理哪些 Pod
  selector:
    matchLabels:
      app: myapp-db
  
  # Pod 模板定義
  template:
    metadata:
      # Pod 的標籤,必須與上面的 selector 匹配
      labels:
        app: myapp-db
    spec:
      # 容器定義
      containers:
      - name: myapp-db-instance
        # 使用官方 MySQL 映像檔
        image: mysql:8.0
        
        # 環境變數配置
        # 透過 valueFrom 從 ConfigMap 或 Secret 取得值
        env:
        # MySQL root 密碼(從 Secret 取得)
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              # 參照的 Secret 名稱
              name: mysql-secret
              # Secret 中的鍵名稱
              key: rootpassword
              # optional: false 表示若 Secret 不存在會導致 Pod 啟動失敗
              # 設定為 true 可以讓 Pod 即使 Secret 不存在也能啟動
        
        # 應用程式使用者密碼(從 Secret 取得)
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: userpassword
        
        # 資料庫使用者名稱(從 ConfigMap 取得)
        - name: MYSQL_USER
          valueFrom:
            configMapKeyRef:
              # 參照的 ConfigMap 名稱
              name: mysql-config
              # ConfigMap 中的鍵名稱
              key: user
        
        # 資料庫名稱(從 ConfigMap 取得)
        - name: MYSQL_DATABASE
          valueFrom:
            configMapKeyRef:
              name: mysql-config
              key: mysqldb
        
        # 容器連接埠配置
        ports:
        - containerPort: 3306
          name: mysql
        
        # 資源限制(生產環境必須設定)
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"

上述 YAML 配置展示了 ConfigMap 與 Secret 的完整使用流程。ConfigMap 儲存資料庫名稱與使用者名稱這類非敏感資訊,Secret 則儲存經過 Base64 編碼的密碼。在 Deployment 的容器定義中,透過環境變數的方式將這些配置注入到 MySQL 容器內。MySQL 容器啟動時會讀取這些環境變數,自動建立對應的資料庫與使用者帳號。這種配置與程式碼分離的方式讓同一個 Deployment 定義可以在開發、測試與生產環境中重複使用,只需要在不同環境中建立對應的 ConfigMap 與 Secret 即可。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
skinparam minClassWidth 100

package "Kubernetes 配置管理架構" {
    component "etcd 資料庫" {
        [ConfigMap 儲存] as cm_storage
        [Secret 儲存\nBase64 編碼] as secret_storage
    }
    
    component "Pod 配置注入" {
        [環境變數注入] as env_inject
        [Volume 掛載] as volume_mount
    }
    
    component "容器執行環境" {
        [應用程式容器] as app_container
        [配置檔案系統] as config_fs
        [環境變數讀取] as env_read
    }
}

cm_storage --> env_inject: 注入非敏感配置
cm_storage --> volume_mount: 掛載配置檔案
secret_storage --> env_inject: 注入敏感資料
secret_storage --> volume_mount: 掛載憑證檔案

env_inject --> env_read: 環境變數
volume_mount --> config_fs: 檔案掛載

env_read --> app_container: 讀取配置
config_fs --> app_container: 讀取檔案

note right of secret_storage
  預設 Base64 編碼
  建議整合外部密鑰管理系統
  例如 HashiCorp Vault
end note

note right of volume_mount
  避免使用 subPath
  確保動態更新生效
end note

@enduml

上方架構圖清楚呈現了 Kubernetes 配置管理的完整流程。ConfigMap 與 Secret 儲存在 etcd 資料庫中,透過環境變數注入或 Volume 掛載的方式傳遞到容器內部。應用程式容器可以透過標準的環境變數讀取介面或檔案系統存取這些配置資料。特別需要注意的是,當使用 Volume 掛載方式時,應避免使用 subPath 屬性,因為 subPath 會阻止配置的動態更新功能。

ConfigMap 與 Secret 的動態更新機制

在生產環境中,應用程式的配置需要隨著業務需求調整。傳統的做法是修改配置檔案後重新部署應用程式,但這種方式在容器化環境中會導致服務中斷。Kubernetes 的 ConfigMap 與 Secret 提供了動態更新的能力,當管理員修改 ConfigMap 或 Secret 的內容後,已經掛載這些資源的 Pod 會在一定時間內(通常是幾秒到幾分鐘)自動同步到最新的配置。這個機制對於需要頻繁調整配置的應用程式非常有價值。

然而動態更新機制有其限制條件。首先,只有透過 Volume 方式掛載的 ConfigMap 或 Secret 才支援動態更新,注入為環境變數的配置資料在 Pod 啟動後就固定了,無法在執行期間變更。這是因為環境變數是在容器啟動時由作業系統核心設定的,後續無法修改。其次,應用程式本身必須支援配置的熱重載功能,能夠監測配置檔案的變化並重新載入設定。許多現代應用框架如 Spring Boot、Nginx 都提供了配置熱重載的機制。若應用程式不支援熱重載,即使配置檔案更新了,應用程式仍會使用舊的配置,直到 Pod 重新啟動。

在實務應用中,許多團隊採用更新 ConfigMap 名稱的策略來觸發 Pod 的滾動更新。具體做法是在 CI/CD 流程中,每次修改配置時都建立一個新的 ConfigMap,其名稱包含版本號或時間戳記,例如 mysql-config-v2mysql-config-20250129。同時更新 Deployment 中對 ConfigMap 的參照,指向新的名稱。由於 Deployment 的 Pod 模板發生了變化,Kubernetes 會自動觸發滾動更新,逐步替換舊的 Pod。這種方式的優點是能夠確保所有 Pod 都使用最新的配置,並且可以輕鬆回滾到先前的版本。另一種做法是在 Deployment 的 Pod 模板中加入 annotation,其值為 ConfigMap 內容的 SHA256 校驗和,當 ConfigMap 內容變化時校驗和也會改變,同樣觸發 Pod 的滾動更新。

#!/bin/bash
# ConfigMap 動態更新範例腳本
# 展示如何透過修改 ConfigMap 觸發應用程式配置更新

# 步驟 1: 檢視當前的 ConfigMap 內容
# kubectl get 命令用於查詢 Kubernetes 資源
# -o yaml 參數指定輸出格式為 YAML
echo "=== 當前 ConfigMap 內容 ==="
kubectl get configmap mysql-config -o yaml

# 步驟 2: 編輯 ConfigMap
# kubectl edit 命令會開啟預設的文字編輯器(通常是 vi 或 nano)
# 修改完成後儲存退出,Kubernetes 會自動應用變更
echo "=== 編輯 ConfigMap ==="
kubectl edit configmap mysql-config

# 修改範例:
# 原本: mysqldb: myappdb1
# 修改為: mysqldb: myappdb2

# 步驟 3: 等待配置同步到 Pod
# Kubernetes 會在背景自動同步變更到掛載此 ConfigMap 的 Pod
# 同步時間通常在 30 秒到 2 分鐘之間
echo "=== 等待配置同步(約 60 秒)==="
sleep 60

# 步驟 4: 驗證 Pod 內的配置檔案已更新
# 進入容器內部檢查掛載的配置檔案內容
# -c 參數指定容器名稱(若 Pod 有多個容器)
echo "=== 驗證 Pod 內配置 ==="
kubectl exec -it myapp-db-deploy-xxxxx -c myapp-db-instance -- cat /etc/config/mysqldb

# 步驟 5: 重新啟動應用程式以套用新配置
# 若應用程式不支援配置熱重載,需要重新啟動
# 方法 1: 刪除 Pod,讓 Deployment 自動建立新的 Pod
kubectl delete pod myapp-db-deploy-xxxxx

# 方法 2: 觸發 Deployment 滾動更新
# 透過修改 Deployment 的 annotation 觸發更新
kubectl patch deployment myapp-db-deploy \
  -p '{"spec":{"template":{"metadata":{"annotations":{"configmap-update":"'$(date +%s)'"}}}}}'

# 步驟 6: 監控滾動更新進度
# rollout status 命令會顯示滾動更新的即時狀態
# 等待所有 Pod 都更新完成
echo "=== 監控滾動更新 ==="
kubectl rollout status deployment/myapp-db-deploy

# 步驟 7: 驗證新配置已生效
# 檢查應用程式日誌確認使用了新的配置
kubectl logs myapp-db-deploy-yyyyy -c myapp-db-instance | grep "database"

# 注意事項:
# 1. 環境變數方式注入的配置無法動態更新
# 2. 使用 subPath 掛載的檔案無法動態更新
# 3. 應用程式需要支援配置熱重載才能無縫更新
# 4. 建議在非高峰時段執行配置更新
# 5. 更新前應該在測試環境驗證配置的正確性

Secret 的安全強化策略

雖然 Kubernetes 的 Secret 機制提供了基本的敏感資料管理能力,但預設的 Base64 編碼並不能提供真正的安全保護。在企業級的生產環境中,需要採取額外的安全措施來保護敏感資料。首要的建議是整合外部的密鑰管理系統,例如 HashiCorp Vault、AWS Secrets Manager、Google Cloud Secret Manager 或 Azure Key Vault。這些專業的密鑰管理服務提供了企業級的加密、存取稽核、金鑰輪換等功能。

External Secrets Operator 是一個開源專案,提供了 Kubernetes 原生的方式整合外部密鑰管理系統。它的工作原理是在 Kubernetes 叢集中執行一個控制器,監聽 ExternalSecret 自訂資源。當管理員建立 ExternalSecret 物件時,控制器會連接到外部的密鑰管理系統,取得實際的密碼值,並自動在 Kubernetes 中建立對應的 Secret 物件。應用程式的 Pod 仍然像使用普通 Secret 一樣存取這些資料,但實際的密碼儲存在外部系統中,受到更嚴格的加密與存取控制保護。

另一個重要的安全實務是避免自動掛載 Service Account 的 API 憑證。Kubernetes 預設會為每個 Pod 自動掛載一個 Service Account Token,這個 Token 可以用來存取 Kubernetes API。對於大多數應用程式而言,它們並不需要直接與 Kubernetes API 互動,但這個自動掛載的 Token 卻成為潛在的安全風險。若應用程式存在漏洞被攻擊者利用,攻擊者可能使用這個 Token 存取 Kubernetes API,查詢敏感資訊或執行惡意操作。因此建議在 ServiceAccount 或 Pod 規格中明確設定不自動掛載 API 憑證,只有真正需要存取 Kubernetes API 的應用程式才啟用這個功能。

# ServiceAccount 安全配置範例
# 展示如何停用自動掛載 API Token 以提升安全性

apiVersion: v1
kind: ServiceAccount
metadata:
  # ServiceAccount 名稱
  name: app1-svcacct
  namespace: default
# 關鍵安全設定:停用自動掛載 Service Account Token
# 設定為 false 後,使用此 ServiceAccount 的 Pod
# 不會自動掛載 /var/run/secrets/kubernetes.io/serviceaccount 目錄
# 適用於不需要存取 Kubernetes API 的應用程式
automountServiceAccountToken: false

# 若需要為特定 Pod 啟用 Token 掛載
# 可以在 Pod 的 spec 中覆寫此設定
# spec:
#   serviceAccountName: app1-svcacct
#   automountServiceAccountToken: true

---
# 安全的 Pod 配置範例
# 展示如何在 Pod 層級控制 Token 掛載

apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: default
spec:
  # 使用已配置停用自動掛載的 ServiceAccount
  serviceAccountName: app1-svcacct
  
  # Pod 層級的 Token 掛載控制
  # 此設定會覆寫 ServiceAccount 的設定
  # false: 不掛載 Token(安全選項)
  # true: 強制掛載 Token(即使 ServiceAccount 設定為 false)
  automountServiceAccountToken: false
  
  containers:
  - name: app-container
    image: myapp:1.0
    
    # 安全性上下文設定
    # 進一步限制容器的權限
    securityContext:
      # 以非 root 使用者執行
      runAsNonRoot: true
      runAsUser: 1000
      
      # 唯讀根檔案系統
      readOnlyRootFilesystem: true
      
      # 停用權限提升
      allowPrivilegeEscalation: false
      
      # 移除所有 Linux Capabilities
      capabilities:
        drop:
        - ALL

---
# External Secrets Operator 配置範例
# 整合 HashiCorp Vault 管理敏感資料

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: vault-mysql-secret
  namespace: default
spec:
  # 更新間隔:每 1 小時從 Vault 同步一次
  refreshInterval: 1h
  
  # 指定使用的 SecretStore
  # SecretStore 定義了如何連接到外部密鑰管理系統
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  
  # 要建立的 Kubernetes Secret 配置
  target:
    # Secret 名稱
    name: mysql-secret
    
    # 建立策略
    # Owner: External Secrets Operator 完全控制此 Secret
    # Merge: 合併現有 Secret 的資料
    creationPolicy: Owner
  
  # 從 Vault 取得的資料對映
  data:
  # 從 Vault 路徑取得 root 密碼
  - secretKey: rootpassword
    remoteRef:
      # Vault 中的 Key 路徑
      key: database/mysql/root
      # Vault Key 中的屬性名稱
      property: password
  
  # 從 Vault 路徑取得應用程式使用者密碼
  - secretKey: userpassword
    remoteRef:
      key: database/mysql/appuser
      property: password

---
# SecretStore 配置範例
# 定義如何連接到 HashiCorp Vault

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
  namespace: default
spec:
  provider:
    vault:
      # Vault 伺服器位址
      server: "https://vault.example.com:8200"
      
      # Vault 路徑前綴
      path: "secret"
      
      # Vault 版本
      version: "v2"
      
      # 認證方式:Kubernetes Service Account
      auth:
        kubernetes:
          # Vault 中配置的 Kubernetes 認證路徑
          mountPath: "kubernetes"
          
          # 使用的 Kubernetes Service Account
          role: "external-secrets"
          
          # Service Account Token 路徑
          # 使用預設的 Token 掛載路徑
          serviceAccountRef:
            name: external-secrets-sa

上述配置展示了多層次的安全防護措施。透過停用 Service Account Token 的自動掛載,避免了不必要的 API 存取權限暴露。透過 External Secrets Operator 整合 HashiCorp Vault,將敏感資料的實際儲存移到專業的密鑰管理系統中,Kubernetes 中的 Secret 只是一個同步的副本。這種架構讓安全團隊能夠集中管理所有敏感資料,實施統一的存取控制、稽核記錄與金鑰輪換策略。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
skinparam minClassWidth 100

package "Secret 安全管理架構" {
    component "外部密鑰管理系統" {
        [HashiCorp Vault] as vault
        [AWS Secrets Manager] as aws_sm
        [Azure Key Vault] as azure_kv
    }
    
    component "Kubernetes 叢集" {
        [External Secrets\nOperator] as eso
        [Secret 物件\n同步副本] as k8s_secret
        [RBAC 權限控制] as rbac
    }
    
    component "應用程式層" {
        [Pod 容器] as pod
        [Service Account] as sa
    }
}

vault --> eso: 加密通道取得密碼
aws_sm --> eso: API 認證存取
azure_kv --> eso: 身份驗證取得

eso --> k8s_secret: 定期同步更新
rbac --> k8s_secret: 存取權限控制

k8s_secret --> pod: 掛載或注入
sa --> pod: 身份識別

note right of vault
  企業級加密儲存
  完整稽核日誌
  自動金鑰輪換
  細緻存取控制
end note

note right of eso
  監聽 ExternalSecret 資源
  自動同步密碼更新
  支援多種密鑰管理系統
end note

note right of rbac
  最小權限原則
  角色綁定控制
  命名空間隔離
end note

@enduml

上方架構圖呈現了整合外部密鑰管理系統的完整流程。External Secrets Operator 作為橋樑,連接 Kubernetes 叢集與外部密鑰管理系統。它定期從 Vault 等系統取得最新的密碼值,自動更新 Kubernetes 中的 Secret 物件。RBAC 機制控制哪些 Pod 可以存取特定的 Secret,實現細緻的權限管理。這種多層防護的架構大幅提升了敏感資料的安全性。

RBAC 權限控制與 CI/CD 整合

當 Kubernetes 叢集規模擴大,多個團隊共用同一個叢集時,權限控制變得至關重要。RBAC(Role-Based Access Control)提供了基於角色的存取控制機制,讓管理員能夠精確定義誰可以對哪些資源執行什麼操作。RBAC 的核心概念包含三個要素:主體、角色與角色綁定。主體代表需要存取叢集資源的實體,可以是使用者、ServiceAccount 或群組。角色定義了一組權限規則,指定可以對哪些資源執行哪些操作。角色綁定則將主體與角色關聯起來,賦予主體相應的權限。

Kubernetes 提供了兩種等級的角色定義。Role 是命名空間範圍的角色,只能授予對特定命名空間內資源的存取權限。ClusterRole 則是叢集範圍的角色,可以授予對整個叢集資源的存取權限,包含跨命名空間的資源與叢集級別的資源如 Node、PersistentVolume 等。對應地,角色綁定也分為 RoleBinding 與 ClusterRoleBinding。RoleBinding 將主體綁定到 Role 或 ClusterRole,但權限範圍限制在特定命名空間內。ClusterRoleBinding 則將主體綁定到 ClusterRole,授予整個叢集範圍的權限。

在實務應用中,建議遵循最小權限原則。每個應用程式或使用者只應該獲得完成其工作所需的最低權限,避免過度授權造成的安全風險。例如一個監控系統可能需要讀取所有 Pod 的狀態,但不需要修改或刪除的權限,那麼應該建立一個只包含 get、list、watch 動詞的 ClusterRole。對於需要存取 Kubernetes API 的應用程式,應該為其建立專屬的 ServiceAccount,透過 RoleBinding 綁定到適當的 Role,而不是使用預設的 ServiceAccount。這樣可以實現更細緻的權限控制與稽核追蹤。

# RBAC 完整配置範例
# 展示如何建立角色、綁定角色以實現細緻的權限控制

# Role 定義:Pod 檢視權限
# 此角色只能檢視 Pod 資源,無法建立、修改或刪除
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  # Role 名稱
  name: pod-viewer
  # 命名空間:此角色只在 default 命名空間生效
  namespace: default
rules:
# 權限規則清單
- apiGroups: [""]
  # 空字串表示核心 API 群組
  # 核心群組包含 Pod、Service、ConfigMap、Secret 等基本資源
  
  # 可存取的資源類型
  resources: ["pods"]
  
  # 允許的操作動詞
  # get: 取得單一資源的詳細資訊
  # watch: 監聽資源的變化事件
  # list: 列出所有資源
  verbs: ["get", "watch", "list"]
  
  # 其他常用動詞:
  # create: 建立新資源
  # update: 更新現有資源
  # patch: 部分更新資源
  # delete: 刪除資源
  # deletecollection: 批次刪除資源

---
# RoleBinding 定義:將使用者綁定到角色
# 賦予特定使用者 Pod 檢視權限

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  # RoleBinding 名稱
  name: noc-helpdesk-view
  # 命名空間:必須與 Role 在同一命名空間
  namespace: default
subjects:
# 主體清單:可以綁定多個主體
- kind: User
  # 使用者類型
  # 其他類型:ServiceAccount、Group
  
  name: helpdeskuser@example.com
  # 使用者識別名稱
  # 通常來自 OpenID Connect 或其他身份驗證系統
  
  apiGroup: rbac.authorization.k8s.io
  # RBAC API 群組

roleRef:
# 角色參照:指定要綁定的角色
  kind: Role
  # 角色類型:Role 或 ClusterRole
  
  name: pod-viewer
  # 角色名稱,必須存在於同一命名空間
  
  apiGroup: rbac.authorization.k8s.io

---
# ClusterRole 定義:叢集範圍的角色
# 監控系統需要讀取所有命名空間的 Pod 與 Node 資訊

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # ClusterRole 名稱
  name: monitoring-reader
  # ClusterRole 不屬於任何命名空間
rules:
# 讀取所有 Pod 資訊
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  # pods/log 是子資源,用於讀取 Pod 日誌
  verbs: ["get", "list", "watch"]

# 讀取 Node 資訊
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "watch"]

# 讀取 Deployment 資訊
- apiGroups: ["apps"]
  # apps API 群組包含 Deployment、StatefulSet、DaemonSet 等
  resources: ["deployments", "statefulsets", "daemonsets"]
  verbs: ["get", "list", "watch"]

---
# ClusterRoleBinding 定義:叢集範圍的角色綁定
# 授予監控系統整個叢集的讀取權限

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: monitoring-system-binding
subjects:
# 使用 ServiceAccount 作為主體
- kind: ServiceAccount
  name: prometheus-sa
  # ServiceAccount 名稱
  
  namespace: monitoring
  # ServiceAccount 所在的命名空間

roleRef:
  kind: ClusterRole
  name: monitoring-reader
  apiGroup: rbac.authorization.k8s.io

---
# ServiceAccount 定義:應用程式身份
# 為監控系統建立專屬的身份識別

apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus-sa
  namespace: monitoring
# 停用自動掛載 API Token(若不需要存取 API)
automountServiceAccountToken: true
# 監控系統需要存取 API 以收集指標,因此設為 true

---
# CI/CD 專用 ServiceAccount
# 限制 CI/CD 工具的權限範圍

apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab-ci-sa
  namespace: ci-cd
automountServiceAccountToken: false
# CI/CD 工具透過外部憑證存取,不需要 Pod 內的 Token

---
# CI/CD 部署角色
# 授予 CI/CD 工具部署應用程式的必要權限

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: app-deployer
  namespace: production
rules:
# 管理 Deployment
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

# 管理 Service
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

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

# 查看部署狀態
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]

當 RBAC 機制與 CI/CD 流程整合時,可以實現安全的自動化部署。CI/CD 工具如 GitLab CI、Jenkins 或 GitHub Actions 需要存取 Kubernetes API 以部署應用程式。建議為這些工具建立專屬的 ServiceAccount,並透過 RoleBinding 授予其必要的權限。這種做法相比使用管理員憑證更加安全,因為可以精確控制 CI/CD 工具能夠操作的資源範圍。當 CI/CD 流程執行部署時,它使用 ServiceAccount 的 Token 認證到 Kubernetes API,執行建立或更新 Deployment、Service、ConfigMap 等操作,整個過程都受到 RBAC 規則的約束與稽核記錄的追蹤。

透過 Kubernetes 的 ConfigMap、Secret 與 RBAC 機制,台灣企業能夠建構安全可靠的容器化應用平台。從配置與程式碼的分離、敏感資料的安全管理,到細緻的權限控制與 CI/CD 整合,每個環節都體現了雲原生架構的設計理念。無論是金融業需要保護客戶資料、電商平台需要彈性調整配置,還是科技公司需要快速迭代部署,這些機制都提供了堅實的技術基礎。掌握這些最佳實務,將協助團隊在享受容器化帶來的敏捷性同時,確保系統的安全性與穩定性。