Workload Identity の使用

このドキュメントでは、Google Kubernetes Engine(GKE)クラスタで Workload Identity を有効にして構成する方法について説明します。Workload Identity を使用すると、GKE クラスタ内のワークロードが Identity and Access Management(IAM)サービス アカウントの権限を借用し、Google Cloud サービスにアクセスできるようになります。

Workload Identity の仕組みの詳細については、Workload Identity をご覧ください。

制限事項

  • GKE は、Google Cloud プロジェクトごとに、PROJECT_ID.svc.id.goog の形式で固定 Workload Identity プールを作成します。

  • Workload Identity は、メタデータ隠蔽機能に代わるものです。メタデータ隠蔽機能で保護された機密メタデータは Workload Identity でも保護されます。

  • GKE がノードプールで GKE メタデータ サーバーを有効にすると、Pod は Compute Engine メタデータ サーバーにアクセスできなくなります。代わりに、GKE メタデータ サーバーは、ホスト ネットワークで実行されている Pod を除き、これらの Pod からメタデータ エンドポイントへのリクエストをインターセプトします。

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

  • GKE メタデータ サーバーが新しく作成された Pod でリクエストの承認を開始するまで、数秒かかります。したがって、Pod の有効期間の最初の数秒以内に Workload Identity を使用して認証を試みると、失敗する可能性があります。この問題は、呼び出しを再試行することで解決します。詳細については、トラブルシューティングのセクションをご覧ください。

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

  • Workload Identity では、リクエスト指標の公開を継続するために、Cloud Run for Anthos の手動設定が必要です。

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

  • Workload Identity は、メモリの問題を回避するため、ノードごとに GKE メタデータ サーバーへの接続を 200 に制限します。ノードがこの上限を超えると、タイムアウトが発生することがあります。

始める前に

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

次のいずれかの方法で 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 ゾーン、リージョン クラスタまたは Autopilot クラスタの場合はデフォルトの Compute Engine リージョンを選択します。

gcloud config の使用

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

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

新規または既存の GKE Standard クラスタで Workload Identity を有効にするには、gcloud ツールを使用します。GKE Autopilot クラスタでは、Workload Identity がデフォルトで有効になっています。

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

    gcloud container clusters update CLUSTER_NAME \
        --workload-pool=PROJECT_ID.svc.id.goog
    

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

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

gcloud container node-pools update NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --workload-metadata=GKE_METADATA

Google Cloud の認証

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

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

    gcloud container clusters get-credentials CLUSTER_NAME
    

    CLUSTER_NAME は、前のステップで作成したクラスタの名前に置き換えます。

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

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

    kubectl create serviceaccount KSA_NAME \
        --namespace K8S_NAMESPACE
    

    次のように置き換えます。

    • KSA_NAME: 新しい Kubernetes サービス アカウントの名前。
    • K8S_NAMESPACE: 前のステップで作成した Kubernetes の名前空間の名前。
  4. Kubernetes サービス アカウントを使用するようにアプリケーションを構成します。

    spec:
      serviceAccountName: KSA_NAME
    
  5. アプリケーションの IAM サービス アカウントを作成するか、既存の IAM サービス アカウントを使用します。組織内の任意のプロジェクトで、任意の IAM サービス アカウントを使用できます。Config Connector の場合は、選択したサービス アカウントに IAMServiceAccount オブジェクトを適用します。

    gcloud

    gcloud ツールを使用して新しい Google サービス アカウントを作成するには、次のコマンドを実行します。

    gcloud iam service-accounts create GSA_NAME
    

    GSA_NAME は、新しい IAM Cloud サービス アカウントの名前に置き換えます。

    Config Connector

    Config Connector で新規または既存の IAM サービス アカウントを使用するには、次の構成ファイルを適用します。

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

    apiVersion: iam.cnrm.cloud.google.com/v1beta1
    kind: IAMServiceAccount
    metadata:
      name: [GSA_NAME]
    spec:
      displayName: [GSA_NAME]
    このマニフェストをデプロイするには、service-account.yaml という名前でマシンにダウンロードします。

    kubectl を使用してマニフェストを適用します。

    kubectl apply -f service-account.yaml
    

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

  6. Google サービス アカウントに必要な IAM ロールがあることを確認します。次のコマンドを使用して、追加のロールを付与できます。

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member "serviceAccount:GSA_NAME@PROJECT_ID.iam.gserviceaccount.com" \
        --role "ROLE_NAME"
    

    次のように置き換えます。

    • PROJECT_ID: Google Cloud プロジェクト ID。
    • GSA_NAME: Google サービス アカウントの名前。
    • ROLE_NAME: roles/spanner.viewer など、サービス アカウントに割り当てる IAM ロール。
  7. Kubernetes サービス アカウントが Google サービス アカウントの権限を借用できるように、この 2 つの間の IAM ポリシー バインディングを作成します。このバインドでは、Kubernetes サービス アカウントが IAM サービス アカウントとして機能します。

    gcloud

    gcloud iam service-accounts add-iam-policy-binding GSA_NAME@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/iam.workloadIdentityUser \
        --member "serviceAccount:PROJECT_ID.svc.id.goog[K8S_NAMESPACE/KSA_NAME]"
    

    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
    
  8. IAM サービス アカウントのメールアドレスを使用して、iam.gke.io/gcp-service-account=GSA_NAME@PROJECT_ID アノテーションを Kubernetes サービス アカウントに追加します。

    kubectl

    kubectl annotate serviceaccount KSA_NAME \
        --namespace K8S_NAMESPACE \
        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
    
  9. サービス アカウントが正しく構成されていることを確認します。Kubernetes サービス アカウントを使用して、OS 固有のコンテナ イメージを実行する Pod を作成し、インタラクティブなセッションで Pod に接続します。

    Linux ノードの場合

    1. Kubernetes サービス アカウントを使用して、cloud-sdk コンテナ イメージを実行する Pod を作成します。

      次の構成を wi-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
      

      Pod を作成します。

      kubectl apply -f wi-test.yaml
      

      Pod でインタラクティブ セッションを開きます。

      kubectl exec -it workload-identity-test \
          --namespace K8S_NAMESPACE -- /bin/bash
      

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

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

      curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/
      

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

    Windows Server ノードの場合

    1. Kubernetes サービス アカウントを使用して、servercore コンテナ イメージを実行する Pod を作成します。

      apiVersion: v1
      kind: Pod
      metadata:
        name: workload-identity-test
        namespace: K8S_NAMESPACE
      spec:
        containers:
        - image: IMAGE_NAME
          name: workload-identity-test
          command: ["powershell.exe", "sleep", "3600"]
        serviceAccountName: KSA_NAME
        nodeSelector:
          kubernetes.io/os: windows
          cloud.google.com/gke-os-distribution: windows_ltsc
      

      IMAGE_NAME を、次のいずれかのコンテナ サーバーコア イメージの値に置き換えます。

      Windows Server ノードイメージ コンテナ servercore イメージ
      WINDOWS_LTSC
      WINDOWS_LTSC_CONTAINERD
      mcr.microsoft.com/windows/servercore:ltsc2019
      WINDOWS_SAC
      WINDOWS_SAC_CONTAINERD
      GKE ノード バージョンと Windows SAC バージョンの間のバージョン マッピングを確認します。Windows Server バージョン 1909 の場合は mcr.microsoft.com/windows/servercore:1909 を指定し、それ以外の場合は mcr.microsoft.com/windows/servercore:20H2 を指定します。

      Pod でインタラクティブ セッションを開きます。

      kubectl exec -it workload-identity-test \
          --namespace K8S_NAMESPACE -- powershell
      
    2. これで、作成した Pod 内でインタラクティブ シェルに接続できました。Pod 内で次の powershell コマンドを実行します。

      Invoke-WebRequest  -Headers @{"Metadata-Flavor"="Google"} -Uri  http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email  -UseBasicParsing
      

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

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

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

アクセス権の取り消し

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

    gcloud

    gcloud iam service-accounts remove-iam-policy-binding GSA_NAME@GSA_PROJECT_ID.iam.gserviceaccount.com \
        --role roles/iam.workloadIdentityUser \
        --member "serviceAccount:PROJECT_ID.svc.id.goog[K8S_NAMESPACE/KSA_NAME]"
    

    次のように置き換えます。

    • PROJECT_ID: GKE クラスタのプロジェクト ID。
    • K8S_NAMESPACE: Kubernetes サービス アカウントが配置されている Kubernetes 名前空間の名前。
    • KSA_NAME: アクセス権が取り消される Kubernetes サービス アカウントの名前。
    • GSA_NAME: IAM サービス アカウントの名前。
    • GSA_PROJECT_ID: IAM サービス アカウントのプロジェクト 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 KSA_NAME \
        --namespace K8S_NAMESPACE iam.gke.io/gcp-service-account-
    

トラブルシューティング

Pod が Google Cloud に対して認証できない

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

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

    IAM Credentials API を有効にする

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

    gcloud container clusters describe CLUSTER_NAME \
        --format="value(workloadIdentityConfig.workloadPool)"
    

    gcloud のデフォルト ゾーンまたはデフォルト リージョンをまだ指定していない場合は、このコマンドの実行時に --region フラグまたは --zone フラグも指定する必要があります。

  3. GKE メタデータ サーバー(GKE_METADATA)が、アプリケーションが実行されているノードプールで構成されていることを確認します。

    gcloud container node-pools describe NODEPOOL_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. IAM サービス アカウントが正しく構成されていることを確認します。

    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. クラスタ ネットワーク ポリシーを導入している場合は、1.21.0-gke.1000 より前のバージョンの GKE を実行しているクラスタのポート 988 で、127.0.0.1/32 への下り(外向き)が許可されていることを確認します。また、GKE バージョン 1.21.0-gke.1000 以降を実行しているクラスタのポート 988 で、169.254.169.252/32 への下り(外向き)が許可されていることを確認します。

    kubectl describe networkpolicy NETWORK_POLICY_NAME
    

Pod の起動時にタイムアウト エラーが発生する

GKE メタデータ サーバーが新しく作成された Pod でリクエストの受信を開始できるようになるまでに数秒かかります。したがって、Pod の有効期間の最初の数秒以内に Workload Identity を使用して認証を試みると、短いタイムアウトが構成されているアプリケーションと Google Cloud クライアント ライブラリで失敗する可能性があります。

タイムアウト エラーが発生した場合は、アプリケーション コードを変更して数秒待ってから再試行してください。また、Pod のメインコンテナを実行する前に、GKE メタデータ サーバーの準備が完了するまで待機する initContainer をデプロイすることもできます。

サンプルの initContainer を備えた Pod を次に示します。

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-initcontainer
spec:
  serviceAccountName: KSA_NAME
  initContainers:
  - image:  gcr.io/google.com/cloudsdktool/cloud-sdk:326.0.0-alpine
    name: workload-identity-initcontainer
    command:
    - '/bin/bash'
    - '-c'
    - |
      curl -s -H 'Metadata-Flavor: Google' 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token' --retry 30 --retry-connrefused --retry-max-time 30 > /dev/null || exit 1
  containers:
  - image: gcr.io/your-project/your-image
    name: your-main-application-container

コントロール プレーンが使用できないため Workload Identity が失敗する

クラスタ コントロール プレーンが使用できない場合、メタデータ サーバーは Workload Identity を返すことができません。メタデータ サーバーを呼び出すと、ステータス コード 500 が返されます。

ログ エクスプローラでは、ログエントリは次のようになります。

dial tcp 35.232.136.58:443: connect: connection refused

これにより、予想どおり、Workload Identity が利用できなくなることがあります。

IP のローテーション、コントロール プレーン VM のアップグレード、クラスタまたはノードプールのサイズ変更などのクラスタ メンテナンス時に、ゾーンクラスタでコントロール プレーンが使用できない場合があります。コントロール プレーンの可用性については、リージョンまたはゾーンのコントロール プレーンの選択をご覧ください。リージョン クラスタに切り替えることで、この問題がなくなります。

Workload Identity が失敗する

なんらかの理由で GKE メタデータ サーバーがブロックされていると、Workload Identity は失敗します。

Istio を使用している場合は、Workload Identity を使用するすべてのワークロードに次のアプリケーション レベルのアノテーションを追加する必要があります。

"traffic.sidecar.istio.io/excludeOutboundIPRanges=169.254.169.254/32"

global.proxy.excludeIPRanges Istio ConfigMap キーを変更して同じ処理を行うこともできます。

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

Workload Identity は GKE Standard クラスタでのみ無効にできます。

  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 を無効にするこれらの手順をご覧ください。

次のステップ