您可以使用 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的以下收费组件:
完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理。
准备工作
-
安装 Google Cloud CLI。
-
配置 gcloud CLI 以使用您的联合身份。
如需了解详情,请参阅使用联合身份登录 gcloud CLI。
-
如需初始化 gcloud CLI,请运行以下命令:
gcloud init -
选择或创建项目所需的角色
- 选择项目:选择项目不需要特定的 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 项目名称。
-
如果您要使用现有项目来完成本指南,请验证您是否拥有完成本指南所需的权限。如果您创建了新项目,则您已拥有所需的权限。
启用 Kubernetes Engine API:
启用 API 所需的角色
如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (
roles/serviceusage.serviceUsageAdmin),该角色包含serviceusage.services.enable权限。了解如何授予角色。gcloud services enable container.googleapis.com
- 如果您使用本地 shell,请安装
kubectl组件:gcloud components install kubectl
- 确保您拥有使用 1.30 版或更高版本的 GKE 集群。您还可以创建 Autopilot 集群来完成本教程。
- 为 Google RBAC 群组配置集群:
- 在您的网域中设置
gke-security-groups群组。 - 在集群中启用 Google RBAC 群组。
如需了解详情,请参阅设置 Google 群组。
- 在您的网域中设置
所需的角色
如需获得在集群中创建 RBAC 政策和 Kubernetes 对象所需的权限,请让您的管理员为您授予项目的 Kubernetes Engine Admin (role/container.admin) IAM 角色。
如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。
准备环境
如需为本教程中的创建和验证任务准备集群,请按以下步骤操作:
连接到集群:
gcloud container clusters get-credentials CLUSTER_NAME \ --location=CONTROL_PLANE_LOCATION替换以下内容:
CLUSTER_NAME:您的集群的名称。CONTROL_PLANE_LOCATION:集群控制平面的区域或可用区,例如us-central1或us-central1-a。
创建一个命名空间,供本教程使用。您还可以使用集群中的任何现有命名空间。
kubectl create namespace computeclass-vap-tutorial创建 RBAC 政策,以授予管理 ValidatingAdmissionPolicies 和 ValidatingAdmissionPolicyBindings 的权限:
将以下清单保存为
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替换为您的用户账号的电子邮件地址。创建 RBAC 政策:
kubectl apply -f validatingadmissionpolicy-editor.yaml
在集群中创建 ComputeClass。如果集群已具有 ComputeClass,请跳过此步骤。
将以下清单保存为
access-computeclass.yaml:apiVersion: cloud.google.com/v1 kind: ComputeClass metadata: name: access-restriction-class spec: priorities: - machineFamily: e2 nodePoolAutoCreation: enabled: true whenUnsatisfiable: ScaleUpAnyway创建 ComputeClass:
kubectl apply -f access-computeclass.yaml
创建 ValidatingAdmissionPolicy
如需限制 Pod 可选择的 ComputeClass,您可以创建 ValidatingAdmissionPolicy,并在特定命名空间中强制执行该政策。您可以使用 ValidatingAdmissionPolicy 规范来控制 Pod 如何选择 ComputeClass。以下步骤展示了如何创建和强制执行此政策:
将以下 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。
创建 ValidatingAdmissionPolicy:
kubectl apply -f restrict-computeclass-usage-vap.yaml将以下 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 审核日志添加条目。创建 ValidatingAdmissionPolicyBinding:
kubectl apply -f restrict-computeclass-usage-binding.yaml
配置 RBAC 政策
除了使用 ValidatingAdmissionPolicy 阻止工作负载使用某些 ComputeClass 之外,还可以使用 RBAC 阻止未经授权的主账号在集群中创建和修改 ComputeClass。以下步骤展示了如何使用 Google RBAC 群组向特定用户群组授予对 ComputeClasses 的访问权限:
为 ComputeClass 编辑者创建群组:
在 Google 管理员控制台中,前往群组页面。
点击创建群组。
在群组详情页面上,执行以下操作:
- 在群组名称字段中,指定
computeclass-editors。 - 在群组邮箱字段中,指定
computeclass-editors。 - 选中安全复选框。
- 点击下一步。
- 在群组名称字段中,指定
在访问权限类型页面上的群组成员列中,验证谁可以查看成员复选框是否已选中。
点击创建群组。
在导航菜单中,依次点击目录 > 群组。
将光标悬停在 gke-security-groups 行上,然后点击添加成员。
在向 gke-security-groups 添加成员对话框中,指定
computeclass-editors,然后从结果中选择该群组。点击添加到群组。
将已获授权的用户的电子邮件地址添加到
computeclass-editors群组。将以下 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"]创建 ClusterRole:
kubectl apply -f computeclass-editor-clusterrole.yaml将以下 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群组的域名。创建 ClusterRoleBinding:
kubectl apply -f computeclass-editor-role-binding.yaml
验证限制
以下部分将介绍如何验证您在前面部分中配置的限制是否按预期运行。如果您在 ValidatingAdmissionPolicies 或 RBAC 政策中配置了自己的限制,请通过创建违反这些政策的工作负载来测试这些限制。
验证 ValidatingAdmissionPolicy
保存以下任一清单,每个清单都违反了 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
创建测试工作负载:
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 配置,请按以下步骤操作:
使用属于
computeclass-editors群组的用户的凭据向集群进行身份验证。检查用户是否可以创建 ComputeClass:
kubectl auth can-i create computeclasses.cloud.google.com \ --as=MEMBER_USER将
MEMBER_USER替换为相应群组中某个用户的电子邮件地址。输出为
yes。使用不是
computeclass-editors群组成员的用户的凭据向集群进行身份验证。检查用户是否可以创建 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
删除各个资源
删除您创建的 ComputeClass:
kubectl delete computeclass access-restriction-class删除 ValidatingAdmissionPolicy 和 ValidatingAdmissionPolicyBinding:
kubectl delete validatingadmissionpolicy restrict-computeclass-usage kubectl delete validatingadmissionpolicybinding restrict-computeclass-usage-binding删除 ClusterRole 和 ClusterRoleBinding:
kubectl delete clusterroles \ computeclass-editor validatingadmissionpolicy-editor kubectl delete clusterrolebindings \ computeclass-editor-role-binding edit-validatingadmissionpolicies删除示例命名空间:
kubectl delete namespace computeclass-vap-tutorial
后续步骤
- 查看集群安全方面的最佳实践
- 探索有关 Google Cloud 的参考架构、图表和最佳做法。查看我们的 Cloud 架构中心。