GitHub Actions の OIDC で Google Cloud に入れない:「The given credential is rejected by the attribute condition」
GitHub はジョブにトークンを渡し、Google Cloud の Security Token Service は、Workload Identity のプロバイダーの属性条件(CEL の式)をそのトークンで評価しました。結果は偽でした。どの部分で落ちたかは Google が教えてくれないので、条件とトークンの中身を見比べます。
見え方
Error: google-github-actions/auth failed with: failed to generate Google Cloud federated token for //iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/github/providers/my-repo: {"error":"unauthorized_client","error_description":"The given credential is rejected by the attribute condition."}
「Failed to generate Google Cloud federated token」は、トークンが Workload Identity のプールに入れなかったという意味です(アクションのトラブルシューティング)。サービスアカウントはそのあとの段階で、そこで落ちたときは別のメッセージになります(このページの最後)。
条件を読みます:
gcloud iam workload-identity-pools providers describe PROVIDER \ --project=PROJECT --location=global --workload-identity-pool=POOL \ --format='value(attributeCondition)'
1. リポジトリの名前を変えた・移管した
assertion.repository_owner == 'old-org' のような名前の条件や、古い名前で始まる workflow_ref の条件は、リポジトリが動くと一致しなくなります。univrse-onboardai #24 では、別の組織への移管でリポジトリの ID は変わらずオーナーの ID が変わり、2つのプロバイダーがどちらも古いオーナーの ID と古い workflow_ref を固定したままでした。
アクションのセキュリティの注意書きは、GitHub が使い回さない数字の ID を勧めています。リポジトリの ID は、名前の変更でも移管でも変わりません:
assertion.repository_id == '260064828' && assertion.ref == 'refs/heads/main'
リポジトリの ID は gh api repos/OWNER/REPO --jq .id、組織の ID は gh api orgs/ORG --jq .id で出ます。assertion.repository_owner_id を足すのは、リポジトリが組織を離れたら止まってほしいときだけです。
2. 条件が sub を見ていて、sub に ID が入った
GitHub の2026年4月23日の変更履歴によると、2026年7月15日より後に作られたリポジトリと、その日より後の名前の変更・移管は、不変の sub を使います。古いリポジトリは、誰かが有効にしたときだけです。これまでの形で書いた条件は、どれにも一致しません:
repo:octo-org/octo-repo:ref:refs/heads/main これまで repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main 不変の形式
fortaleza-game #7 では、use_immutable_subject: true のリポジトリが名前の形を求めるプロバイダーで落ち、直しは上の repository_id と ref の条件でした。これならどちらの形でも通ります。リポジトリがどちらの形を送るかは gh api repos/OWNER/REPO/actions/oidc/customization/sub でわかります。
principal://…/subject/repo:octo-org/octo-repo:…への IAM のバインディングも、1段あとで同じ問題になります。マッピングにattribute.repository_id=assertion.repository_idを入れたprincipalSet://…/attribute.repository_id/260064828のバインディングなら、なりません。- 不変の形式は長くなります。マッピングが
google.subject=assertion.subだと、長い名前に environment が付いて、Google Cloud がgoogle.subjectに設けている127文字の上限を超えることがあります。
3. プルリクエストから実行し、条件が main だけを許している
プルリクエストの実行の ref は refs/pull/N/merge なので、assertion.ref == 'refs/heads/main' は偽になります。たいていは狙いどおりです。olmo-eval #497 では、デプロイ用の ID を main に絞ったあとプルリクエストの plan がすべて失敗し、プロジェクトはプルリクエストからの認証をやめました。プルリクエストに読むだけの権限が要るなら、refs/pull/ を許す条件の別のプロバイダーかサービスアカウントを用意します。
4. 大文字と小文字
GitHub は FooBar と foobar を同じ名前として扱いますが、Google Cloud は区別するので、条件にはトークンのとおりの大文字と小文字を書きます(アクションのトラブルシューティング)。
トークンの中身を見る
トラブルシューティングは github/actions-oidc-debugger を挙げています。クレームを表示するので、プライベートのリポジトリで走らせ、repository・repository_id・repository_owner・ref・sub を条件と見比べます。
見分け方
- サービスアカウントについての「Failed to generate Google Cloud OAuth 2.0 Access Token for」:トークンはプールに入れて、サービスアカウントになりすます段階で落ちました。
roles/iam.workloadIdentityUserのバインディングとその principal を見ます。 - 「GitHub Actions did not inject $ACTIONS_ID_TOKEN_REQUEST_TOKEN or $ACTIONS_ID_TOKEN_REQUEST_URL into this job」:調べるトークンがありませんでした:「Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable」。
- 同じ不変の
subは、Azure と AWS の信頼の設定も壊します:「AADSTS700213」と「Not authorized to perform sts:AssumeRoleWithWebIdentity」。
失敗したジョブを IntelliJ IDEA から見るなら
Pipeline Inbox for GitHub Actions Workflows は、Lesstep が作っている JetBrains IDE(2024.1 以降)のプラグインです。すべてのリポジトリの実行を、ジョブ・ステップと一緒に IDE のツールウィンドウに並べ、いまのブランチの実行はステータスバーに出ます。読むのは無料、失敗したジョブの再実行・キャンセル・ワークフローの実行・デプロイのレビューは Pro(月 US$1.50・30日の無料試用つき)です。
GitHub と GitHub Actions は GitHub, Inc. の商標、Google Cloud は Google LLC の商標、IntelliJ IDEA は JetBrains s.r.o. の商標です。このページは GitHub, Inc.・Google・JetBrains のいずれとも提携しておらず、承認も受けていません。
ほかに:GitHub Actions の OIDC で Azure に入れない · GitHub Actions の OIDC で AWS に入れない · 「Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable」 · IntelliJ IDEA で使える GitHub Actions のプラグインの比較 · English