Workload Identity の使用

このページでは、Google API によって提供されるサービスを Google Kubernetes Engine(GKE)アプリケーションで使用する際に推奨される方法を説明します。

概要

Workload Identity を使用して GKE 内で実行しているアプリケーションから Google Cloud サービスにアクセスすることをおすすめするのは、セキュリティのプロパティと管理性が優れているからです。GKE から Google Cloud API にアクセスする別の方法については、下の別の方法セクションをご覧ください。

用語

このドキュメントでは、Kubernetes サービス アカウントGoogle サービス アカウントを区別しています。Kubernetes サービス アカウントは Kubernetes のリソースですが、Google サービス アカウントは Google Cloud 固有のものです。Google Cloud の他のドキュメントでは、Google サービス アカウントを「サービス アカウント」と表記しています。

概念

GKE で実行されるアプリケーションで、Compute API、Storage API、Database API、Machine Learning API などの Google Cloud APIs を使用するには認証が必要です。

Workload Identity では、Kubernetes サービス アカウントを構成して Google サービス アカウントとして使用します。Kubernetes サービス アカウントとして実行されるアプリケーションは、Google Cloud APIs にアクセスするとき自動的に Google サービス アカウントとして認証されます。これにより、クラスタ内のアプリケーションにきめ細かい ID と承認の割り当てを行えます。

Kubernetes サービス アカウントと Google サービス アカウント間の安全なマッピングを実現するために、Workload Identity は、クラスタのワークロード ID プールの概念を導入します。これにより、Identity and Access Management(IAM)は Kubernetes サービス アカウントの認証情報を信頼して確認できます。

GKE クラスタで Workload Identity を有効にする際は、クラスタの Workload Identity プールを my-pool.svc.id.goog に設定します。これにより、IAM は次のメンバー名で Kubernetes サービス アカウントを認証できます。

serviceAccount:my-pool.svc.id.goog[k8s-namespace/ksa-name]

このメンバー名で:

  • my-pool.svc.id.goog は、クラスタで設定された Workload Identity プールです。
  • ksa-name は、リクエストを行っている Kubernetes サービス アカウントの名前です。
  • k8s-namespace は、Kubernetes サービス アカウントが定義されている Kubernetes Namespace です。

Google Cloud プロジェクトごとに、自動的に Workload Identity プール project-id.svc.id.goog が 1 つだけ作成されて固定されます。

クラスタ間での ID の共有

名前、名前空間名、workload identity プールを共有するすべての Kubernetes サービス アカウントが同じメンバー名に解決されて、Google Cloud リソースへのアクセスが共有されます。これは、複数のクラスタに同じ ID が含まれている場合に便利ですが、Kubernetes サービス アカウント名と名前空間が慎重に管理されていないと危険です。

たとえば、Workload Identity がクラスタで有効になっている場合、次のコマンドによって、プロジェクト内のあらゆるクラスタ内で、デフォルトのサービス アカウントと名前空間を使用するすべての Kubernetes ワークロードに、同じアクセス権が付与されます。

gcloud iam service-accounts add-iam-policy-binding \
  --role roles/iam.workloadIdentityUser \
  --member "serviceAccount:project-id.svc.id.goog[default/default]" \
  gsa-name@project-id.iam.gserviceaccount.com

制限事項

  • 現在のところ、Google Cloud プロジェクトごとに自動的に Workload Identity プール project-id.svc.id.goog が 1 つだけ作成され、固定されます。

  • 現時点では、ワークロードが GKE On-Prem クラスタで実行されている場合、Workload Identity はサポートされません。

  • Workload Identity は、メタデータ隠蔽機能に代わるもので、この 2 つに互換性はありません。メタデータ隠蔽機能で保護された機密メタデータは Workload Identity でも保護されます。

  • ノードプールで GKE メタデータ サーバーが有効にされると、Pod は Compute Engine のメタデータ サーバーにアクセスできなくなります。代わりに、これらの Pod から Metadata API に送信されたリクエストは、GKE メタデータ サーバーにルーティングされます。ただし、ホスト ネットワークで実行されている Pod は例外です(次をご覧ください)。

  • ホスト ネットワークで実行されている Pod で Workload Identity を使用することはできません。これらの Pod から Metadata API に送信されたリクエストは、Compute Engine のメタデータ サーバーにルーティングされます。

  • GKE メタデータ サーバーが新しく作成された Pod で実行を開始するまでには、数秒かかります。したがって、Pod の有効期間の最初の数秒以内に Workload Identity を使用して認証または承認を試みると、失敗する可能性があります。この問題は、呼び出しを再試行することで解決します。

  • GKE の Logging および Monitoring エージェントは、ノードのサービス アカウントを引き続き使用します。

  • Workload Identity は Windows ノードではサポートされていません。

  • Workload Identity では Cloud Run for Anthos on Google Cloud がリクエスト指標を引き続きリリースするための手動設定が必要です。

  • Workload Identity は、クラスタが --disable-default-snat フラグなしで作成された場合に ip-masq-agent をインストールします。

始める前に

作業を始める前に、次のことを確認してください。

次のいずれかの方法で gcloud のデフォルトの設定を指定します。

  • gcloud init。デフォルトの設定全般を確認する場合に使用します。
  • gcloud config。プロジェクト ID、ゾーン、リージョンを個別に設定する場合に使用します。

gcloud init の使用

エラー One of [--zone, --region] must be supplied: Please specify location を受信した場合は、このセクションの内容を実施します。

  1. gcloud init を実行して、次の操作を行います。

    gcloud init

    リモート サーバーで SSH を使用している場合は、--console-only フラグを指定して、コマンドがブラウザを起動しないようにします。

    gcloud init --console-only
  2. 手順に従って gcloud を承認し、Google Cloud アカウントを使用します。
  3. 新しい構成を作成するか、既存の構成を選択します。
  4. Google Cloud プロジェクトを選択します。
  5. デフォルトの Compute Engine ゾーンを選択します。

gcloud config の使用

  • デフォルトのプロジェクト ID を設定します。
    gcloud config set project project-id
  • ゾーンクラスタを使用する場合は、デフォルトのコンピューティング ゾーンを設定します。
    gcloud config set compute/zone compute-zone
  • リージョン クラスタを使用する場合は、デフォルトのコンピューティング リージョンを設定します。
    gcloud config set compute/region compute-region
  • gcloud を最新バージョンに更新します。
    gcloud components update

クラスタで Workload Identity を有効にする

新規または既存のクラスタで Workload Identity を有効にするには、gcloud ツールを使用します。

  1. IAM Service Account Credentials API が有効になっているかを確認します。

    IAM Credentials API を有効にする

  2. Workload Identity を有効にして新しいクラスタを作成するには、次のコマンドを使用します。

    gcloud container clusters create cluster-name \
      --workload-pool=project-id.svc.id.goog
    

    以下を置き換えます。

    • cluster-name: クラスタの名前。
    • project-id: Google Cloud プロジェクトの ID。

    この操作を行うには、プロジェクトに対する container.clusters.create 権限が必要です。

  3. 既存のクラスタで Workload Identity を有効にするには、次のコマンドを使用してクラスタを変更します。

    gcloud container clusters update cluster-name \
      --workload-pool=project-id.svc.id.goog
    

    既存のノードプールは影響を受けません。新しいノードプールはデフォルトで --workload-metadata=GKE_METADATA になります。

    この操作を行うには、クラスタに対する container.clusters.update 権限が必要です。

アプリケーションを Workload Identity に移行する

ご使用の環境に適した移行方法を選択します。ノードプールを移行するか、新しいノードプールを作成して Workload Identity を有効にすることもできます。この機能に対応するようにアプリケーションを変更する必要がある場合は、新しいノードプールの作成をおすすめします。

新しいノードプールをクラスタに追加して Workload Identity を有効にし、そのプールにワークロードを手動で移行します。この操作が成功するのは、Workload Identity がクラスタで有効になっている場合のみです。

gcloud container node-pools create nodepool-name \
  --cluster=cluster-name \
  --workload-metadata=GKE_METADATA

クラスタで Workload Identity が有効になっている場合、--workload-metadata=GCE_METADATA を明示的に指定することで特定のノードプールで選択的に無効にできます。詳しくは、クラスタ メタデータの保護をご覧ください。

オプション 2: ノードプールの変更

既存のノードプールを変更して、GKE_METADATA を有効にします。Workload Identity がクラスタで有効になっている場合のみ、この更新が成功します。更新が成功すると、ノードプールにデプロイされたワークロードの Workload Identity がすぐに有効になります。この変更により、ワークロードは Compute Engine サービス アカウントを使用できなくなるので、慎重にロールアウトする必要があります。

gcloud container node-pools update nodepool-name \
  --cluster=cluster-name \
  --workload-metadata=GKE_METADATA

この操作を行うには、プロジェクトに対する container.nodes.update 権限が必要です。

Google Cloud の認証

このセクションでは、Workload Identity を使用してアプリケーションが Google Cloud で認証を行う方法について説明します。これを行うため、アプリケーションに Kubernetes サービス アカウントを割り当て、Google サービス アカウントとして機能するように構成します。

  1. クラスタと通信を行うように kubectl を構成します。

    gcloud container clusters get-credentials cluster-name
    

    cluster-name を前のステップで作成したクラスタの名前に置き換えます。

    この操作を行うには、プロジェクトに対する container.clusters.get 権限が必要です。

  2. 他のほとんどのリソースと同様に、Kubernetes サービス アカウントは名前空間に存在します。Kubernetes サービス アカウントに使用する名前空間を作成します。

    kubectl create namespace k8s-namespace
    

    この操作を行うには、クラスタ内に名前空間の RBAC を作成する権限が必要です。

  3. アプリケーションで使用する Kubernetes サービス アカウントを作成します。

    kubectl create serviceaccount --namespace k8s-namespace ksa-name
    

    以下を置き換えます。

    • k8s-namespace: 前のステップで作成した Kubernetes 名前空間の名前。
    • ksa-name: Kubernetes サービス アカウントに使用する名前。

    この操作を行うには、名前空間内でサービス アカウントの RBAC を作成する権限が必要です。

    また、デフォルトの名前空間を使用することも、名前空間でデフォルトの Kubernetes サービス アカウントを使用することもできます。

  4. アプリケーションの Google サービス アカウントを作成します。新しいサービス アカウントを作成せずに、既存のサービス アカウントを使用することもできます。サービス アカウントは、クラスタと同じプロジェクトにある必要はありません。組織内の任意の Google サービス アカウントを使用できます。

    gcloud

    gsa-name は、サービス アカウントに選択した名前に置き換えます。

    gcloud iam service-accounts create gsa-name
    

    Config Connector

    クラスタにすでに Config Connector がインストールされている場合、Config Connector 構成を使用して Workload Identity を有効にした新しい GKE クラスタを作成できます。

    注: この手順には Config Connector が必要です。Config Connector をクラスタにインストールするには、インストール手順に従ってください。

    apiVersion: iam.cnrm.cloud.google.com/v1beta1
    kind: IAMServiceAccount
    metadata:
      name: [GSA_NAME]
    spec:
      displayName: [GSA_NAME]
    このマニフェストをデプロイするには、service-account.yaml という名前でマシンにダウンロードします。gsa-name は、サービス アカウントに選択した名前に置き換えます。次に、kubectl を使用してマニフェストを適用します。

    kubectl apply -f service-account.yaml

    この操作を行うには、プロジェクトに対する iam.serviceAccounts.create 権限が必要です。

    Google サービス アカウントから Google Cloud APIs へのアクセスを承認する方法については、サービス アカウントについてをご覧ください。

  5. Kubernetes サービス アカウントが Google サービス アカウントになり代われるよう、この 2 つの間の IAM ポリシー バインディングを作成します。このバインドでは、Kubernetes サービス アカウントが Google サービス アカウントとして機能します。

    gcloud

    gcloud iam service-accounts add-iam-policy-binding \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:project-id.svc.id.goog[k8s-namespace/ksa-name]" \
      gsa-name@project-id.iam.gserviceaccount.com
    

    Config Connector

    注: この手順には Config Connector が必要です。Config Connector をクラスタにインストールするには、インストール手順に従ってください。

    apiVersion: iam.cnrm.cloud.google.com/v1beta1
    kind: IAMPolicy
    metadata:
      name: iampolicy-workload-identity-sample
    spec:
      resourceRef:
        apiVersion: iam.cnrm.cloud.google.com/v1beta1
        kind: IAMServiceAccount
        name: [GSA_NAME]
      bindings:
        - role: roles/iam.workloadIdentityUser
          members:
            - serviceAccount:[PROJECT_ID].svc.id.goog[[K8S_NAMESPACE]/[KSA_NAME]]
    このマニフェストをデプロイするには、policy-binding.yaml という名前でマシンにダウンロードします。gsa-nameproject-idk8s-namespaceksa-name を、実際の環境での値に置き換えます。次のコマンドを実行します。

    kubectl apply -f policy-binding.yaml

    この操作を行うには、プロジェクトに対する iam.serviceAccounts.setIamPolicy 権限が必要です。

  6. Google サービス アカウントのメールアドレスを使用して、iam.gke.io/gcp-service-account=gsa-name@project-id アノテーションを Kubernetes サービス アカウントに追加します。

    kubectl

    kubectl annotate serviceaccount \
      --namespace k8s-namespace \
      ksa-name \
      iam.gke.io/gcp-service-account=gsa-name@project-id.iam.gserviceaccount.com
    

    yaml

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      annotations:
        iam.gke.io/gcp-service-account: gsa-name@project-id.iam.gserviceaccount.com
      name: ksa-name
      namespace: k8s-namespace
    

    この操作を行うには、Kubernetes サービス アカウントに RBAC を編集する権限が必要です。

  7. サービス アカウントが正しく構成されていることを確認します。それには、Kubernetes サービス アカウントを使って cloud-sdk コンテナ イメージを実行する Pod を作成し、インタラクティブなセッションでその Pod に接続します。

    kubectl

    kubectl run -it \
      --image google/cloud-sdk:slim \
      --serviceaccount ksa-name \
      --namespace k8s-namespace \
      workload-identity-test
    

    yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: workload-identity-test
      namespace: k8s-namespace
    spec:
      containers:
      - image: google/cloud-sdk:slim
        name: workload-identity-test
        command: ["sleep","infinity"]
      serviceAccountName: ksa-name
    

    google/cloud-sdk イメージには gcloud コマンドライン ツールが含まれています。このツールを使用すると、Google Cloud API を簡単に利用できます。イメージのダウンロードに時間がかかる場合があります。

    この操作を行うには、名前空間内で Pod 作成の RBAC 権限が必要です。

    これで、作成したポッド内でインタラクティブ シェルに接続できました。Pod 内で次のコマンドを実行します。

    gcloud auth list
    

    サービス アカウントが正しく構成されている場合、Google サービス アカウントのメールアドレスがアクティブな唯一の ID になります。デフォルトでは、Google Cloud API を呼び出すときに Google サービス アカウントの権限が使用されます。

コードから Workload Identity を使用する

コードで Google Cloud サービスに対する認証を行うプロセスは、Compute Engine のメタデータ サーバーを使用した認証と同じです。Workload Identity を使用すると、インスタンス メタデータ サーバーに対するリクエストが GKE メタデータ サーバーにルーティングされます。インスタンス メタデータ サーバーを使用して認証する既存のコードは(Google Cloud クライアント ライブラリを使用したコード同様)、変更せずにそのまま使用できます。

GKE メタデータ サーバーについて

GKE メタデータ サーバーは、Kubernetes で使用するために設計された新しいメタデータ サーバーです。クラスタノードごとに 1 つの Pod を使用して、daemonset として実行されます。メタデータ サーバーは、Pod がその役割を果たすように構成された Google サービス アカウントのトークンを取得するための GET /computeMetadata/v1/instance/service-accounts/default/token などのリクエストも含め、http://metadata.google.internal(169.254.169.254:80)への HTTP リクエストをインターセプトします。メタデータ サーバーへのトラフィックは必ず、Pod をホストする VM インスタンスに向かいます。

GKE メタデータ サーバーは、Kubernetes ワークロードとの関連性があり、安全な Compute Engine メタデータ サーバー エンドポイントのサブセットのみを実装します。

  • /computeMetadata/v1/instance/attributes/cluster-location
  • /computeMetadata/v1/instance/attributes/cluster-name
  • /computeMetadata/v1/instance/attributes/cluster-uid
  • /computeMetadata/v1/instance/hostname
  • /computeMetadata/v1/instance/id
  • /computeMetadata/v1/project/numeric-project-id
  • /computeMetadata/v1/project/project-id
  • /computeMetadata/v1/instance/service-accounts
  • /computeMetadata/v1/instance/service-accounts/default
  • /computeMetadata/v1/instance/service-accounts/default/aliases
  • /computeMetadata/v1/instance/service-accounts/default/email
  • /computeMetadata/v1/instance/service-accounts/default/identity
  • /computeMetadata/v1/instance/service-accounts/default/identity?audience=audience
  • /computeMetadata/v1/instance/service-accounts/default/scopes
  • /computeMetadata/v1/instance/service-accounts/default/token
  • /computeMetadata/v1/instance/service-accounts/default/token?scopes=comma-separated-list-of-scopes

アクセス権の取り消し

  1. IAM を使用して Google サービス アカウントへのアクセス権を取り消します。

    gcloud

    gcloud iam service-accounts remove-iam-policy-binding \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:project-id.svc.id.goog[k8s-namespace/ksa-name]" \
      gsa-name@gsa-project-id.iam.gserviceaccount.com
    

    以下を置き換えます。

    • project-id: GKE クラスタのプロジェクト ID コンテナ。
    • k8s-namespace: Kubernetes サービス アカウントが配置されている Kubernetes 名前空間の名前。
    • ksa-name: アクセス権が取り消される Kubernetes サービス アカウントの名前。
    • gsa-name: Google サービス アカウントの名前。 
    • gsa-project-id: Google サービス アカウントを含むプロジェクト ID。

    Config Connector

    Config Connector を使用してサービス アカウントを作成した場合は、kubectl を使用してサービス アカウントを削除します。

    kubectl delete -f service-account.yaml
    

    この操作を実行するには、サービス アカウントに対する iam.serviceAccounts.setIamPolicy 権限が必要です。

    キャッシュ内のトークンの有効期限は 30 分です。キャッシュ内のトークンが期限切れになっているかどうかは、次のコマンドで確認できます。

    gcloud auth list
    

    このコマンドの出力に gsa-name@project-id.iam.gserviceaccount.com が含まれない場合は、キャッシュ内のトークンはすでに期限切れです。

  2. Kubernetes サービス アカウントからアノテーションを削除します。IAM によってアクセス権が取り消されたため、このステップは省略可能です。

    kubectl annotate serviceaccount \
      --namespace k8s-namespace \
      ksa-name \
      iam.gke.io/gcp-service-account-
    

トラブルシューティング

アプリケーションが Google Cloud で認証できない場合は、次の設定が正しく構成されていることを確認してください。

  1. GKE クラスタを含むプロジェクトで IAM Service Account Credentials API が有効になっているかを確認します。

    IAM Credentials API を有効にする

  2. Workload Identity がクラスタで有効になっていることを確かにするには、ワークロード ID プールが設定されていることを確認します。

    gcloud container clusters describe cluster-name \
      --format="value(workloadIdentityConfig.workloadPool)"
    
  3. GKE メタデータ サーバー(GKE_METADATA)が、アプリケーションが実行されているノードプールで構成されていることを確認します。

    gcloud container node-pools describe node-pool-name \
      --cluster=cluster-name \
      --format="value(config.workloadMetadataConfig.mode)"
    
  4. Kubernetes サービス アカウントに正しくアノテーションが付けられていることを確認します。

    kubectl describe serviceaccount \
      --namespace k8s-namespace \
      ksa-name
    

    アノテーションの形式は次のとおりです。

    iam.gke.io/gcp-service-account: gsa-name@project-id.iam.gserviceaccount.com
    
  5. Google サービス アカウントが正しく構成されていることを確認します。

    gcloud iam service-accounts get-iam-policy \
      gsa-name@project-id.iam.gserviceaccount.com
    

    次の形式のバインディングがあることを確認します。

    - members:
      - serviceAccount:project-id.svc.id.goog[k8s-namespace/ksa-name]
      role: roles/iam.workloadIdentityUser
    
  6. クラスタ ネットワーク ポリシーを導入している場合は、ポート 988 で 127.0.0.1/32 への Egress が許可されていることを確認します。

    kubectl describe networkpolicy network-policy-name
    

クラスタでの Workload Identity の無効化

  1. 各ノードプールで Workload Identity を無効にします。

    gcloud container node-pools update nodepool-name \
      --cluster=cluster-name \
      --workload-metadata=GCE_METADATA
    

    クラスタ内の各ノードプールに対してこのコマンドを繰り返します。

  2. クラスタで Workload Identity を無効にします。

    gcloud container clusters update cluster-name \
      --disable-workload-identity
    

    この操作を行うには、クラスタに対する container.clusters.update 権限が必要です。

組織内での Workload Identity の無効化

セキュリティの観点から、Workload Identity では GKE が、Kubernetes サービス アカウント ID を Google Cloud リソースに対して認証して承認できるものとして表明できるようになっています。サービス アカウントの作成を無効化したり、サービス アカウント キーの作成を無効化したりするなどしてワークロードを Google Cloud リソースから分離するための措置を講じた管理者は、組織で Workload Identity を無効化することも検討できます。

組織の Workload Identity を無効にするこれらの手順をご覧ください。

Workload Identity に代わる方法

GKE から Cloud API にアクセスするには、2 つの方法があります。Workload Identity のリリースに伴い、調整が必要になるため、これらのアプローチはおすすめしません。

  1. サービス アカウント キーをエクスポートして Kubernetes Secret として保存します。Google サービス アカウント キーは 10 年後に有効期限が切れ、手動でローテーションされます。サービス アカウント キーをエクスポートすると、セキュリティ侵害を受けた場合、それが検出されなければ侵害の範囲が拡大する可能性があります。

  2. ノードの Compute Engine サービス アカウントを使用します。プロジェクト内の任意の IAM サービス アカウントとしてノードプールを実行できます。ノードプールの作成時にサービス アカウントを指定しなければ、GKE はプロジェクトのデフォルトの Compute Engine サービス アカウントを使用します。デフォルトの Compute Engine サービス アカウントは、そのノードにデプロイされているすべてのワークロードで共有されます。そのため、権限が過剰にプロビジョニングされることがあります。

次のステップ