Article

🔐 GitHub ActionsからAWSへ安全に接続する:OIDCとIAMロールの実装手順

githubactions, aws, oidc, security

GitHub ActionsからAWSへデプロイする際、AWSアクセスキーをSecretsに保存する方法だけが選択肢ではありません。**OIDC(OpenID Connect)**を使えば、GitHubが発行する身元証明用トークンをAWSに渡し、短期間だけ有効な認証情報を受け取れます。

この記事では、GitHub ActionsからS3へファイルをアップロードする例で、実装と失敗しやすい箇所を整理します。2026年10月時点の公式ドキュメントを確認しています。

仕組みを理解する

GitHub Actions
  → GitHubからOIDCトークンを取得
  → AWS STSでIAMロールを引き受ける
  → 一時的なAWS認証情報を使ってS3にアクセス
  • OIDC:異なるサービス間で実行元の身元を証明するための仕組み。
  • STS:AWSの一時的な認証情報を発行するサービス。
  • IAMロール:AWSで引き受けられる権限のまとまり。
  • 信頼ポリシー:そのロールを誰が引き受けられるか決める設定。

長期アクセスキーの保管とローテーションを減らせる一方で、ロールの権限は引き続き最小限に設定する必要があります。

1. GitHubのOIDCプロバイダーをAWSへ登録する

AWS IAMでIDプロバイダーを作成し、次の値を設定します。

項目 設定値
プロバイダーURL https://token.actions.githubusercontent.com
Audience sts.amazonaws.com

Audience(オーディエンス)はトークンの利用先を表します。一般的なAWSの構成で公式Actionを使う場合の値です。既存のIDプロバイダーがある場合は重複して作らず設定を確認します。

2. 信頼ポリシーで実行元を限定する

IAMロールの信頼ポリシー例です。AWSアカウントIDやリポジトリ名はダミー値です。

{
  "Version": "2012-10-17",
  "Statement": [{
    "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:example-org/example-api:ref:refs/heads/main"
      }
    }
  }]
}

sub(subject)はトークンの実行元を識別する値です。この例は特定のリポジトリのmainブランチだけを許可します。AWS公式ドキュメントも、組織・リポジトリ・ブランチなどで信頼対象を絞ることを推奨しています。

2026年7月15日以降に作成したGitHubリポジトリは要注意です。 GitHub公式リファレンスによると、新規リポジトリのデフォルトsubには変更されない所有者IDとリポジトリIDが含まれます。

# 従来形式
repo:example-org/example-api:ref:refs/heads/main

# 新形式(IDは説明用の値)
repo:example-org@111111/example-api@222222:ref:refs/heads/main

実際に使用する形式とIAMの信頼ポリシーを一致させてください。従来から存在するリポジトリも設定変更や移転で形式が変わる場合があります。またGitHub Environmentを使う場合は、ブランチ参照の代わりに環境名を含むsubを使うため、環境のデプロイ保護ルールも設定します。

3. AWS操作権限を最小にする

信頼ポリシーは「誰が使えるか」、権限ポリシーは「何をできるか」で、別々の設定です。S3の特定の場所にファイルをアップロードするだけなら、次のように絞れます。

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["s3:PutObject"],
    "Resource": ["arn:aws:s3:::example-deploy-bucket/releases/*"]
  }]
}

s3:PutObjectはS3へのファイル書き込み権限です。s3:*やAdministratorAccessを最初から付けないようにします。S3バケットの設定やKMS暗号化などによっては追加権限が必要です。

4. GitHub Actionsの設定例

.github/workflows/deploy.ymlに次のように定義します。アカウントID・ロールARN・バケット名は自分の環境に置き換えてください。

name: Deploy to S3
on:
  push:
    branches: [main]

permissions:
  contents: read
  id-token: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/[email protected]
      - uses: aws-actions/[email protected]
        with:
          role-to-assume: arn:aws:iam::123456789012:role/example-github-oidc
          aws-region: ap-northeast-1
          allowed-account-ids: "123456789012"
      - name: Verify identity
        run: aws sts get-caller-identity
      - name: Upload
        run: aws s3 cp public/index.html s3://example-deploy-bucket/releases/index.html

contents: readはリポジトリを読む権限、id-token: writeはOIDCトークンを要求する権限です。後者はAWSへの無制限な書き込み権限ではありません。 allowed-account-idsは、想定外のAWSアカウントの認証情報が返されたときに処理を失敗させます。

コマンドaws sts get-caller-identityは利用中のAWSアカウントと権限主体を確認します。aws s3 cpは指定したローカルファイルをS3へコピーします。ファイルpublic/index.htmlがリポジトリに存在する想定です。

Actionのバージョンは2026年10月10日時点の公式リリースを確認しています。本番では更新内容をレビューし、必要ならコミットSHAで固定します。

よくある失敗と対処

Not authorized to perform sts:AssumeRoleWithWebIdentity:IAMの信頼ポリシーを確認してください。subのリポジトリ名・ID形式・ブランチ・Environment、audの不一致が典型的です。

Unable to locate credentials:id-token: writeやActionの入力値、実行環境を確認します。

認証は成功したのにS3でAccessDenied:IAM権限ポリシー、S3バケットポリシー、暗号化設定などを確認します。信頼ポリシーと操作権限は異なります。

不要なブランチまで許可している:repo:example-org/example-api:*のように広く許可すると、意図しないワークフローでもロールを利用できる可能性があります。必要なブランチ・環境のみに制限し、信頼できないPull Requestから強いAWS権限を利用しない設計にします。

長期アクセスキーとどう使い分ける?

OIDCは初期設定としてプロバイダー・IAMロールの作成が必要ですが、長期アクセスキーをGitHub Secretsへ保存する必要がありません。アクセスキー方式はセットアップが簡単な場合がある一方、漏えいや鍵の交換を継続して管理します。

新しいGitHub Actions→AWS連携では、公式ガイドでも案内されているOIDCを第一候補にすると運用しやすくなります。

まとめ

認証失敗の調査では、GitHubのid-token: write→IAM信頼ポリシーのsub→IAM操作権限の順に確認すると原因を切り分けやすくなります。特に2026年7月以降のsub形式変更に注意してください。

一次情報