Secret 權限控制 - ServiceAccount 與 RBAC 🎭
還記得昨天我們學會了 Secret 的基本使用嗎?但是各位,光會用 Secret 還不夠!就像銀行不能讓所有員工都能打開所有保險箱一樣,我們需要精確的權限控制。今天我們要學習 K8s 的身份認證與授權系統:ServiceAccount 和 RBAC!
想像你是一家跨國企業的 IT 安全主管,公司有開發團隊、測試團隊、運維團隊、安全稽核團隊,每個團隊都需要不同程度的 Secret 訪問權限。如何確保「開發人員只能看開發環境的密碼」、「稽核人員能看但不能改」、「運維人員能管理但要留下記錄」?這就是今天要解決的企業級挑戰!
✅ 理解 ServiceAccount:Kubernetes 的身份證系統
✅ 掌握 RBAC 權限控制:Role、ClusterRole、RoleBinding 的設計藝術
✅ 實作企業權限分級:為不同角色設計精確的 Secret 權限
跟一般系統做 RBAC 一樣,先建立身份ServiceAccount
。接著定義角色Role
跟對應的資源存取Resource
或功能權限。接著就能把角色綁訂Binding
給所需的身份上。
圖: K8s RBAC 元件之間的關係圖
命名空間內的權限鏈條:
Secret → ServiceAccount → RoleBinding → Role
↓ ↓ ↓ ↓
機密資料 身份認證 權限綁定 具體權限
實際運作流程:
Kubernetes 的身份證系統 🆔
想像你走進一家大型企業,沒有員工證就無法進入任何辦公區域。ServiceAccount 就是 Kubernetes 世界中的「員工證系統」!
沒有 ServiceAccount 的災難場景
# 😱 災難場景:所有 Pod 都使用預設權限
kubectl get pods --all-namespaces
# 任何 Pod 都能看到所有命名空間的資源
kubectl get secrets --all-namespaces
# 任何應用都能看到所有 Secret!
kubectl delete deployment critical-payment-service
# 甚至能刪除關鍵服務!
這會造成什麼問題?
🔴 權限過度授予:每個應用都有管理員權限
🔴 無法追蹤責任:不知道是誰執行了什麼操作
🔴 安全風險巨大:一個應用被攻破,整個集群淪陷
🔴 合規要求無法滿足:無法滿足金融業的審計要求
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:
# 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
# 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
# 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︰一個 Role 對象只能對用於授予對單一 namespace 中資源的訪問權限。
ClusterRole︰對整個 K8s cluster 內有效的角色。
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"]
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" # 批量刪除
設定規則決定將哪個用戶綁訂到哪個 Role 或 ClusterRole 上。
單個命名間空級別的權限控制:
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 ↔ 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
的角色。
# 🎯 開發環境的開發人員權限
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"]
# 🎯 運營環境的應用服務權限(最小權限原則)
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 中限制
# 🎯 運維工程師的集群管理權限
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、
Role和
RoleBinding 都設定好後。最後一步就是將
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 規則,以及所有操作紀錄就能有身份紀錄了。
傳統單體應用:
┌─────────────────────────────┐
│ 所有功能共享權限 │
│ ❌ 權限邊界模糊 │
└─────────────────────────────┘
微服務架構:
┌─────────┐ ┌─────────┐ ┌─────────┐
│支付服務 │ │用戶服務 │ │訂單服務 │
│專屬權限 │ │專屬權限 │ │專屬權限 │
└─────────┘ └─────────┘ └─────────┘
###分層思考的核心能力: