GitHub Actions: OIDC認証でAWSクレデンシャルを排除する

1. 概要

  • OIDCとは何か、なぜアクセスキーより安全か
  • GitHub ActionsのOIDCトークンの仕組み
  • AWS IAMのOIDCプロバイダー設定とIAMロール作成
  • GitHub ActionsでのOIDC認証設定
  • conditionで特定リポジトリ・ブランチに限定する方法

GitHub ActionsからAWSを操作する際、従来はIAMアクセスキーをGitHub Secretsに保存していました。OIDCを使うと、一時的な認証情報を自動取得するため、長期間有効なアクセスキーが不要になります。


2. OIDCとは

OIDC(OpenID Connect)は、GitHub ActionsのジョブがAWSに対して「自分はGitHubのどのリポジトリのどのワークフローです」と証明する仕組みです。

GitHub Actions
  │ OIDCトークン(JWT)を発行
  ↓
AWS IAM(OIDC プロバイダー)
  │ トークンを検証 → 一時認証情報を発行
  ↓
AWS(S3・EC2等)

OIDCのメリット:

  • アクセスキーを管理・ローテーションする必要がない
  • 一時的な認証情報(15分〜12時間)のみ使用
  • 特定リポジトリ・ブランチのみに権限を絞れる

3. AWSのOIDCプロバイダーとIAMロールを作成

# oidc_setup/main.tf
terraform {
  required_version = ">= 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

variable "environment" {
  description = "環境名"
  type        = string
  default     = "dev"
}

variable "github_org" {
  description = "GitHubオーガニゼーション名"
  type        = string
}

variable "github_repo" {
  description = "GitHubリポジトリ名"
  type        = string
}

# GitHubのOIDCプロバイダー(アカウントに1つ)
resource "aws_iam_openid_connect_provider" "github" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]

  tags = {
    Name        = "github-oidc-provider"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

# GitHub ActionsがAssumeRoleするIAMロール
resource "aws_iam_role" "github_actions" {
  name = "GitHubActionsRole-${var.github_repo}"

  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 = {
            # mainブランチのみに制限する場合
            "token.actions.githubusercontent.com:sub" = "repo:${var.github_org}/${var.github_repo}:ref:refs/heads/main"
          }
        }
      }
    ]
  })

  tags = {
    Name        = "GitHubActionsRole-${var.github_repo}"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

# 必要な権限を付与(最小権限が望ましい)
resource "aws_iam_role_policy_attachment" "github_actions" {
  role       = aws_iam_role.github_actions.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
  # 本番ではterraform実行に必要な最小権限ポリシーに絞る
}

4. conditionの書き方パターン

# パターン1: mainブランチのみ
"token.actions.githubusercontent.com:sub" = "repo:my-org/my-repo:ref:refs/heads/main"

# パターン2: リポジトリの全ブランチ(PRも含む)
"token.actions.githubusercontent.com:sub" = "repo:my-org/my-repo:*"

# パターン3: タグのみ
"token.actions.githubusercontent.com:sub" = "repo:my-org/my-repo:ref:refs/tags/*"

# パターン4: 特定の環境(GitHub Environmentsを使う場合)
"token.actions.githubusercontent.com:sub" = "repo:my-org/my-repo:environment:production"

推奨: planはPRで実行するため*、applyはmainブランチに限定するために別ロールに分けることも検討してください。


5. GitHub Actionsでの設定

# .github/workflows/terraform.yml
name: Terraform

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  id-token: write    # OIDCトークン発行に必須
  contents: read

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole-my-repo
          aws-region: ap-northeast-1
          # role-session-nameでセッションを識別しやすくする
          role-session-name: GitHubActions-${{ github.run_id }}

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~> 1.9"

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        if: github.event_name == 'pull_request'
        run: terraform plan -no-color

      - name: Terraform Apply
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        run: terraform apply -auto-approve

6. アクセスキー方式との比較

比較軸OIDCアクセスキー
認証情報の有効期限一時的(15分〜12時間)永続(手動ローテーション必要)
シークレット管理不要GitHub Secretsで管理
ローテーション不要(自動)定期的に手動で実施
権限の絞り込みブランチ・環境単位で可能全ジョブで同一キー
漏洩リスク低(一時的トークン)高(長期間有効なキー)

7. 関連記事


8. まとめ

  • OIDCを使うとIAMアクセスキーなしでGitHub ActionsからAWSを操作できる
  • GitHub OIDCプロバイダー(IAMの設定)とIAMロールをTerraformで一度だけ作成する
  • permissions: id-token: writeをワークフローに設定することでOIDCトークンが発行される
  • conditionでリポジトリ・ブランチ・環境を絞ることで最小権限の原則を守れる
  • アクセスキー方式より安全で管理コストも低い。新規構築時はOIDCを選択する

対象バージョン: Terraform >= 1.9 / GitHub Actions (2024) 公式ドキュメント: https://docs.github.com/ja/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services