GKE 角色型存取權控管 (RBAC) 的最佳做法


本頁面提供規劃角色型存取權控管 (RBAC) 政策的最佳做法。如要瞭解如何在 Google Kubernetes Engine (GKE) 中導入 RBAC,請參閱「設定角色型存取權控管」。RBAC 是 Kubernetes 的核心安全功能,可讓您建立精細的權限,管理使用者和工作負載可對叢集中的資源執行的動作。您會建立 RBAC 角色,並將這些角色繫結主體,也就是經過驗證的使用者,例如服務帳戶或 Google 群組。

本頁內容適用於安全專家和作業人員,他們負責為機構規劃及實作 RBAC 政策。如要進一步瞭解 Google Cloud 內容中提及的常見角色和範例工作,請參閱常見的 GKE Enterprise 使用者角色和工作

閱讀本頁面之前,請先熟悉下列概念:

如需這項指引的檢查清單,請參閱「檢查清單摘要」。

RBAC 的運作方式

RBAC 支援下列類型的角色和繫結:

  • ClusterRole:一組可套用至任何命名空間或整個叢集的權限。
  • 角色:一組權限,僅限於單一命名空間。
  • ClusterRoleBinding:ClusterRole 繫結至使用者或群組,適用於叢集中的所有命名空間。
  • RoleBinding:RoleClusterRole 繫結至特定命名空間中的使用者或群組。

您可以在 RoleClusterRole 中將權限定義為 rules。角色中的每個 rules 欄位都包含 API 群組、該 API 群組中的 API 資源,以及允許對這些資源執行的動詞 (動作)。或者,您可以使用 resourceNames 欄位,將動詞範圍限定為 API 資源的具名執行個體。如需範例,請參閱「限制只能存取特定資源執行個體」。

定義角色後,您可以使用 RoleBindingClusterRoleBinding 將角色繫結至主體。根據您要在單一命名空間或多個命名空間中授予權限,選擇繫結類型。

RBAC 角色設計

遵循最低權限原則

指派 RBAC 角色所含權限時,請採用最低權限原則,並授予執行工作所需的最低權限。採用最低權限原則可以降低叢集遭駭時權限提升的可能性,以及因過度存取而引發安全事件的機率。

設計角色時,請仔細考量常見的權限提升風險,例如 escalatebind 動詞、PersistentVolume 的 create 存取權,或是 Certificate Signing Requests 的 create 存取權。如需風險清單,請參閱 Kubernetes RBAC - 權限提升風險

避免使用預設角色和群組

Kubernetes 會建立一組預設的 ClusterRole 和 ClusterRoleBinding,可用於 API 探索及啟用受管理元件功能。視角色而定,這些預設角色授予的權限可能相當廣泛。Kubernetes 也有一組預設使用者和使用者群組,以 system: 前置字元識別。根據預設,Kubernetes 和 GKE 會自動將這些角色繫結至預設群組和各種主體。如需 Kubernetes 建立的預設角色和繫結完整清單,請參閱「預設角色和角色繫結」。

下表說明部分預設角色、使用者和群組。建議您避免與這些角色、使用者和群組互動,除非您已仔細評估過,因為與這些資源互動可能會對叢集的安全性狀態造成意料之外的後果。

名稱 類型 說明
cluster-admin ClusterRole 授予主體在叢集內對任何資源執行任何操作的權限。
system:anonymous 使用者

Kubernetes 會將這個使用者指派給未提供驗證資訊的 API 伺服器要求。

將角色繫結至這個使用者後,任何未通過驗證的使用者都會獲得該角色授予的權限。

system:unauthenticated 群組

Kubernetes 會將這個群組指派給未提供驗證資訊的 API 伺服器要求。

將角色繫結至這個群組後,任何未通過驗證的使用者都會獲得該角色授予的權限。

system:authenticated 群組

如果使用者登入 Google 帳戶 (包括所有 Gmail 帳戶),GKE 會將這個群組指派給 API 伺服器要求。實際上,這與 system:unauthenticated 沒有顯著差異,因為任何人都能建立 Google 帳戶。

將角色繫結至這個群組後,任何擁有 Google 帳戶的使用者 (包括所有 Gmail 帳戶) 都會獲得該角色授予的權限。

system:masters 群組

Kubernetes 預設會將 cluster-admin ClusterRole 指派給這個群組,以啟用系統功能。

如果將自有主體新增至這個群組,這類主體就能對叢集內的各項資源執行任何操作。

請盡可能避免建立涉及預設使用者、角色和群組的繫結。這可能會對叢集的安全性狀態造成意想不到的後果。例如:

  • 將預設 cluster-admin ClusterRole 繫結至 system:unauthenticated 群組,會授予任何未經驗證的使用者存取叢集中所有資源 (包括密鑰) 的權限。這類高權限繫結是攻擊 (例如大規模惡意軟體活動) 的目標。
  • 將自訂角色繫結至 system:unauthenticated 群組,即可授予未經驗證的使用者該角色授予的權限。

請盡可能遵守下列規定:

  • 請勿將自己的主體新增至 system:masters 群組。
  • 請勿將 system:unauthenticated 群組繫結至任何 RBAC 角色。
  • 請勿將 system:authenticated 群組繫結至任何 RBAC 角色。
  • 請勿將 system:anonymous 使用者繫結至任何 RBAC 角色。
  • 請勿將 cluster-admin ClusterRole 繫結至您自己的主體,或任何預設使用者和群組。如果應用程式需要多項權限,請判斷確切需要的權限,並為此建立特定角色。
  • 繫結主體前,請先評估其他預設角色授予的權限。
  • 修改預設群組的成員之前,請先評估繫結至這些群組的角色。

禁止使用預設群組

您可以使用 gcloud CLI,在參照 system:unauthenticatedsystem:authenticated 群組或 system:anonymous 使用者的叢集中,停用非預設 RBAC 繫結。建立新的 GKE 叢集或更新現有叢集時,請使用下列一或兩個標記。使用這些標記不會停用參照這些群組的預設 Kubernetes 繫結。這些標記需要 GKE 1.30.1-gke.1283000 以上版本。

偵測及移除預設角色和群組的使用情形

如要檢查叢集是否在 RBAC 繫結中參照這些使用者和群組,請為叢集或車隊啟用 Kubernetes 安全防護機制掃描標準層級,這樣 GKE 就能在 Google Cloud 控制台的安全防護機制資訊主頁中顯示結果。如需操作說明,請參閱「啟用工作負載設定稽核」。

以下各節說明如何找出參照預設使用者和群組的特定 RoleBinding 或 ClusterRoleBinding,以及如何刪除這些資源。

ClusterRoleBindings
  1. 列出主體為 system:anonymoussystem:unauthenticatedsystem:authenticated 的所有 ClusterRoleBinding 名稱:

    kubectl get clusterrolebindings -o json \
      | jq -r '["Name"], ["-----"], (.items[] | select((.subjects | length) > 0) | select(any(.subjects[]; .name == "system:anonymous" or .name == "system:unauthenticated" or .name == "system:authenticated")) | [.metadata.namespace, .metadata.name]) | @tsv'
    

    輸出內容應只列出下列 ClusterRoleBinding:

    Name
    ----
    "system:basic-user"
    "system:discovery"
    "system:public-info-viewer"
    

    如果輸出內容包含其他非預設繫結,請為每個額外繫結執行下列步驟。如果輸出內容不含非預設繫結,請略過下列步驟。

  2. 列出與繫結相關聯的角色權限:

    kubectl get clusterrolebinding CLUSTER_ROLE_BINDING_NAME -o json \
        | jq ' .roleRef.name +" " + .roleRef.kind' \
        | sed -e 's/"//g' \
        | xargs -l bash -c 'kubectl get $1 $0 -o yaml'
    

    CLUSTER_ROLE_BINDING_NAME 替換為非預設 ClusterRoleBinding 的名稱。

    輸出結果會與下列內容相似:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
    ...
    rules:
    - apiGroups:
      - ""
      resources:
      - secrets
      verbs:
      - get
      - watch
      - list
    

    如果您判斷輸出內容中的權限可安全授予預設使用者或群組,則無須採取進一步行動。如果您判斷繫結授予的權限不安全,請繼續下一個步驟。

  3. 從叢集中刪除不安全的繫結:

    kubectl delete clusterrolebinding CLUSTER_ROLE_BINDING_NAME
    

    CLUSTER_ROLE_BINDING_NAME 替換為要刪除的 ClusterRoleBinding 名稱。

RoleBindings
  1. 列出主體為 system:anonymoussystem:unauthenticatedsystem:authenticated 的任何 RoleBinding 的命名空間和名稱:

    kubectl get rolebindings -A -o json \
      | jq -r '["Namespace", "Name"], ["---------", "-----"], (.items[] | select((.subjects | length) > 0) | select(any(.subjects[]; .name == "system:anonymous" or .name == "system:unauthenticated" or .name == "system:authenticated")) | [.metadata.namespace, .metadata.name]) | @tsv'
    

    如果叢集設定正確,輸出內容應為空白。 如果輸出內容包含任何非預設繫結,請針對每個額外繫結執行下列步驟。如果輸出結果空白,請略過後續步驟。

    如果您只知道 RoleBinding 的名稱,可以使用下列指令在所有命名空間中尋找相符的 RoleBinding:

    kubectl get rolebindings -A -o json \
      | jq -r '["Namespace", "Name"], ["---------", "-----"], (.items[] | select((.subjects | length) > 0) | select(.metadata.name == "ROLE_BINDING_NAME") | [.metadata.namespace, .metadata.name]) | @tsv'
    

    請將 ROLE_BINDING_NAME 替換為非預設 RoleBinding 的名稱。

  2. 列出與繫結相關聯的角色權限:

    kubectl get rolebinding ROLE_BINDING_NAME --namespace ROLE_BINDING_NAMESPACE -o json \
        | jq ' .roleRef.name +" " + .roleRef.kind' \
        | sed -e 's/"//g' \
        | xargs -l bash -c 'kubectl get $1 $0 -o yaml --namespace ROLE_BINDING_NAMESPACE'
    

    更改下列內容:

    • ROLE_BINDING_NAME:非預設 RoleBinding 的名稱。
    • ROLE_BINDING_NAMESPACE:非預設 RoleBinding 的命名空間。

    輸出結果會與下列內容相似:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    ...
    rules:
    - apiGroups:
      - ""
      resources:
      - secrets
      verbs:
      - get
      - watch
      - list
    

    如果您判斷輸出內容中的權限可安全授予預設使用者或群組,則無須採取進一步行動。如果您判斷繫結授予的權限不安全,請繼續下一個步驟。

  3. 從叢集中刪除不安全的繫結:

    kubectl delete rolebinding ROLE_BINDING_NAME --namespace ROLE_BINDING_NAMESPACE
    

    更改下列內容:

    • ROLE_BINDING_NAME:要刪除的 RoleBinding 名稱。
    • ROLE_BINDING_NAMESPACE:要刪除的 RoleBinding 命名空間。

將權限範圍設為命名空間層級

請根據工作負載或使用者的需求,使用繫結和角色:

  • 如要授予一個命名空間中資源的存取權,請使用 RoleRoleBinding
  • 如要授予多個命名空間中資源的存取權,請為每個命名空間使用 ClusterRoleRoleBinding
  • 如要授予每個命名空間中資源的存取權,請使用 ClusterRole,並搭配 ClusterRoleBinding

盡可能在最少的命名空間中授予權限。

請勿使用萬用字元

* 字元是適用於所有內容的萬用字元。請勿在規則中使用萬用字元。在 RBAC 規則中明確指定 API 群組、資源和動詞。舉例來說,在 verbs 欄位中指定 *,會授予資源 getlistwatchpatchupdatedeletecollectiondelete 權限。下表列出在規則中避免使用萬用字元的範例:

建議 不建議使用
- rules:
    apiGroups: ["apps","extensions"]
    resources: ["deployments"]
    verbs: ["get","list","watch"]

專門授予 appsextensions API 群組 getlistwatch 動詞。

- rules:
    apiGroups: ["*"]
    resources: ["deployments"]
    verbs: ["get","list","watch"]

將動詞授予任何 API 群組中的 deployments

- rules:
    apiGroups: ["apps", "extensions"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch"]

僅將 getlistwatch 動詞授予 appsextensions API 群組中的部署作業。

- rules:
    apiGroups: ["apps", "extensions"]
    resources: ["deployments"]
    verbs: ["*"]

授予所有動詞,包括 patchdelete

使用個別規則授予特定資源的最低權限存取權

規劃規則時,請嘗試下列高階步驟,為每個角色設計更有效率的最低權限規則:

  1. 針對主體需要存取的每個資源,為每個動詞草擬個別的 RBAC 規則。
  2. 草擬規則後,請分析規則,檢查是否有相同 verbs 清單的多項規則。將這些規則合併為單一規則。
  3. 將所有剩餘規則彼此分開。

這種做法可讓規則設計更有條理,將授予多個資源相同動詞的規則合併,並將授予資源不同動詞的規則分開。

舉例來說,如果工作負載需要 deployments 資源的 get 權限,但需要 listwatch 資源的 daemonsets 權限,則建立角色時應使用個別規則。將 RBAC 角色繫結至工作負載後,工作負載就無法在 deployments 上使用 watch

再舉一例,如果工作負載在 pods 資源和 daemonsets 資源上都需要 getwatch,您可以將這些項目合併為單一規則,因為工作負載在兩個資源上都需要相同的動詞。

下表顯示這兩種規則設計都有效,但分割規則可根據您的需求,更精細地限制資源存取權:

建議 不建議使用
- rules:
    apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get"]
- rules:
    apiGroups: ["apps"]
    resources: ["daemonsets"]
    verbs: ["list", "watch"]

授予 Deployment 的 get 存取權,以及 DaemonSet 的 watchlist 存取權。受試者無法列出部署作業。

- rules:
    apiGroups: ["apps"]
    resources: ["deployments", "daemonsets"]
    verbs: ["get","list","watch"]

將動詞授予 Deployment 和 DaemonSet。即使主體可能不需要存取list物件的deployments權限,仍會取得該權限。

- rules:
    apiGroups: ["apps"]
    resources: ["daemonsets", "deployments"]
    verbs: ["list", "watch"]

合併兩項規則,因為主體需要 daemonsetsdeployments 資源的相同動詞。

- rules:
    apiGroups: ["apps"]
    resources: ["daemonsets"]
    verbs: ["list", "watch"]
- rules:
    apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["list", "watch"]

這些分割規則與合併規則的結果相同,但會在角色資訊清單中產生不必要的雜亂內容

限制特定資源執行個體的存取權

RBAC 可讓您在規則中使用 resourceNames 欄位,限制對特定具名資源執行個體的存取權。舉例來說,如果您要編寫 RBAC 角色,該角色只需要 update seccomp-high ConfigMap,您可以使用 resourceNames 僅指定該 ConfigMap。請盡可能使用 resourceNames

建議 不建議使用
- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["seccomp-high"]
    verbs: ["update"]

將主體限制為只能更新 seccomp-high ConfigMap。主體無法更新命名空間中的任何其他 ConfigMap。

- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["update"]

主體可以更新 seccomp-high ConfigMap 和命名空間中的任何其他 ConfigMap。

- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["list"]
- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["seccomp-high"]
    verbs: ["update"]

具備命名空間中所有 ConfigMap 的 list 存取權,包括 seccomp-high。限制 update存取權,僅限 seccomp-high ConfigMap。由於您無法為具名資源授予 list,因此規則會拆分。

- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["update", "list"]

授予所有 ConfigMap 的 update 存取權,以及 list 存取權。

禁止服務帳戶修改 RBAC 資源

請勿將具有 bindescalatecreateupdatepatch 權限的 RoleClusterRole 資源,繫結至任何命名空間中的服務帳戶。rbac.authorization.k8s.ioescalatebind 特別容易讓攻擊者規避 RBAC 內建的權限提升防範機制

Kubernetes 服務帳戶

為各項工作負載建立 Kubernetes 服務帳戶

為每個工作負載建立個別的 Kubernetes 服務帳戶。將最低權限 RoleClusterRole 繫結至該服務帳戶。

請勿使用預設服務帳戶

Kubernetes 會在每個命名空間中建立名為 default 的服務帳戶。如果 Pod 未在資訊清單中明確指定服務帳戶,系統會自動將 default 服務帳戶指派給這些 Pod。請勿將 RoleClusterRole 繫結至 default 服務帳戶。Kubernetes 可能會將 default 服務帳戶指派給不需要這些角色授予存取權的 Pod。

不要自動掛接服務帳戶權杖

Pod 規格中的 automountServiceAccountToken 欄位會告知 Kubernetes 將 Kubernetes 服務帳戶的憑證權杖插入 Pod。Pod 可以使用這個權杖,向 Kubernetes API 伺服器發出已驗證的要求。這個欄位的預設值為 true

在所有 GKE 版本中,如果 Pod 不需要與 API 伺服器通訊,請在 Pod 規格中設定 automountServiceAccountToken=false

偏好使用臨時權杖,而非以 Secret 為基礎的權杖

根據預設,節點上的 kubelet 程序會為每個 Pod 擷取短期有效的服務帳戶權杖,並自動輪替。除非您在 Pod 規格中將 automountServiceAccountToken 欄位設為 false,否則 kubelet 會將這個權杖掛接至 Pod,做為投射磁碟區。Pod 對 Kubernetes API 的任何呼叫都會使用這個權杖,向 API 伺服器進行驗證。

如果您是手動擷取服務帳戶權杖,請避免使用 Kubernetes Secrets 儲存權杖。以密碼為基礎的服務帳戶權杖是舊版憑證,不會過期,也不會自動輪替。如需服務帳戶的憑證,請使用 TokenRequest API 取得會自動輪替的短期權杖。

持續檢查 RBAC 權限

定期檢查 RBAC 角色和存取權,找出潛在的權限提升路徑和多餘規則。舉例來說,假設您未刪除將具有特殊權限的 Role 繫結至已刪除使用者的 RoleBinding,如果攻擊者在該命名空間中建立與已刪除使用者同名的使用者帳戶,該帳戶就會繫結至 Role,並沿用相同的存取權。定期審查可將這類風險降至最低。

檢查清單摘要

後續步驟