限制对修改和选择 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。

费用

在本文档中,您将使用 Cloud de Confiance by S3NS的以下收费组件:

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

准备工作

  1. 安装 Google Cloud CLI。

  2. 配置 gcloud CLI 以使用您的联合身份。

    如需了解详情,请参阅使用联合身份登录 gcloud CLI

  3. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  4. 创建或选择 Cloud de Confiance 项目

    选择或创建项目所需的角色

    • 选择项目:选择项目不需要特定的 IAM 角色,您可以选择已获授角色的任何项目。
    • 创建项目:如需创建项目,您需要拥有 Project Creator 角色 (roles/resourcemanager.projectCreator),该角色包含 resourcemanager.projects.create 权限。了解如何授予角色
    • 创建 Cloud de Confiance 项目:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替换为您要创建的 Cloud de Confiance 项目的名称。

    • 选择您创建的 Cloud de Confiance 项目:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替换为您的 Cloud de Confiance 项目名称。

  5. 如果您要使用现有项目来完成本指南,请验证您是否拥有完成本指南所需的权限。如果您创建了新项目,则您已拥有所需的权限。

  6. 验证是否已为您的 Cloud de Confiance 项目启用结算功能

  7. 启用 Kubernetes Engine API:

    启用 API 所需的角色

    如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (roles/serviceusage.serviceUsageAdmin),该角色包含 serviceusage.services.enable 权限。了解如何授予角色

    gcloud services enable container.googleapis.com
  8. 如果您使用本地 shell,请安装 kubectl 组件:
    gcloud components install kubectl
  9. 确保您拥有使用 1.30 版或更高版本的 GKE 集群。您还可以创建 Autopilot 集群来完成本教程。
  10. 为 Google RBAC 群组配置集群:
    1. 在您的网域中设置 gke-security-groups 群组。
    2. 在集群中启用 Google RBAC 群组。

    如需了解详情,请参阅设置 Google 群组

所需的角色

如需获得在集群中创建 RBAC 政策和 Kubernetes 对象所需的权限,请让您的管理员为您授予项目的 Kubernetes Engine Admin (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 的节点污点对应的容忍
      • 使用与集群中所有节点污点匹配的容忍度。

    此 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 或 Deployment,并向 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. 群组名称字段中,指定 computeclass-editors
      2. 群组邮箱字段中,指定 computeclass-editors
      3. 选中安全复选框。
      4. 点击下一步
    4. 访问权限类型页面上的群组成员列中,验证谁可以查看成员复选框是否已选中。

    5. 点击创建群组

    6. 在导航菜单中,依次点击目录 > 群组

    7. 将光标悬停在 gke-security-groups 行上,然后点击添加成员

    8. 向 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 的不同条件:

    • 使用节点选择器选择不允许的 ComputeClass 的 Deployment:

      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 的容忍度的 Deployment:

      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:

      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 请求。如需保持这些政策处于有效状态,请跳过此部分。如果您是在学习或测试环境中按照本教程操作的,以下部分将介绍如何删除项目或各个资源。

删除项目

    删除 Cloud de Confiance 项目:

    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
    

后续步骤