GitHub Actions: 複数AWSアカウントへのTerraformデプロイ

1. 概要

  • 複数AWSアカウントへのTerraformデプロイパターン
  • 環境ごとにOIDC IAMロールを分ける構成
  • GitHub Environments(承認ゲート)の活用
  • matrix strategyでの並列・順次デプロイ

dev/stg/prdを別々のAWSアカウントで管理している場合、GitHub ActionsからそれぞれのアカウントにTerraformをデプロイする構成が必要です。


2. 構成の概要

GitHub Actions
  ├─ dev job  → sts:AssumeRoleWithWebIdentity → dev account (123456789001)
  ├─ stg job  → sts:AssumeRoleWithWebIdentity → stg account (123456789002)
  └─ prd job  → sts:AssumeRoleWithWebIdentity → prd account (123456789003)

各AWSアカウントに同名のIAMロール(例: GitHubActionsRole)を作成します。


3. 各アカウントのOIDC IAMロール設定

# 各アカウントに同じコードでデプロイ(アカウントIDは変数で管理)
terraform {
  required_version = ">= 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

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

variable "environment" {
  description = "環境名(dev/stg/prd)"
  type        = string
  default     = "dev"
}

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

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

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"
  }
}

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_org}/${var.github_repo}:*"
        }
      }
    }]
  })

  tags = {
    Name        = "GitHubActionsRole"
    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"
}

4. GitHub Actionsワークフロー(順次デプロイ)

# .github/workflows/terraform-multi-account.yml
name: Terraform Multi Account Deploy

on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy-dev:
    name: Deploy to dev
    runs-on: ubuntu-latest
    environment: dev   # GitHub Environmentsの承認ゲート(任意)
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789001:role/GitHubActionsRole
          aws-region: ap-northeast-1
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~> 1.9"
      - name: Terraform Init & Apply (dev)
        run: |
          terraform init -backend-config="bucket=my-tfstate-dev"             -backend-config="key=app/terraform.tfstate"             -backend-config="region=ap-northeast-1"
          terraform apply -auto-approve -var="environment=dev"
        working-directory: ./environments/dev

  deploy-stg:
    name: Deploy to stg
    needs: deploy-dev    # devが成功してから実行
    runs-on: ubuntu-latest
    environment: stg
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789002:role/GitHubActionsRole
          aws-region: ap-northeast-1
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~> 1.9"
      - name: Terraform Init & Apply (stg)
        run: |
          terraform init -backend-config="bucket=my-tfstate-stg"             -backend-config="key=app/terraform.tfstate"             -backend-config="region=ap-northeast-1"
          terraform apply -auto-approve -var="environment=stg"
        working-directory: ./environments/stg

  deploy-prd:
    name: Deploy to prd
    needs: deploy-stg    # stgが成功してから実行
    runs-on: ubuntu-latest
    environment: production   # GitHub Environments: 手動承認を設定
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789003:role/GitHubActionsRole
          aws-region: ap-northeast-1
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~> 1.9"
      - name: Terraform Init & Apply (prd)
        run: |
          terraform init -backend-config="bucket=my-tfstate-prd"             -backend-config="key=app/terraform.tfstate"             -backend-config="region=ap-northeast-1"
          terraform apply -auto-approve -var="environment=prd"
        working-directory: ./environments/prd

5. GitHub Environments(手動承認ゲート)

GitHub の Settings → Environments → production で “Required reviewers” を設定すると、prdデプロイ前に指定したメンバーの承認が必要になります。

dev deploy → stg deploy → [承認待ち] → prd deploy

これにより、意図しない本番デプロイを防ぐことができます。


6. アカウントID管理

# .github/workflows/terraform-multi-account.yml(変数化)
env:
  DEV_ACCOUNT_ID: "123456789001"
  STG_ACCOUNT_ID: "123456789002"
  PRD_ACCOUNT_ID: "123456789003"
  ROLE_NAME: "GitHubActionsRole"

# 各jobで
role-to-assume: arn:aws:iam::${{ env.DEV_ACCOUNT_ID }}:role/${{ env.ROLE_NAME }}

アカウントIDはGitHub Secretsではなく環境変数として管理して問題ありません(AWSアカウントIDは秘密情報ではない)。


7. 関連記事


8. まとめ

  • 複数AWSアカウントへのデプロイは、アカウントごとに異なるIAMロールARNを使ってAssumeRoleする
  • OIDCを使えばアカウントキーなしで各アカウントに認証できる
  • needs:でjob間の依存関係を設定することで dev → stg → prd の順次デプロイを実現
  • GitHub Environmentsの承認ゲートで本番デプロイに人間の承認を必須にできる

対象バージョン: Terraform >= 1.9 / GitHub Actions (2024) 公式ドキュメント: https://docs.github.com/ja/actions/deployment/targeting-different-environments/using-environments-for-deployment