限制修改和選取 ComputeClass 的存取權

您可以使用 Google Kubernetes Engine (GKE) ComputeClasses 建立節點,滿足各種工作負載需求。Pod 可以使用 ComputeClass 建立硬體。視 ComputeClass 而定,該硬體可能供不應求、供應量有限,或對貴公司而言相對昂貴。本教學課程說明如何使用 Kubernetes RBAC 和ValidatingAdmissionPolicies,限制 ComputeClass 的建立、刪除、修改和選取作業。

這些限制有助於避免下列情況:

  • 不需要 GPU 或 TPU 等專用硬體的 Pod 會選取要求該硬體的 ComputeClass。
  • 未經授權的實體建立或修改 ComputeClass,以存取為重要工作負載保留的硬體。

本文使用 ValidatingAdmissionPolicy 範例,封鎖常見的濫用類型,例如萬用字元 ComputeClass 容許度,或選取特定禁止的 ComputeClass。您可以修改 ValidatingAdmissionPolicy,以符合貴機構的特定需求,例如禁止特定團隊的工作負載使用 ComputeClass。

目標

  • 使用 ValidatingAdmissionPolicy,將每個命名空間中 Pod 可選取的 ComputeClass 限制在核准清單內。
  • 使用角色型存取控管 (RBAC),限制叢集中可建立、修改或刪除 ComputeClass 的使用者。

費用

在本文件中,您會使用下列 Google Cloud的計費元件:

如要根據預測用量估算費用,請使用 Pricing Calculator

初次使用 Google Cloud 的使用者可能符合免費試用期資格。

完成本文所述工作後,您可以刪除建立的資源,避免繼續計費,詳情請參閱「清除所用資源」。

事前準備

  1. 登入 Google Cloud 帳戶。如果您是 Google Cloud新手,歡迎 建立帳戶,親自評估產品在實際工作環境中的成效。新客戶還能獲得價值 $300 美元的免費抵免額,可用於執行、測試及部署工作負載。
  2. 安裝 Google Cloud CLI。

  3. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

  4. 執行下列指令,初始化 gcloud CLI:

    gcloud init
  5. 建立或選取 Google Cloud 專案

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需要具備特定 IAM 角色,只要您在專案中獲派角色,即可選取該專案。
    • 建立專案:如要建立專案,您需要「專案建立者」角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色
    • 建立 Google Cloud 專案:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  6. 如要使用現有專案進行本指南中的操作,請確認您具有完成本指南所需的權限。如果您建立新專案,則已具備必要權限。

  7. 確認專案已啟用計費功能 Google Cloud

  8. 啟用 Kubernetes Engine API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable container.googleapis.com
  9. 安裝 Google Cloud CLI。

  10. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

  11. 執行下列指令,初始化 gcloud CLI:

    gcloud init
  12. 建立或選取 Google Cloud 專案

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需要具備特定 IAM 角色,只要您在專案中獲派角色,即可選取該專案。
    • 建立專案:如要建立專案,您需要「專案建立者」角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色
    • 建立 Google Cloud 專案:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  13. 如要使用現有專案進行本指南中的操作,請確認您具有完成本指南所需的權限。如果您建立新專案,則已具備必要權限。

  14. 確認專案已啟用計費功能 Google Cloud

  15. 啟用 Kubernetes Engine API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable container.googleapis.com
  16. 如果您使用本機殼層,請安裝 kubectl 元件:
    gcloud components install kubectl
  17. 確認您有使用 1.30 以上版本的 GKE 叢集。您也可以建立 Autopilot 叢集,以進行本教學課程。
  18. 設定叢集以使用 RBAC 適用的 Google 群組:
    1. 在網域中設定 gke-security-groups 群組。
    2. 在叢集中啟用 RBAC 適用的 Google 群組。

    詳情請參閱「設定 Google 網路論壇」一文。

必要的角色

如要取得在叢集中建立 RBAC 政策和 Kubernetes 物件所需的權限,請要求管理員授予您專案的 Kubernetes Engine 管理員 (role/container.admin) IAM 角色。如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和機構的存取權」。

您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

準備環境

如要準備叢集,以便在本教學課程中建立及驗證資源,請按照下列步驟操作:

  1. 連線至叢集:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=CONTROL_PLANE_LOCATION
    

    更改下列內容:

    • CLUSTER_NAME:叢集名稱。
    • CONTROL_PLANE_LOCATION:叢集控制層的區域或可用區,例如 us-central1us-central1-a
  2. 建立要用於本教學課程的命名空間。您也可以使用叢集中的任何現有命名空間。

    kubectl create namespace computeclass-vap-tutorial
    
  3. 建立 RBAC 政策,授予管理 ValidatingAdmissionPolicies 和 ValidatingAdmissionPolicyBindings 的存取權:

    1. 將下列資訊清單儲存為 validatingadmissionpolicy-editor.yaml

      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: validatingadmissionpolicy-editor
      rules:
      - apiGroups: ["admissionregistration.k8s.io"]
        resources: ["validatingadmissionpolicies","validatingadmissionpolicybindings"]
        verbs: ["get", "list", "create", "update", "patch", "delete"]
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
        name: edit-validatingadmissionpolicies
      subjects:
      - kind: User
        name: USER_ACCOUNT
        apiGroup: rbac.authorization.k8s.io
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: ClusterRole
        name: validatingadmissionpolicy-editor
      

      USER_ACCOUNT 替換為使用者帳戶的電子郵件地址。

    2. 建立 RBAC 政策:

      kubectl apply -f validatingadmissionpolicy-editor.yaml
      
  4. 在叢集中建立 ComputeClass。如果叢集已有 ComputeClass,請略過這個步驟。

    1. 將下列資訊清單儲存為 access-computeclass.yaml

      apiVersion: cloud.google.com/v1
      kind: ComputeClass
      metadata:
        name: access-restriction-class
      spec:
        priorities:
        - machineFamily: e2
        nodePoolAutoCreation:
          enabled: true
        whenUnsatisfiable: ScaleUpAnyway
      
    2. 建立 ComputeClass:

      kubectl apply -f access-computeclass.yaml
      

建立 ValidatingAdmissionPolicy

如要限制 Pod 可選取的 ComputeClass,請建立 ValidatingAdmissionPolicy,並在特定命名空間中強制執行。您可以使用 ValidatingAdmissionPolicy 規格,控管 Pod 選取 ComputeClass 的方式。以下步驟說明如何建立及強制執行這項政策:

  1. 將下列 ValidatingAdmissionPolicy 資訊清單儲存為 restrict-computeclass-usage-vap.yaml

    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingAdmissionPolicy
    metadata:
      name: restrict-computeclass-usage
    spec:
      failurePolicy: Fail # If an internal error occurs, deny the request.
      variables:
      # Check whether the admission request is for a Deployment.
      - name: isDeployment
        expression: "object.kind == 'Deployment'"
      # Get the Pod specification from the admission request by reading the
      # spec.template.spec field for Deployments or the spec field for static Pods.
      - name: podSpec
        expression: "variables.isDeployment ? object.spec.template.spec : object.spec"
      # Check whether a node selector or an affinity rule that explicitly requests a
      # disallowed ComputeClass.
      - name: hasForbiddenNodeSelectorOrAffinity
        expression: >-
          (has(variables.podSpec.nodeSelector) &&
          variables.podSpec.nodeSelector['cloud.google.com/compute-class'] == 'COMPUTECLASS_NAME') ||
          (has(variables.podSpec.affinity) &&
          has(variables.podSpec.affinity.nodeAffinity) &&
          has(variables.podSpec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution) &&
          variables.podSpec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.exists(term, has(term.matchExpressions) &&
            term.matchExpressions.exists(
              exp, exp.key == 'cloud.google.com/compute-class' &&
              exp.operator == 'In' && exp.values.exists(v, v == 'COMPUTECLASS_NAME')
            )
          ))
    
      # Check whether the Pod has a toleration for the taint that corresponds to a
      # disallowed ComputeClass.
      - name: hasForbiddenComputeClassToleration
        expression: >-
          has(variables.podSpec.tolerations) &&
          variables.podSpec.tolerations.exists(t, 
            t.key == 'cloud.google.com/compute-class' &&
            (t.operator == 'Exists' || (t.operator == 'Equal' && t.value == 'COMPUTECLASS_NAME')) &&
            has(t.effect) && t.effect == 'NoSchedule')
    
      # Check whether the Pod has a toleration that could match any taint.
      - name: hasWildcardToleration
        expression: >-
          has(variables.podSpec.tolerations) &&
          variables.podSpec.tolerations.exists(t, 
            (t.operator == 'Exists' && !(has(t.key) && t.key != ''))
          )
    
      # Trigger the ValidatingAdmissionPolicy when Pods or Deployments are created or
      # updated.
      matchConstraints:
        resourceRules:
        - apiGroups: [""]
          apiVersions: ["v1"]
          operations: ["CREATE", "UPDATE"]
          resources: ["pods"]
        - apiGroups: ["apps"]
          apiVersions: ["v1"]
          operations: ["CREATE", "UPDATE"]
          resources: ["deployments"]
    
      # Validate whether any of the expressions in the variables section evaluate to
      # true.
      validations:
        - expression: >-
            !(variables.hasForbiddenNodeSelectorOrAffinity ||
              variables.hasForbiddenComputeClassToleration ||
              variables.hasWildcardToleration)
          message: >-
            Pods and Deployments in this namespace cannot request ComputeClass
            COMPUTECLASS_NAME or use wildcard
            tolerations.
    

    COMPUTECLASS_NAME 替換為要禁止 Pod 選取的 ComputeClass 名稱。

    這個 ValidatingAdmissionPolicy 具有下列屬性:

    • 靜態 Pod 或 Deployment 中的 Pod 觸發條件。
    • 找出執行下列任一動作的 Pod:

      • 使用節點選取器或節點相依性規則,明確選取特定不允許的 ComputeClass。
      • 使用與特定不允許的 ComputeClass 節點 taint 相對應的容許條件
      • 使用與叢集中所有節點汙染相符的容許條件。

    這個 ValidatingAdmissionPolicy 是範例。您可以根據自己的條件使用運算式觸發政策,例如防止具有特定標籤的 Pod 選取特定 ComputeClass。

  2. 建立 ValidatingAdmissionPolicy:

    kubectl apply -f restrict-computeclass-usage-vap.yaml
    
  3. 將下列 ValidatingAdmissionPolicyBinding 儲存為 restrict-computeclass-usage-binding.yaml

    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingAdmissionPolicyBinding
    metadata:
      name: restrict-computeclass-usage-binding
    spec:
      policyName: restrict-computeclass-usage
      validationActions: ["Deny","Audit"]
      matchResources:
        namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: computeclass-vap-tutorial # Replace with the name of any namespace in the cluster.
    

    這個 ValidatingAdmissionPolicyBinding 會在 computeclass-vap-tutorial 命名空間中,強制執行上一個步驟的 ValidatingAdmissionPolicy。validationActions 欄位中的值會拒絕違反 ValidatingAdmissionPolicy 的 Pod 或部署項目,並在 Kubernetes 稽核記錄中新增項目。

  4. 建立 ValidatingAdmissionPolicyBinding:

    kubectl apply -f restrict-computeclass-usage-binding.yaml
    

設定 RBAC 政策

除了使用 ValidatingAdmissionPolicy 防止工作負載使用特定 ComputeClass 外,您也可以使用 RBAC,防止未經授權的主體在叢集中建立及修改 ComputeClass。下列步驟說明如何使用 Google 網路論壇進行 RBAC,將 ComputeClasses 的存取權授予特定使用者群組:

  1. 為 ComputeClass 編輯者建立群組:

    1. 前往 Google 管理控制台的「群組」頁面。

      前往網上論壇

    2. 按一下 [建立群組]

    3. 在「群組詳細資料」頁面中,執行下列操作:

      1. 在「Group name」(群組名稱) 欄位中,指定 computeclass-editors
      2. 在「群組電子郵件」欄位中,指定 computeclass-editors
      3. 選取「安全性」核取方塊。
      4. 點選「下一步」
    4. 在「存取類型」頁面的「群組成員」欄中,確認已選取「可以檢視成員的使用者」核取方塊。

    5. 按一下 [建立群組]

    6. 在導覽選單中,依序點選「目錄」>「群組」

    7. 將游標懸停在「gke-security-groups」列上,然後按一下「新增成員」

    8. 在「Add members to gke-security-groups」(將成員新增至 gke-security-groups) 對話方塊中,指定 computeclass-editors 並從結果中選取該群組。

    9. 按一下 [加入群組]

  2. 將授權使用者的電子郵件地址新增至群組。computeclass-editors

  3. 將下列 ClusterRole 儲存為 computeclass-editor-clusterrole.yaml

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: computeclass-editor
    rules:
    -   apiGroups: ["cloud.google.com"]
      resources: ["computeclasses"]
      verbs: ["create","update"]
    
  4. 建立 ClusterRole:

    kubectl apply -f computeclass-editor-clusterrole.yaml
    
  5. 將下列 ClusterRoleBinding 儲存為 computeclass-editor-role-binding.yaml

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: computeclass-editor-role-binding
    subjects:
    - kind: Group
      name: computeclass-editors@GROUP_DOMAIN
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: ClusterRole
      name: computeclass-editor
      apiGroup: rbac.authorization.k8s.io # Required for role references
    

    GROUP_DOMAIN 替換為 computeclass-editors 群組的網域名稱。

  6. 建立 ClusterRoleBinding:

    kubectl apply -f computeclass-editor-role-binding.yaml
    

確認限制

以下各節說明如何確認您在上述各節中設定的限制是否正常運作。如果您在 ValidatingAdmissionPolicies 或 RBAC 政策中設定自己的限制,請建立違反這些政策的工作負載,測試這些限制。

驗證 ValidatingAdmissionPolicy

  1. 儲存下列任一資訊清單,這些資訊清單各自違反 ValidatingAdmissionPolicy 的不同條件:

    • Deployment 使用節點選取器選取不允許的 ComputeClass:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: disallowed-computeclass-deployment
        namespace: computeclass-vap-tutorial
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: forbidden-selector-app
        template:
          metadata:
            labels:
              app: forbidden-selector-app
          spec:
            containers:
            - name: my-app-container
              image: nginx:latest
            # The node selector triggers the policy.
            nodeSelector:
              cloud.google.com/compute-class: COMPUTECLASS_NAME
      
    • 部署作業容許使用不允許的 ComputeClass:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: disallowed-computeclass-deployment-toleration
        namespace: computeclass-vap-tutorial
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: forbidden-selector-app
        template:
          metadata:
            labels:
              app: forbidden-selector-app
          spec:
            containers:
            - name: my-app-container
              image: nginx:latest
            tolerations:
            - key: cloud.google.com/compute-class
              operator: Equal
              value: COMPUTECLASS_NAME
              effect: NoSchedule
      
    • 部署作業,其中包含不允許的 ComputeClass 節點親和性規則:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: disallowed-computeclass-deployment-toleration
        namespace: computeclass-vap-tutorial
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: forbidden-selector-app
        template:
          metadata:
            labels:
              app: forbidden-selector-app
          spec:
            containers:
            - name: my-app-container
              image: nginx:latest
            affinity:
              nodeAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                  nodeSelectorTerms:
                  - matchExpressions:
                    - key: cloud.google.com/compute-class
                      operator: In
                      values:
                      - COMPUTECLASS_NAME
      
    • Pod 容許叢集中的任何節點 taint:

      apiVersion: v1
      kind: Pod
      metadata:
        name: disallowed-computeclass-deployment-toleration
        namespace: computeclass-vap-tutorial
      spec:
        containers:
        - name: my-app-container
          image: nginx:latest
        tolerations:
        - operator: Exists
          effect: NoSchedule
      
  2. 建立測試工作負載:

    kubectl apply -f PATH_TO_WORKLOAD_MANIFEST
    

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

    Error from server (BadRequest): admission webhook "validation-policy.kubernetes.io" denied the request: Pods and Deployments in this namespace cannot request ComputeClass COMPUTECLASS_NAME or use wildcard tolerations.
    

驗證 RBAC 設定

如要驗證 RBAC 設定,請按照下列步驟操作:

  1. 使用 computeclass-editors 群組成員的使用者憑證,向叢集進行驗證。

  2. 檢查使用者是否可以建立 ComputeClass:

    kubectl auth can-i create computeclasses.cloud.google.com \
        --as=MEMBER_USER
    

    MEMBER_USER 替換為群組成員的電子郵件地址。

    輸出內容為 yes

  3. 使用不屬於 computeclass-editors 群組的使用者憑證,向叢集進行驗證。

  4. 檢查使用者是否可以建立 ComputeClass:

    kubectl auth can-i create computeclasses.cloud.google.com \
        --as=NON_MEMBER_USER
    

    NON_MEMBER_USER 替換為非群組成員的使用者電子郵件地址。

    輸出內容為 no

如果 kubectl auth can-i 指令的輸出內容是 yes,但使用者不是群組成員,請確認下列事項:

  • computeclass-editors 群組是 gke-security-groups 群組的成員。
  • ClusterRoleBinding 中的群組電子郵件地址必須是群組的確切電子郵件地址,例如 computeclass-editors@example.com

清除所用資源

為避免因為本教學課程所用資源,導致系統向 Google Cloud 帳戶收取費用,請刪除含有相關資源的專案,或者保留專案但刪除個別資源。

如果您在本教學課程中,將 ValidatingAdmissionPolicy 和 RBAC 政策部署至正式版叢集,GKE 會封鎖違反政策的傳入 Pod 和 API 要求。如要維持這些政策的效力,請略過本節。如果您是在學習或測試環境中完成本教學課程,請參閱下列各節,瞭解如何刪除專案或個別資源。

刪除專案

    刪除 Google Cloud 專案:

    gcloud projects delete PROJECT_ID

刪除個別資源

  1. 刪除您建立的 ComputeClass:

    kubectl delete computeclass access-restriction-class
    
  2. 刪除 ValidatingAdmissionPolicy 和 ValidatingAdmissionPolicyBinding:

    kubectl delete validatingadmissionpolicy restrict-computeclass-usage
    kubectl delete validatingadmissionpolicybinding restrict-computeclass-usage-binding
    
  3. 刪除 ClusterRole 和 ClusterRoleBinding:

    kubectl delete clusterroles \
        computeclass-editor validatingadmissionpolicy-editor
    kubectl delete clusterrolebindings \
        computeclass-editor-role-binding edit-validatingadmissionpolicies
    
  4. 刪除範例命名空間:

    kubectl delete namespace computeclass-vap-tutorial
    

後續步驟