Workload Identityは、一般にはソフトウェアが認証やアクセス制御に使うIDを指します。本記事で主に扱うのは、サービスアカウントキー(JSONの鍵ファイル)を配らずに、GKEのPodやAWS・GitHub Actionsで動くプログラムへ有効期間の短いトークンを渡すGoogle Cloudの仕組みです。Google Cloudでは2つの機能がこの名前で呼ばれます。GKEのPod向けの「Workload Identity Federation for GKE」(旧称 Workload Identity)と、Google Cloudの外で動くワークロード向けの「Workload Identity 連携」です。Microsoftには、アプリケーションやサービスプリンシパル、マネージドIDを扱うMicrosoft Entra Workload IDがあります。
以下、3つの区別、トークン交換の流れ、設定コマンド、Podが認証できないときの確認順、採用前の制約を、各社の公式ドキュメント(2026年10月17日時点)に沿って説明します。
まとめ
- Workload Identityは、鍵ファイルの代わりにKubernetesのServiceAccountトークンや外部IdPのトークンを、Google CloudのSecurity Token Service(STS)で短命の連携アクセストークンへ交換する仕組みです。GKEメタデータサーバーが返すアクセストークンの有効期間は既定で1時間ですが、外部連携では認証方式や元のトークンによって異なります。
- GKEの現行の推奨は、Kubernetes ServiceAccount(KSA)に
principal://の識別子で直接IAMロールを付与する方式です。IAMサービスアカウントを借用する従来方式は、Cloud Storageの署名付きURL生成など直接付与が使えない場面に限ります。 - Autopilotでは常に有効、Standardではクラスタの
--workload-poolとノードプールの--workload-metadata=GKE_METADATAの両方が必要です。 - 同じプロジェクトの別クラスタで同じNamespace名・KSA名を使うと、IAMは同一IDとして扱います。信頼できないチームのクラスタは別プロジェクトに置きます。
- 料金は追加でかかりません。2024年5月3日以降に作成された組織では、サービスアカウントキーの作成が既定で禁止されています。
Workload Identityが指す3つの機能
検索結果に並ぶ「Workload Identity」は、対象のワークロードと信頼するIdPが違う3つの機能を指しています。読んでいる手順がどれのものかを最初に確認しないと、設定の主語(KSAか、プールか、Entraのアプリか)を取り違えます。
| 名称 | 対象のワークロード | 信頼するIdP | 権限を付ける相手 |
|---|---|---|---|
| Workload Identity Federation for GKE | GKEのPod | GKEクラスタ(Googleが管理) | KSA または IAMサービスアカウント |
| Workload Identity 連携 | AWS・Azure・GitHub Actions・オンプレミス | AWS・OIDC・SAML・X.509証明書 | プールのプリンシパル |
| Microsoft Entra Workload ID | Azure・AKS・外部のアプリ | 連携時はGitHub・Kubernetesなどの外部IdP | アプリ・マネージドID |
GKE向けの機能も内部では外部連携と同じ仕組みに乗っています。GKEの概念ドキュメントは、GKEではGoogle CloudがWorkload Identityプールとプロバイダを管理するため外部IdPが不要だと説明しています。プール名は PROJECT_ID.svc.id.goog に固定で、名前は変更できません。なお、Google Cloudコンソールのクラスタ設定画面では、今も「Workload Identity」という表記が使われています。
人間のユーザー(従業員や委託先)が外部IdPのアカウントでGoogle Cloudコンソールに入る機能は、Workforce Identity連携という別機能です。
鍵ファイルを置かずに認証できる仕組み
Google Cloudの連携では、外部の認証情報をGoogleの短命トークンに交換します。Microsoft Entraの連携では、外部IdPのトークンをMicrosoftのアクセストークンに交換します。外部連携は OAuth 2.0 のトークン交換の仕様に準拠しています。長期間有効な秘密をワークロードに持たせないので、漏えいしても被害の時間が限られます。
GKEのPodでトークンが発行される流れ
- アプリのクライアントライブラリ(ADC)が、メタデータサーバー
169.254.169.254にアクセストークンを要求します。 - GKEメタデータサーバー(LinuxノードではDaemonSet、Windowsノードではネイティブサービス)がこの要求を横取りし、Kubernetes APIサーバーにPodのServiceAccountトークン(JWT)を要求します。
- GKEメタデータサーバーがSTSでJWTを連携アクセストークンに交換し、Podへ返します。
返るトークンの有効期間は既定で1時間(3,600秒)です。GKEメタデータサーバーはトークンをキャッシュするため、残り時間が短いトークンが返ることがあります。Cloudクライアントライブラリは期限まで3分45秒を切ると更新するので、自前でAPIを叩くコードは同じ判定を入れてください。メタデータサーバー経由で認証する既存コードは、改修せずにそのまま動きます。
外部ワークロードが使う認証情報構成ファイル
AWSやオンプレミスのワークロードは、「認証情報構成ファイル」をADCに読ませてトークン交換を行います。gcloud CLI 589.0.0 で、AWS用の構成ファイルをオフラインで生成した結果が次の内容です(プロジェクト番号は架空の値)。
gcloud iam workload-identity-pools create-cred-config \
projects/123456789012/locations/global/workloadIdentityPools/aws-pool/providers/aws-provider \
--aws --enable-imdsv2 --output-file=aws.json
{
"universe_domain": "googleapis.com",
"type": "external_account",
"audience": "//iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/aws-pool/providers/aws-provider",
"subject_token_type": "urn:ietf:params:aws:token-type:aws4_request",
"token_url": "https://sts.googleapis.com/v1/token",
"credential_source": {
"environment_id": "aws1",
"region_url": "http://169.254.169.254/latest/meta-data/placement/availability-zone",
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials",
"regional_cred_verification_url": "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
"imdsv2_session_token_url": "http://169.254.169.254/latest/api/token"
},
"token_info_url": "https://sts.googleapis.com/v1/introspect"
}
ファイルにあるのは、トークンの取得元(AWSのインスタンスメタデータ)と交換先(sts.googleapis.com)だけで、秘密は含まれていません。ファイル単体では認証できず、AWS側の認証情報が別に必要になる点が、鍵JSONとの決定的な違いです。--service-account を付けて生成すると service_account_impersonation_url が設定され、交換後にさらにIAMサービスアカウントのトークンを取りに行く「借用」の動きになります。このバージョンの生成結果では、代わりに token_info_url が出力されなくなります。
GKEでWorkload Identityを有効にする手順
手順はGKEの設定ガイドに沿っています。事前にIAM Service Account Credentials APIを有効にし、作業者に roles/container.admin と roles/iam.serviceAccountAdmin を付けておきます。後述のバケットへのロール付与を実行する作業者には、対象バケットの storage.buckets.getIamPolicy と storage.buckets.setIamPolicy も必要です。
Standardクラスタとノードプールの有効化設定
Autopilotでは常に有効なので、この節は飛ばして次の節へ進みます。Standardでは、クラスタ側の設定に加えて、ノードプールでGKEメタデータサーバーを使う設定が要ります。
# クラスタで有効化(既存ノードプールは変わらず、新しいノードプールから有効になる)
gcloud container clusters update CLUSTER_NAME \
--location=LOCATION \
--workload-pool=PROJECT_ID.svc.id.goog
# 既存ノードプールを切り替える
gcloud container node-pools update NODEPOOL_NAME \
--cluster=CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--workload-metadata=GKE_METADATA
既存ノードプールを切り替えると、その上のPodはすぐにノードのサービスアカウントを使えなくなり、動いているワークロードが止まることがあります。アプリの改修も伴うなら、公式のベストプラクティスどおり新しいノードプールを作って移すのが安全です。特定のノードプールだけ外したいときは --workload-metadata=GCE_METADATA を指定します。
KSAへの直接ロール付与(推奨方式)
現行の推奨は、IAMサービスアカウントを作らずに、KSAそのものをIAMのプリンシパルとして扱う方式です。識別子にはプロジェクトIDではなく数字のプロジェクト番号を入れます。
# 操作対象クラスタの認証情報とコンテキストを設定
gcloud container clusters get-credentials CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION --project=PROJECT_ID
kubectl create namespace NAMESPACE
kubectl create serviceaccount KSA_NAME --namespace NAMESPACE
gcloud storage buckets add-iam-policy-binding gs://BUCKET \
--role=roles/storage.objectViewer \
--member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/NAMESPACE/sa/KSA_NAME \
--condition=None
Podは spec.serviceAccountName でこのKSAを指定するだけです。Standardでは nodeSelector に iam.gke.io/gke-metadata-server-enabled: "true" を足して、有効なノードプールに載せます(Autopilotはこの指定を拒否します)。権限の範囲は識別子で変えられます。principalSet://.../namespace/NAMESPACE ならNamespace内の全Pod、kubernetes.cluster/... なら特定クラスタの全Podが対象です。
IAMサービスアカウントの借用設定(従来方式)
直接付与が使えない場面では、KSAにIAMサービスアカウントを借用させます。まずIAMサービスアカウントを用意し、アクセス先のリソースに必要なロールをそのアカウントへ付与します。そのうえで、次のコマンドでKSAへの借用許可とKSAのアノテーションを設定します。この2つは両方必要です。
gcloud iam service-accounts add-iam-policy-binding IAM_SA_NAME@IAM_SA_PROJECT_ID.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]"
kubectl annotate serviceaccount KSA_NAME \
--namespace NAMESPACE \
iam.gke.io/gcp-service-account=IAM_SA_NAME@IAM_SA_PROJECT_ID.iam.gserviceaccount.com
アノテーション iam.gke.io/gcp-service-account を付ける先はPodではなくKubernetesのServiceAccountです。ネット上の解説にはPodのmetadataに書く例が残っていますが、公式の手順は kubectl annotate serviceaccount です。
直接付与と借用の選び方
既定は直接付与にして、次の条件に当たる操作だけを借用へ回します。直接付与の連携トークンにはサービスごとの制限があり、ID連携の対応プロダクトと制限事項に一覧があります。
| やりたいこと | 直接付与 | 理由・公式の記述 |
|---|---|---|
| Cloud Storageの読み書き | 可 | 均一バケットレベルのアクセスのバケットに限る |
| 署名付きURLの生成 | 不可 | 連携IDは署名付きURLを生成できない |
| Cloud Runサービスの呼び出し | 不可 | 直接アクセス非対応。借用を使う |
| 別のVPC SC境界のリソース | 条件付きで可 | GKEプリンシパルを使う境界ルールはプレビュー対応 |
| Podから別クラスタへkubectl | 不可 | 借用を使う(自前のプールなら対象外) |
借用で付与する roles/iam.workloadIdentityUser の中身は、iam.serviceAccounts.get・getAccessToken・getOpenIdToken・list の4権限です。このロールはサービスアカウントそのものに付けるもので、プロジェクト全体に付けると、そのプロジェクトの全サービスアカウントを借用できてしまいます。VPC Service Controlsの境界の考え方はVPC Service Controlsの解説記事で扱っています。
外部ワークロードからGoogle Cloudへ連携する設定
AWS・Azure・GitHub Actionsなど、Google Cloudの外で動くワークロードは、自分でWorkload Identityプールとプロバイダを作ります。Workload Identity 連携の概要は、開発・ステージング・本番など環境ごとにプールを分けることを勧めています。
GitHub Actions向けのプール・プロバイダ・属性条件の設定
プロバイダでは、外部トークンのクレームをGoogle側の属性へ写す「属性マッピング」と、受け入れるトークンを絞る「属性条件」を設定します。google.subject は必須で、127バイト以内の一意の値にします。マルチバイト文字を含む場合は、文字数ではなくバイト数で確認します。カスタム属性は50個まで定義できます。
gcloud iam workload-identity-pools create github-pool \
--location=global --display-name="GitHub Actions"
gcloud iam workload-identity-pools providers create-oidc github-provider \
--location=global \
--workload-identity-pool=github-pool \
--issuer-uri="https://token.actions.githubusercontent.com" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository_owner_id=assertion.repository_owner_id" \
--attribute-condition="assertion.repository_owner_id == '1234567'"
GitHub・GitLab SaaS・HCP Terraformは全組織で同じ発行者URLを使うため、属性条件で自分の組織に絞らないと、他人のリポジトリのトークンもプールを通ってしまいます。条件には repository_owner のような名前ではなく、数字の repository_owner_id を使います。デプロイパイプライン向けの公式手順は、組織やリポジトリを削除すると第三者が同じ名前を取得できるため、再利用されない数字のIDを使うよう求めています。
ワークフロー側は permissions に id-token: write を付け、google-github-actions/auth@v3(2026年10月時点の最新メジャー)に workload_identity_provider を渡します。入力の詳細と鍵JSONからの移行はgoogle-github-actions/authの設定記事にまとめています。
AWS EC2のIAMロールを使う属性マッピングと認証設定
AWSのプロバイダは、GetCallerIdentityの応答(account・arn・userid)を属性マッピングの元にします。EC2にアタッチしたIAMロール単位で権限を付けたいなら、マッピングに attribute.aws_role=assertion.arn.extract('assumed-role/{role_name}/') を足し、principalSet://.../attribute.aws_role/ROLE_NAME にロールを付与します。ワークロード側は、前の章の create-cred-config --aws --enable-imdsv2 で作った構成ファイルを環境変数 GOOGLE_APPLICATION_CREDENTIALS で指定します。外部IDへロールを付けるときも、識別子にはプロジェクト番号を使います。
Podが認証できないときの確認順
症状から原因を当てるより、上流から順に潰すほうが早く終わります。順番はGKEの認証トラブルシューティングに沿っています。
- クラスタにプールが設定されているか:
gcloud container clusters describe CLUSTER_NAME --format="value(workloadIdentityConfig.workloadPool)" - Podが載るノードプールが
GKE_METADATAか:gcloud container node-pools describe NODEPOOL_NAME --cluster=CLUSTER_NAME --format="value(config.workloadMetadataConfig.mode)" - ネットワークポリシーで、
169.254.169.252/32のポート988への下りを許可しているか(GKE Dataplane V2では169.254.169.254/32のポート80)。 - VPCの下りを既定拒否にしている場合、
sts.googleapis.comの443番へ出られるか。塞がれていると504 Gateway Timeoutやcontext deadline exceededになります。 - 許可ポリシーに
principal://の付与があるか、借用方式ならアノテーションとroles/iam.workloadIdentityUserの両方があるか。
設定が正しいのに失敗する場合は、次のエラー文で切り分けます。
Permission 'iam.serviceAccounts.getAccessToken' denied:設定変更直後なら、ロール付与の伝播待ちが考えられます。伝播は通常約2分ですが、7分以上かかることもあります。IAMとPodを同時に作るパイプラインで起きやすく、起動直後のリトライか待機で解消します。Invalid form of account ID test_account.svc.id.goog:借用方式ではメタデータサーバーがSERVICEACCOUNT_NAME.svc.id.goog形式のIDを返すため、署名付きURLの手動作成などでメールアドレスを要求する処理が失敗します。KSAにiam.gke.io/return-principal-id-as-email="true"を付けます。- Pod起動直後の数秒だけ失敗する:メタデータサーバーが新しいPodの要求を受け付けるまで数秒かかる仕様です。リトライで解消します。Istioを使う場合は、Podの
metadata.annotationsにproxy.istio.io/config: '{"holdApplicationUntilProxyStarts": true}'を設定し、プロキシの準備ができるまでアプリの起動を待たせます。 ImagePullBackOff:イメージのpullはWorkload Identityではなくノードのサービスアカウントで行われます。Artifact Registryの権限はノード側に付けます。
採用前に確認したい制約
Workload Identityは、ノードのサービスアカウントや鍵ファイルより安全な方式として公式が推奨しています。ただし、次の制約を知らずに設計すると、権限が意図せず広がったり、高負荷時に認証が詰まったりします。
ID の同一性とマルチクラスタの境界
プールはプロジェクトに1つなので、同じプロジェクトの複数クラスタで同じNamespace名・KSA名を使うと、IAMはそれらを同一のIDとして扱い、どのクラスタからの呼び出しかを区別しません。公式ドキュメントは、信頼できないチームが同じプロジェクトにクラスタを作れば、同じ名前のNamespaceとKSAで権限を得られると明記しています。チームごとに信頼度が違うなら、クラスタを別プロジェクトに分けてください。同じプロジェクトに置くしかない場合は、条件付きIAMでクラスタを限定します。この1点を理由に、テナントの異なるクラスタを1プロジェクトに同居させる構成は採りません。
メタデータサーバーの上限と対象外のPod
- GKEメタデータサーバーへの同時接続はノードあたり500までで、超えた分は待たされ、クライアントのタイムアウトで
HTTP/499になることがあります。 - クラスタ内のKSAが3,000を超えると、メモリ不足でメタデータサーバーのPodがkubeletに終了されることがあります。
- STSのトークン交換の割り当ては1分あたり6,000リクエストです。超えると
QUOTA_EXCEEDEDになるので、割り当ての引き上げを申請します。 hostNetwork: trueのPodのメタデータ要求は、原則としてノードのメタデータサーバーへ回されます。ただし、Standard GKE 1.33.3-gke.1226000以降のCloud Storage FUSE CSIドライバでは、対応する設定によりhostNetworkのPodも自身のKSAで認証できます。組み込みのLogging・Monitoringエージェントもノードのサービスアカウントで動きます。
AWS・Azureの同等機能との違い
Kubernetes上のPodに権限を渡す仕組みを、EKS・AKSと並べると次のとおりです。
| 項目 | GKE | EKS Pod Identity | EKS IRSA | AKS Workload ID |
|---|---|---|---|---|
| 信頼の設定 | 不要(固定プール) | ロールが pods.eks.amazonaws.com を信頼 | クラスタごとのOIDCプロバイダ | フェデレーション資格情報 |
| ノード側の部品 | メタデータサーバー | Pod Identity Agent | 不要 | 変更Webhook |
| Pod側の指定 | KSAのみ | 関連付けのみ | KSAのアノテーション | ラベル+KSAのアノテーション |
| 使える環境 | GKE | EKSのみ | EKS・自前のK8sなど | AKS |
AWSのEKSユーザーガイドは、可能ならEKS Pod Identity(2023年11月発表)を使うよう推奨しています。IRSAはロールを新しいクラスタで使うたびに信頼ポリシーへOIDCプロバイダを追記する必要があり、Pod Identityではこの作業が要りません。EKSの全体像はAmazon EKSの解説記事を参照してください。
AKSでは、Podに azure.workload.identity/use: "true" ラベルを付け、KSAに azure.workload.identity/client-id アノテーションを付けます。フェデレーション資格情報はアプリまたはユーザー割り当てマネージドIDごとに最大20個なので、クラスタやNamespaceを増やす設計では上限に当たります。多数のクラスタで1つのマネージドIDを共有するidentity bindingsはプレビュー段階です。旧方式のPodマネージドIDは2022年10月24日に非推奨、2023年9月にアーカイブされ、マネージドアドオンのサポートも2025年9月までだったため、Microsoftの移行案内に沿ってWorkload IDへ移します。AKS自体の概要はAKSの解説記事にあります。
サービスアカウントキーから移行する判断
新規の構成で鍵ファイルを選ぶ理由は、ほぼ残っていません。サービスアカウントキーのドキュメントによると、2024年5月3日以降に作成された組織では、組織ポリシー iam.disableServiceAccountKeyCreation が既定で適用され、鍵をそもそも作れません。IAMの料金表でも、Workload Identity連携を含めユーザーやIDごとの追加料金はかからないとされています。
既存の鍵を使っている構成は、ワークロード単位で移します。GKEなら新しいノードプールを作ってから移し、外部連携なら構成ファイルで動くことを確かめてから鍵を無効化し、最後に削除します。鍵を使うしかないのは、トークンを交換できるIdPを持たない環境から呼ぶ場合などに限られます。社内でGoogle CloudやAWSの認証基盤をまとめて見直す場合は、弊社のインフラ構築(AWS・Google Cloud・Azure)支援でも設計から対応しています。
よくある質問
Workload IdentityとWorkload Identity Federationは違うものですか?
GKEの機能としては同じもので、現在の正式名称がWorkload Identity Federation for GKEです。一方、単に「Workload Identity 連携(Federation)」と書かれている場合は、AWSやGitHub ActionsなどGoogle Cloudの外のワークロード向けの機能を指すことが多く、自分でプールとプロバイダを作る点がGKEと違います。
Workforce Identity連携との違いは何ですか?
Workforce Identity連携は、従業員や委託先などの人間のユーザーが、外部IdPのアカウントでGoogle CloudのコンソールやCLIを使うための機能です。Workload Identityはプログラム(ワークロード)向けで、対象が違います。
Workload Identityに料金はかかりますか?
かかりません。Google CloudのIAMの料金表では、Workload Identity連携を含めユーザー・IDごとの追加料金はなく、IAM APIの利用も無料です。GKEやCloud Storageなど、アクセス先のサービスの料金は別に発生します。
iam.gke.io/gcp-service-accountのアノテーションはPodとServiceAccountのどちらに付けますか?
KubernetesのServiceAccountに付けます。このアノテーションはIAMサービスアカウントを借用する従来方式でだけ使うもので、KSAへ直接ロールを付与する推奨方式では不要です。
Cloud RunでもWorkload Identityの設定は必要ですか?
Cloud Run上のコードからGoogle Cloud APIを呼ぶだけなら不要です。Cloud Runのサービスアイデンティティとして、サービスにサービスアカウントを指定すれば、クライアントライブラリがその権限で動きます。外部の連携IDからCloud Runサービスを呼び出す場合は直接アクセスに対応していないため、サービスアカウントの借用を使います。Cloud Run自体の仕組みはCloud Runの解説記事を参照してください。