⚙️

environment設定でOIDC認証が失敗した話 (GitHub Actions)

に公開

GitHub Actions と AWS の OIDC 連携は、アクセスキーを不要にできるので非常に便利です。

これまでも同様の設定経験はありましたが、今回、特定のワークフローに限って突然認証エラーが発生し、原因の特定に時間を要しました。

原因は、GitHub Actionseinvoroment を使用すると sub クレームが変更されることでした。

(ちゃんと仕様を把握せずに使っていたせいです... orz)

事象:特定の信頼ポリシーでのみ認証が失敗

信頼ポリシーの確認

リポジトリを具体的に指定した場合は失敗し、ワイルドカードを使った場合にのみ成功していました。

# 失敗する例
{
  "Condition": {
    "StringLike": {
      "token.actions.githubusercontent.com:sub": [
        "repo:{MyOrg}/{repo}:ref:refs/heads/main",
        "repo:{MyOrg}/{repo}:ref:refs/heads/feature/*"
      ]
    }
  }
}

# 成功する例
{
  "Condition": {
    "StringLike": {
      "token.actions.githubusercontent.com:sub": "repo:{MyOrg}/*"
    }
  }
}

IAM ポリシーの記述ミスや権限設定も確認しましたが、原因が掴めませんでした。

原因調査:OIDCトークンの内容確認

GitHub Actions からのサンプルログ

  • GitHub ActionsのワークフローログでOIDCトークンのsubクレームを確認
OIDC Debug Information:
Repository: {MyOrg}/{repo}
Ref: refs/heads/feature/fix-deployment
SHA: a1b2c3d4e5f6789012345678901234567890abcd
Actor: developer-user
Workflow: Deploy API Service (OIDC)
Run ID: 12345678901
Event: workflow_dispatch
Expected sub claim: repo:{MyOrg}/{repo}:ref:refs/heads/feature/fix-deployment

CloudTrail からのサンプルログ

{
  "eventSource": "sts.amazonaws.com",
  "eventName": "AssumeRoleWithWebIdentity",
  "errorCode": "AccessDenied",
  "userIdentity": {
    "type": "WebIdentityUser",
    "userName": "repo:{MyOrg}/{repo}:environment:development"
  }
}

この userName が AWS が受け取った sub クレームであり、
リポジトリ名+ブランチ情報ではなく environment 名 が渡されていることがわかりました。

原因:environment設定によるsubクレーム形式の変更

CloudTrail のログが示すように、ジョブに environment を設定していると sub クレームの形式が変わります。

environment 設定 sub クレームの形式
なし repo:{MyOrg}/{repo}:ref:refs/heads/branch-name
あり repo:{MyOrg}/{repo}:environment:environment-name

GitHub の公式ドキュメントでもこの挙動は明記されています:

The following example OIDC token uses a subject (sub) that references a job environment named prod in the octo-org/octo-repo repository

参考:About security hardening with OpenID Connect


対処法

認証の仕組みが理解できれば、運用に合わせて使い分けができます。

パターン1: 環境ベース認証(推奨)

  • 各環境で environment を設定
  • 環境ごとに別々のIAMロールで権限を分離
# 開発用
"repo:{MyOrg}/{repo}:environment:development"
# 検証用
"repo:{MyOrg}/{repo}:environment:staging"
# 本番用
"repo:{MyOrg}/{repo}:environment:production"

パターン2: ブランチベース認証

  • environment 設定なしでブランチ名による認証
  • feature/* ブランチから開発環境へのデプロイなど
"repo:{MyOrg}/{repo}:ref:refs/heads/main",
"repo:{MyOrg}/{repo}:ref:refs/heads/feature/*"

まとめ

今回の認証エラーは、environment 設定の有無によってOIDCトークンの sub クレーム形式が変わるという、見落としがちなGitHub Actionsの仕様が原因でした。

運用パターンとしては以下のような使い分けが可能です:

  • 開発環境: environment なし → ブランチベース認証
  • 本番環境: environment あり → 環境ベース認証

これまであまり気にせずテンプレートで作成していたので、完全に盲点でした。
同じ問題で悩む方の参考になれば幸いです。

Discussion