はじめに
GitHub ActionsからAWSへアクセスするとき、こう書くことがある。
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/my-role
aws-region: ap-northeast-1
👉 アクセスキーがどこにもない。なぜこれでAWSにアクセスできるのか?
答えは OIDC認証 だ。
OIDCトークンで"一時アクセスキー"を発行する
❌ よくある誤解:「OIDCトークンをそのままAWS APIに渡している」
👉 実際は違う。OIDCトークン(JWT)は一時アクセスキーを発行するための証明書として使う。
最終的にAWSへのAPIアクセスに使うのはいつもの3つ:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_SESSION_TOKEN
フローはこうなっている:
GitHub Actions
1. GitHubからOIDCトークン(JWT)を取得
2. AWS STS: AssumeRoleWithWebIdentity にJWTを渡す
3. STSが一時キー(有効期限付き)を返す
→ AWS_ACCESS_KEY_ID
→ AWS_SECRET_ACCESS_KEY
→ AWS_SESSION_TOKEN
4. その一時キーで通常通りAWS APIを叩く
永続的なアクセスキーをリポジトリやSecretsに置く必要がなくなる。
そのJWT、なぜ信頼できるの?
疑問が出てくる。
「AWSはそのJWTが"許可していいトークン"だとどうやって判断しているの?」
答え:公開鍵暗号(電子署名) でJWTの署名を検証しているから。
JWTの中には署名が入っている。GitHubが秘密鍵でサインしたもので、AWSは公開鍵を使って「本当にGitHubが発行したものか」を検証できる。
公開鍵暗号の2パターン
「公開鍵・秘密鍵」と聞くと混乱しやすいが、用途が2つある。
① 暗号化(encryption)
公開鍵 → lock(暗号化)
秘密鍵 → unlock(復号)
- 公開鍵で暗号化し、秘密鍵でしか復号できない
- 例:PGP暗号メール、HTTPSの鍵交換フェーズ(※実データはセッション鍵で対称暗号化)
② 電子署名(digital signature)
秘密鍵 → サイン(署名)
公開鍵 → 本物確認(検証)
- 秘密鍵を持つ人だけが署名できる
- 誰でも公開鍵で「この署名は本物か」を確認できる
- 例:JWTの署名、コード署名
👉 OIDCはこちら(電子署名)を使う
GitHubが秘密鍵でJWTに署名 → AWSが公開鍵で検証
鍵の配置は自分でやる必要がある?
秘密鍵・公開鍵そのものを自分で生成・配置する必要はない。GitHubとAWSがそれぞれ管理してくれる。
- GitHubは自動的にOIDCトークンを発行し、公開鍵を Discovery エンドポイント(
https://token.actions.githubusercontent.com/.well-known/openid-configuration)経由でJWKSとして公開している - AWSはそのDiscoveryから公開鍵セット(JWKS)を取得・キャッシュし、JWTの署名を検証する
ただし、以下の3つの設定は自分でやる必要がある:
-
AWS IAMにOIDC Providerを登録する(
token.actions.githubusercontent.comをIDプロバイダーとして追加) - IAM RoleのTrust Policyを設定する(誰を信じるかの条件)
- GitHub ActionsのワークフローにOIDCトークン取得の権限を付与する(後述)
自分で設定するのは主に 「誰を信じるか」 の部分だ。
IAM RoleのTrust Policyで指定する:
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:myorg/my-app:ref:refs/heads/main"
}
}
}
条件の意味:
| 条件 | 意味 |
|---|---|
Federated |
GitHubのOIDC Providerを信頼する |
aud |
トークンの宛先(受信者)が sts.amazonaws.com であること |
sub |
特定のリポジトリ・ブランチからのみ許可 |
👉 sub の条件がポイント。特定リポジトリ・ブランチ以外からはAssumeRoleできない。なお sub の形式はコンテキストによって変わる(PR: repo:ORG/REPO:pull_request、タグ: repo:ORG/REPO:ref:refs/tags/TAG、Environment: repo:ORG/REPO:environment:ENV)。
また、GitHub ActionsのワークフローにOIDCトークンを取得する権限が必要だ。
permissions:
id-token: write # OIDCトークンの取得に必要
contents: read
👉 id-token: write が抜けると Error: Could not assume role で失敗する。
GitHubの機能?AWSの機能?
両方。 GitHubのOIDC機能 × AWSのOIDC Federation機能の掛け合わせ。
GitHub(IdP)
「私はGitHubです」
→ OIDCトークン(JWT)を発行
↓
AWS(Relying Party)
「GitHub発行か?」(公開鍵で署名検証)
「repo合ってる?」(sub条件チェック)
「aud合ってる?」(aud条件チェック)
↓
一時IAM Role払い出し
(AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN)
- GitHub:IdP(Identity Provider)。OIDCトークンを発行する側
- AWS:Relying Party。OIDCトークンを受け取り検証する側
どちらが欠けても動かない。
OIDCが使える条件と対応サービス
前提:発行側(IdP)と受け入れ側(Relying Party)の両方がOIDCを話せること
どちらか一方だけでは成立しない。
IdP(OIDCトークンを発行できる)
| サービス | 用途 |
|---|---|
| GitHub Actions | CI/CDパイプラインからクラウドへ |
| GitLab CI/CD | 同上 |
| Google(Google Identity / OIDC) | Googleアカウントでのログイン |
| Okta / Auth0 | 企業のIdP |
Relying Party(OIDCトークンを検証・信頼できる)
| サービス | 仕組み |
|---|---|
| AWS | IAM OIDC Federation |
| GCP | Workload Identity Federation |
| Azure | Federated Identity Credentials |
| Kubernetes(EKS等) | Pod Identity / IRSA(SA TokenをIdPとしてAWSが信頼) |
👉 Kubernetes はIdPとしてもRelying Partyとしても機能する(APIサーバーに --oidc-issuer-url を設定することで外部OIDCも受け入れ可能)。
👉 GitHub Actions × AWS の組み合わせは代表例の一つ。同じ仕組みで GitHub × GCP や GitHub × Azure も実現できる。
まとめ
| 疑問 | 答え |
|---|---|
| OIDCトークンでAWS APIを叩く? | ❌ 一時アクセスキーを取得するために使う |
| AWSはなぜJWTを信頼できるの? | 公開鍵で電子署名を検証しているから |
| 秘密鍵・公開鍵を自分で設置する? | 不要。GitHubとAWSが管理 |
| GitHubの機能?AWSの機能? | 両方。IdP × Relying Partyの掛け合わせ |
| 他のサービスでも使える? | OIDCを話せるサービス同士なら使える |