github-actions-oidc-aws について
GitHub Actions から AWS へアクセスする際、長期 IAM 認証情報の代わりに OIDC でロールを引き受ける方法を示すリファレンススキルです。チーム向けに、設定、リポジトリ制限、権限、デプロイ方式、トラブルシューティングを扱います。
主な機能
- 01OIDC による一時 AWS 認証情報
- 02リポジトリとブランチの信頼ポリシー制限
- 03最小権限に基づく IAM 設定
- 04CDK、Terraform、CLI、CloudFormation の設定例
- 05デプロイ方式とトラブルシューティング
活用シーン
- 01デプロイ前の GitHub Actions の AWS 認証
- 02AWS ロールの対象を特定リポジトリやブランチに限定
- 03保存済み AWS アクセスキーの置き換え
- 04OIDC エラーやロール権限の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ loxosceles-dev/ dev-skills --skill github-actions-oidc-awsインストール後、Claude Code で/github-actions-oidc-awsを入力して読み込まれたか確認します。
詳細
AWS 向け GitHub Actions OIDC 認証
これは参考パターンです。 このアプローチを学び、状況に合わせて応用してください。そのままコピーしないでください。
ステータス:🔴 重大なパターン
カテゴリ:CI/CD/インフラストラクチャ
適用対象:GitHub Actions を使用して AWS にデプロイするすべてのプロジェクト
概要
長期間有効な IAM 認証情報の代わりに、OpenID Connect(OIDC)を使用して AWS リソースにアクセスする、GitHub Actions ワークフロー向けの安全な認証パターンです。GitHub シークレットに AWS アクセスキーを保存する必要がなくなります。
主なメリット:
- ローテーションや漏えいの心配がある長期間有効な認証情報が不要
- 有効期限が自動設定される一時的な認証情報
- リポジトリを対象としたアクセス制御
- AWS CloudTrail による監査証跡
- 業界のベストプラクティス(AWS と GitHub が推奨)
問題
GitHub Actions ワークフローは、インフラストラクチャのデプロイ、パイプラインのトリガー、またはリソースの管理を行うために、AWS に対して認証する必要があります。従来の方法には、セキュリティ上の問題があります。
アンチパターン:静的 IAM 認証情報
# ❌ Security risk: long-lived credentials in secrets
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
問題点:
- 認証情報に有効期限がありません(手動でローテーションする必要があります)
- 漏えいした場合、攻撃者が継続的にアクセスできます
- 特定のリポジトリにアクセスを制限する方法がありません
- どのワークフローが認証情報を使用したかを監査するのが困難です
- 最小権限の原則に違反します
解決策
GitHub の OIDC プロバイダーを使用し、AWS IAM ロールの引き受けを通じて一時的な認証情報を発行します。
フロー:
GitHub Actions → OIDC Token → AWS STS → Temporary Credentials → AWS Resources
仕組み:
- GitHub Actions が GitHub に OIDC トークンをリクエストします
- ワークフローがトークンを AWS STS に提示します
- AWS が IAM OIDC プロバイダーに照らしてトークンを検証します
- AWS が一時的な認証情報を発行します(有効期間は 1 時間)
- ワークフローが一時的な認証情報を使用して AWS にアクセスします
コンポーネント
1. AWS IAM OIDC プロバイダー
AWS と GitHub の OIDC 発行者間の信頼関係を確立します。
設定:
- URL:
https://token.actions.githubusercontent.com - オーディエンス:
sts.amazonaws.com - サムプリント:
1c58a3a8518e8759bf075b76b750d4f2df264fcd(GitHub ルート CA)
ルート CA のサムプリントを使う理由
- 中間証明書より安定しています
- GitHub が中間証明書をローテーションしても、信頼関係が損なわれません
- AWS のドキュメントで推奨されています
2. 信頼ポリシーを設定した IAM ロール
信頼ポリシーでアクセスを制限し、GitHub Actions が引き受けられるロールです。
信頼ポリシーの構造:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::{account}:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:{owner}/{repo}:*"
}
}
}]
}
信頼ポリシーのスコープ設定オプション:
# All branches and tags
"repo:owner/repo:*"
# Specific branch only
"repo:owner/repo:ref:refs/heads/main"
# Multiple branches
["repo:owner/repo:ref:refs/heads/main", "repo:owner/repo:ref:refs/heads/dev"]
# Pull requests
"repo:owner/repo:pull_request"
# Environment-specific
"repo:owner/repo:environment:production"
3. IAM アクセス許可ポリシー
ロールが AWS で実行できる操作を定義します(最小権限の原則)。
ユースケース別の例:
パイプラインのトリガーのみ:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "codepipeline:StartPipelineExecution",
"Resource": "arn:aws:codepipeline:*:{account}:pipeline-name-*"
}]
}
S3 への直接デプロイ:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:DeleteObject", "s3:ListBucket"],
"Resource": ["arn:aws:s3:::bucket-name", "arn:aws:s3:::bucket-name/*"]
},
{
"Effect": "Allow",
"Action": "cloudfront:CreateInvalidation",
"Resource": "*"
}
]
}
インフラストラクチャのデプロイ(慎重に使用してください):
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}]
}
4. GitHub Actions ワークフローの設定
ワークフローでは、OIDC トークンをリクエストしてロールを引き受ける必要があります。
必要なアクセス許可:
permissions:
id-token: write # Required for OIDC token
contents: read # Required to checkout code
認証ステップ:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::{account}:role/{role-name}
aws-region: {region}
実装
ステップ 1:OIDC プロバイダーを作成する(一度だけの設定)
インフラストラクチャツールを選択してください。
AWS CDK(TypeScript):
import * as iam from 'aws-cdk-lib/aws-iam';
const provider = new iam.OpenIdConnectProvider(this, 'GitHubProvider', {
url: 'https://token.actions.githubusercontent.com',
clientIds: ['sts.amazonaws.com'],
thumbprints: ['1c58a3a8518e8759bf075b76b750d4f2df264fcd']
});
Terraform:
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["1c58a3a8518e8759bf075b76b750d4f2df264fcd"]
}
AWS CLI:
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com \
--thumbprint-list 1c58a3a8518e8759bf075b76b750d4f2df264fcd
CloudFormation:
GitHubOIDCProvider:
Type: AWS::IAM::OIDCProvider
Properties:
Url: https://token.actions.githubusercontent.com
ClientIdList:
- sts.amazonaws.com
ThumbprintList:
- 1c58a3a8518e8759bf075b76b750d4f2df264fcd
ステップ 2:IAM ロールを作成する
AWS CDK(TypeScript):
const role = new iam.Role(this, 'GitHubActionsRole', {
roleName: 'GitHubActionsRole',
assumedBy: new iam.WebIdentityPrincipal(provider.openIdConnectProviderArn, {
StringEquals: {
'token.actions.githubusercontent.com:aud': 'sts.amazonaws.com'
},
StringLike: {
'token.actions.githubusercontent.com:sub': `repo:${owner}/${repo}:*`
}
}),
inlinePolicies: {
DeploymentPermissions: new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['codepipeline:StartPipelineExecution'],
resources: [`arn:aws:codepipeline:*:${this.account}:pipeline-*`]
})
]
})
}
});
Terraform:
resource "aws_iam_role" "github_actions" {
name = "GitHubActionsRole"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.github.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
}
StringLike = {
"token.actions.githubusercontent.com:sub" = "repo:${var.github_owner}/${var.github_repo}:*"
}
}
}]
})
}
resource "aws_iam_role_policy" "github_actions" {
name = "deployment-permissions"
role = aws_iam_role.github_actions.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "codepipeline:StartPipelineExecution"
Resource = "arn:aws:codepipeline:*:${data.aws_caller_identity.current.account_id}:pipeline-*"
}]
})
}
ステップ 3:GitHub Actions ワークフローを更新する
変更前(静的認証情報):
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-bucket
変更後(OIDC):
name: Deploy
on: [push]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-bucket
ステップ 4:古いシークレットを削除する(クリーンアップ)
# List current secrets
gh secret list
# Remove old credentials
gh secret remove AWS_ACCESS_KEY_ID
gh secret remove AWS_SECRET_ACCESS_KEY
設定管理
アカウント ID のハードコーディングを避ける
アンチパターン:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
改善策:リポジトリ変数を使用する:
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/GitHubActionsRole
最善策:設定ファイルから読み取る:
- name: Load config
id: config
run: |
echo "account=$(grep '^AWS_ACCOUNT_ID=' .env | cut -d'=' -f2)" >> $GITHUB_OUTPUT
echo "region=$(grep '^AWS_REGION=' .env | cut -d'=' -f2)" >> $GITHUB_OUTPUT
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ steps.config.outputs.account }}:role/GitHubActionsRole
aws-region: ${{ steps.config.outputs.region }}
デプロイパターン
パターン A:パイプラインのトリガー
GitHub Actions が AWS CodePipeline をトリガーし、実際のデプロイを処理します。
次の場合に使用します:
- 複雑な複数ステージのデプロイ
- AWS ネイティブのデプロイ履歴が必要な場合
- 複数のソースからトリガーしたい場合
- ビルドに大規模なコンピューティングリソースが必要な場合
ワークフロー:
permissions:
id-token: write
contents: read
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/GitHubActionsRole
aws-region: ${{ vars.AWS_REGION }}
- run: aws codepipeline start-pipeline-execution --name my-pipeline
IAM アクセス許可:
{
"Effect": "Allow",
"Action": "codepipeline:StartPipelineExecution",
"Resource": "arn:aws:codepipeline:*:*:pipeline-name"
}
パターン B:直接デプロイ
GitHub Actions がデプロイ全体(ビルド+デプロイ)を実行します。
使用する場合:
- シンプルな静的サイトのデプロイ
- 素早いフィードバックループを求める場合
- GitHub Actions のネイティブ機能を優先する場合
- コストを重視する場合(CodePipeline/CodeBuild のコストを避ける)
ワークフロー:
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci && npm run build
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/GitHubActionsRole
aws-region: ${{ vars.AWS_REGION }}
- run: |
aws s3 sync dist/ s3://my-bucket/ --delete
aws cloudfront create-invalidation --distribution-id ${{ vars.CF_DIST_ID }} --paths "/*"
IAM 権限:
{
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:DeleteObject", "s3:ListBucket"],
"Resource": ["arn:aws:s3:::bucket/*", "arn:aws:s3:::bucket"]
},
{
"Effect": "Allow",
"Action": "cloudfront:CreateInvalidation",
"Resource": "*"
}
]
}
パターン C:インフラストラクチャのデプロイ
GitHub Actions がインフラストラクチャの変更(CDK、Terraform、CloudFormation)をデプロイします。
使用する場合:
- Infrastructure as Code のワークフロー
- PR ベースでインフラストラクチャをレビューしたい場合
- マージ前に変更を検証する必要がある場合
ワークフロー:
permissions:
id-token: write
contents: read
pull-requests: write # For PR comments
jobs:
plan:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/GitHubActionsTerraformRole
aws-region: ${{ vars.AWS_REGION }}
- run: terraform plan -out=plan.tfplan
- uses: actions/github-script@v7
with:
script: |
// Post plan to PR comment
apply:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/GitHubActionsTerraformRole
aws-region: ${{ vars.AWS_REGION }}
- run: terraform apply -auto-approve
IAM 権限:通常、広範な権限(AdministratorAccess または PowerUserAccess)が必要です。plan(読み取り専用)と apply(書き込み)で別々のロールを使用することを検討してください。
複数環境の戦略
環境ごとに個別のロールを設定する
推奨:開発/ステージング/本番環境ごとに、異なる権限を持つ個別のロールを作成してください。
CDK の例:
['dev', 'prod'].forEach(env => {
new iam.Role(this, `GitHubActionsRole-${env}`, {
roleName: `GitHubActionsRole-${env}`,
assumedBy: new iam.WebIdentityPrincipal(provider.openIdConnectProviderArn, {
StringEquals: {
'token.actions.githubusercontent.com:aud': 'sts.amazonaws.com'
},
StringLike: {
'token.actions.githubusercontent.com:sub':
env === 'prod'
? `repo:${owner}/${repo}:ref:refs/heads/main`
: `repo:${owner}/${repo}:ref:refs/heads/dev`
}
})
});
});
ワークフロー:
- name: Determine environment
id: env
run: |
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
echo "name=prod" >> $GITHUB_OUTPUT
else
echo "name=dev" >> $GITHUB_OUTPUT
fi
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/GitHubActionsRole-${{ steps.env.outputs.name }}
aws-region: ${{ vars.AWS_REGION }}
セキュリティに関する考慮事項
1. 最小権限の原則
必要最小限の権限を必ず付与してください:
// ❌ Too broad
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
// ✅ Specific
{
"Effect": "Allow",
"Action": "codepipeline:StartPipelineExecution",
"Resource": "arn:aws:codepipeline:us-east-1:123456789012:my-pipeline"
}
2. リポジトリのスコープ設定
必ず特定のリポジトリに制限してください:
// ❌ Any repository in organization
"token.actions.githubusercontent.com:sub": "repo:my-org/*"
// ✅ Specific repository
"token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:*"
// ✅ Even more specific (main branch only)
"token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"
3. オーディエンスの検証
必ずオーディエンスを検証してください:
{
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
}
}
4. セッション期間
デフォルト:1 時間(ほとんどのワークフローに十分です)
カスタム期間(必要な場合):
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
role-duration-seconds: 3600 # 1 hour (default)
aws-region: us-east-1
5. CloudTrail による監査
ロールの引き受けを監視します:
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \
--max-results 10
監視する主なフィールド:
userIdentity.principalId:GitHub リポジトリとワークフローrequestParameters.roleArn:引き受けられたロールsourceIPAddress:GitHub Actions の IP 範囲userAgent:GitHub Actions のユーザーエージェント
トラブルシューティング
エラー:「Not authorized to perform sts:AssumeRoleWithWebIdentity」
原因:信頼ポリシーがワークフローのコンテキストと一致していません。
確認項目:
- リポジトリ名が信頼ポリシーと一致している
- ブランチ/タグが信頼ポリシーの条件と一致している
- ワークフローに
id-token: write権限がある
デバッグ:
- name: Debug OIDC token
run: |
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sts.amazonaws.com" | jq
エラー:「OpenIDConnect provider not found」
原因:OIDC プロバイダーが作成されていないか、ARN が間違っています。
修正方法:
# List providers
aws iam list-open-id-connect-providers
# Check provider details
aws iam get-open-id-connect-provider \
--open-id-connect-provider-arn arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com
認証成功後に「Access Denied」エラーが発生する
原因:ロールに必要な権限がありません。
修正方法:ロールの権限ポリシーを更新し、必要なアクションを含めてください。
ワークフローが OIDC トークンを要求しない
原因:id-token: write 権限がありません。
修正方法:
permissions:
id-token: write # Add this
contents: read
移行チェックリスト
静的認証情報から OIDC への移行:
- AWS アカウントに OIDC プロバイダーを作成する
- 信頼ポリシーを持つ IAM ロールを作成する
- ロールに権限ポリシーをアタッチする
- ロールの引き受けを手動でテストする(任意)
- OIDC を使用するようワークフローを更新する
- ワークフローに
permissionsブロックを追加する - 認証情報のシークレットをロール ARN に置き換える
- 本番環境以外でワークフローをテストする
- CloudTrail ログにロールの引き受けが記録されていることを確認する
- 本番環境にデプロイする
- GitHub から古い AWS 認証情報のシークレットを削除する
- 古い IAM ユーザーを無効化/削除する(該当する場合)
- ロール ARN と権限を文書化する
参考資料
- GitHub Actions の OIDC ドキュメント
- AWS IAM OIDC プロバイダーのドキュメント
- aws-actions/configure-aws-credentials
- GitHub OIDC トークンのクレーム
- AWS セキュリティブログ:IAM ロールを使用して GitHub Actions を接続する
段階的な改善
開発者が、このスキルで防ぐべきだった動作を修正した場合は、同じ修正が今後発生しないよう、このスキルに加える具体的な変更を提案してください。