ComputeClass の変更と選択に対するアクセスを制限する

Google Kubernetes Engine(GKE)の ComputeClasses を使用すると、さまざまなワークロード要件を満たすノードを作成できます。Pod は ComputeClass を使用してハードウェアを作成できます。ComputeClass によって、そのハードウェアは需要が高い、可用性が低い、または企業にとって比較的コストが高い場合があります。このチュートリアルでは、Kubernetes RBAC と ValidatingAdmissionPolicies を使用して、ComputeClass の作成、削除、変更、選択を制限する方法について説明します。

これらの制限により、次のような状況を防ぐことができます。

  • GPU や TPU などの専用ハードウェアを必要としない Pod は、そのハードウェアをリクエストする ComputeClass を選択します。
  • 未承認のエンティティが ComputeClass を作成または変更して、重要なワークロード用に予約されているハードウェアにアクセスします。

このドキュメントでは、ワイルドカード ComputeClass 許容や特定の許可されていない ComputeClass の選択など、一般的なタイプの不正使用をブロックする ValidatingAdmissionPolicy の例を使用します。ValidatingAdmissionPolicy を変更して、特定のチームのワークロードが ComputeClass を使用できないようにするなど、組織固有の要件を満たすことができます。

目標

  • ValidatingAdmissionPolicy を使用して、各 Namespace で Pod が選択できる ComputeClass を承認済みリストに制限します。
  • ロールベース アクセス制御(RBAC)を使用して、クラスタ内の ComputeClass の作成、変更、削除を行うユーザーを制限します。

費用

このドキュメントでは、課金対象である次の Cloud de Confiance by S3NSコンポーネントを使用します。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

  1. Google Cloud CLI をインストールします。

  2. フェデレーション ID(連携 ID)を使用するように gcloud CLI を構成します。

    詳細については、連携 ID を使用して gcloud CLI にログインするをご覧ください。

  3. gcloud CLI を初期化するには、次のコマンドを実行します。

    gcloud init
  4. Cloud de Confiance プロジェクトを作成または選択します

    プロジェクトの選択または作成に必要なロール

    • プロジェクトを選択する: プロジェクトの選択に特定の IAM ロールは必要ありません。ロールが付与されているプロジェクトであれば、どのプロジェクトでも選択できます。
    • プロジェクトを作成する: プロジェクトを作成するには、resourcemanager.projects.create 権限を含むプロジェクト作成者ロール(roles/resourcemanager.projectCreator)が必要です。詳しくは、ロールを付与する方法をご覧ください。
    • 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 を有効にするには、serviceusage.services.enable 権限が必要です。プロジェクトを作成した場合は、オーナーロール(roles/owner)を介してこの権限がすでに付与されている可能性があります。それ以外の場合は、Service Usage 管理者ロール(roles/serviceusage.serviceUsageAdmin)を介してこの権限を取得できます。ロールを付与する方法をご覧ください。

    gcloud services enable container.googleapis.com
  8. ローカルシェルを使用する場合は、kubectl コンポーネントをインストールします。
    gcloud components install kubectl
  9. バージョン 1.30 以降を使用する GKE クラスタがあることを確認します。このチュートリアルでは、Autopilot クラスタを作成することもできます。
  10. 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. このチュートリアルで使用する Namespace を作成します。クラスタ内の既存の Namespace を使用することもできます。

    kubectl create namespace computeclass-vap-tutorial
    
  3. ValidatingAdmissionPolicies と ValidatingAdmissionPolicyBindings の管理権限を付与する RBAC ポリシーを作成します。

    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 を作成して、特定の Namespace で適用します。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 に対応する toleration を使用します。
      • クラスタ内のすべてのノード taint と一致する toleration を使用します。

    この 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 は、前の手順の ValidatingAdmissionPolicy を computeclass-vap-tutorial Namespace で適用します。validationActions フィールドの値は、ValidatingAdmissionPolicy に違反する Pod または Deployment を拒否し、Kubernetes 監査ログにエントリを追加します。

  4. ValidatingAdmissionPolicyBinding を作成します。

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

RBAC ポリシーを構成する

ValidatingAdmissionPolicy を使用してワークロードが特定の ComputeClass を使用できないようにするだけでなく、RBAC を使用して、承認されていないプリンシパルがクラスタ内の ComputeClass を作成および変更できないようにします。次の手順では、RBAC 向け Google グループを使用して、特定のユーザー グループに ComputeClass へのアクセス権を付与する方法について説明します。

  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 のノード アフィニティ ルールがある 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
            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. サンプル Namespace を削除します。

    kubectl delete namespace computeclass-vap-tutorial
    

次のステップ