1. 概要
- TerraformとCI/CDを組み合わせる理由
- GitHub Actions連携の実例
planをPRにコメントする設定- 環境ごとのdeploy戦略
- セキュリティ上の注意点
手動でterraform applyを実行するワークフローは、レビューなしの変更・実行環境の差異・誰がいつapplyしたかのトレーサビリティ欠如、といった問題を生みます。CI/CDパイプラインに組み込むことでこれらを解消できます。
2. 基本的なGitHub Actionsワークフロー
# .github/workflows/terraform.yml
name: Terraform CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
TF_VERSION: "1.9.0"
AWS_REGION: "ap-northeast-1"
jobs:
terraform:
name: Terraform
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # PRへのコメント権限
id-token: write # OIDC認証用
defaults:
run:
working-directory: environments/prd
steps:
- name: Checkout
uses: actions/checkout@v4
# AWS認証(OIDCで一時認証情報を取得 — シークレット不要)
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-terraform
aws-region: ${{ env.AWS_REGION }}
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Terraform Init
run: terraform init
- name: Terraform Format Check
run: terraform fmt -check -recursive
- name: Terraform Validate
run: terraform validate
- name: Terraform Plan
id: plan
run: terraform plan -no-color -out=tfplan
continue-on-error: true # planが失敗してもコメントを投稿する
# PRにplanの結果をコメント
- name: Comment Plan Result
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const output = `#### Terraform Plan 📖
\`\`\`
${{ steps.plan.outputs.stdout }}
\`\`\`
*Pusher: @${{ github.actor }}*`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
# mainブランチへのマージ時のみapply
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve tfplan
3. OIDCによるAWS認証設定
シークレットとしてアクセスキーを管理するのではなく、OIDCで一時認証情報を使います。
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 = "prd"
}
variable "github_org" {
description = "GitHubオーガニゼーション名"
type = string
}
variable "github_repo" {
description = "GitHubリポジトリ名"
type = string
}
# GitHub Actions用OIDCプロバイダー
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-actions-oidc"
Environment = var.environment
ManagedBy = "terraform"
}
}
# GitHub Actions用IAMロール
resource "aws_iam_role" "github_actions_terraform" {
name = "github-actions-terraform"
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 = "github-actions-terraform"
Environment = var.environment
ManagedBy = "terraform"
}
}
# Terraformに必要な権限(最小権限の原則)
resource "aws_iam_role_policy_attachment" "github_actions_terraform" {
role = aws_iam_role.github_actions_terraform.name
policy_arn = "arn:aws:iam::aws:policy/PowerUserAccess"
}
4. 環境ごとのdeploy戦略
# PRからdev自動deploy、mainマージでprd deploy
name: Terraform Multi-env
on:
push:
branches: [main, develop]
pull_request:
jobs:
plan-dev:
runs-on: ubuntu-latest
defaults:
run:
working-directory: environments/dev
steps:
- uses: actions/checkout@v4
- name: Plan Dev
run: |
terraform init
terraform plan
apply-dev:
if: github.ref == 'refs/heads/develop'
needs: plan-dev
runs-on: ubuntu-latest
defaults:
run:
working-directory: environments/dev
steps:
- uses: actions/checkout@v4
- name: Apply Dev
run: |
terraform init
terraform apply -auto-approve
apply-prd:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production # GitHubの手動承認gate
defaults:
run:
working-directory: environments/prd
steps:
- uses: actions/checkout@v4
- name: Apply Prd
run: |
terraform init
terraform apply -auto-approve
5. セキュリティ上の注意点
| リスク | 対策 |
|---|---|
| AWSアクセスキーの漏洩 | OIDCで一時認証情報を使う(シークレット不要) |
| state内のsensitive値 | S3バックエンド + バケット暗号化 + アクセス制限 |
| 誤ったprd環境へのapply | environment: productionでGitHubの手動承認を要求 |
| planの結果が外部に漏洩 | PRコメントには概要のみ。詳細はCIログで確認 |
6. 関連記事
- terraform fmt / validate — CI組み込みの基本コマンド
- 環境分離のパターン比較 — ディレクトリ分離とCI/CDの組み合わせ
- backend — stateファイルの保存場所 — S3バックエンドの設定
7. まとめ
- GitHub ActionsでInit → fmt-check → validate → plan → applyの順で実行する
- AWSの認証はOIDCで一時認証情報を使う(アクセスキーのシークレット管理は不要)
- PRにplanをコメントしてレビューを促す
- prd環境へのapplyは
environment: productionで手動承認ゲートを設ける - stateはS3バックエンド + 暗号化 + アクセス制限で保護する
動作確認バージョン: Terraform >= 1.9 公式ドキュメント: https://developer.hashicorp.com/terraform/tutorials/automation/github-actions