はじめに
インフラの変更を手動で terraform apply するのは、ミスのリスクもあるし、履歴も残りにくい。そこで今回は GitHub Actions を使って Terraform の実行を自動化し、CI/CD パイプライン上で AWS インフラを管理できる環境を構築しました。
OIDC(OpenID Connect)を使った パスワードレス認証 を採用しているので、AWS のアクセスキーをシークレットに保存する必要がないのもポイントです。
構成
ディレクトリ構成
GithubActions/
├── .github/
│ └── workflows/
│ ├── tf_deploy.yml # Terraform Apply ワークフロー
│ └── tf_destory.yml # Terraform Destroy ワークフロー
├── backend.tf # S3 バックエンド設定
└── main.tf # AWS リソース定義
構成図
GitHub Actions
│
│ OIDC 認証(アクセスキー不要)
▼
AWS IAM Role
│
├──▶ S3(tfstate 管理)
│ bucket: hiro-tech-taku-terraform-tfstate-xxxxxxxx
│
└──▶ Terraform が管理する AWS リソース
├── VPC(10.0.0.0/16)
└── Subnet(10.0.1.0/24 / ap-northeast-1a)
使用技術
| カテゴリ | ツール・サービス |
|---|---|
| IaC | Terraform |
| CI/CD | GitHub Actions |
| クラウド | AWS(VPC, Subnet, S3, IAM) |
| 認証 | AWS OIDC(パスワードレス) |
| tfstate 管理 | S3 バックエンド |
作業手順
1. S3 バックエンドの設定
Terraform の状態ファイル(tfstate)を S3 で管理します。ローカルに tfstate を持たないことで、チーム開発や CI/CD との相性が格段に上がります。
# backend.tf
terraform {
backend "s3" {
bucket = "hiro-tech-taku-terraform-tfstate-xxxxxxxx"
key = "network/terraform.tfstate"
region = "ap-northeast-1"
}
}
2. AWS リソースの定義
今回は VPC とパブリックサブネットを東京リージョンに作成します。
# main.tf
provider "aws" {
region = "ap-northeast-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "public_a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
}
3. GitHub Actions の OIDC 認証設定
GitHub Actions から AWS へ安全に接続するため、OIDC を使います。事前に AWS 側で以下を設定します。
-
IAM Identity Provider に GitHub の OIDC プロバイダー(
token.actions.githubusercontent.com)を追加 - IAM ロール を作成し、Trust Policy でリポジトリからの Assume Role を許可
- ロールの ARN を GitHub リポジトリの Secrets に
AWS_ROLE_ARNとして登録
4. Terraform Apply ワークフロー
workflow_dispatch(手動実行)をトリガーとして、plan → apply を実行します。誤操作防止のため自動トリガーはあえて設定していません。
# .github/workflows/tf_deploy.yml
name: Terraform Apply
on:
workflow_dispatch: # 手動実行推奨(誤操作防止)
permissions:
id-token: write
contents: read
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1
- name: Terraform Init
run: terraform init
- name: Terraform Plan
run: terraform plan
- name: Terraform Apply
run: terraform apply -auto-approve
ポイント: permissions に id-token: write を付与することで OIDC トークンの発行が可能になります。
5. Terraform Destroy ワークフロー
リソースを削除するワークフローも別ファイルで管理します。こちらも workflow_dispatch のみに限定し、意図しない削除を防ぎます。
# .github/workflows/tf_destory.yml
name: Terraform Destroy
on:
workflow_dispatch:
permissions:
id-token: write
contents: read
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1
- name: Terraform Init
run: terraform init
- name: Terraform Destroy
run: terraform destroy -auto-approve
6. 動作確認
GitHub の Actions タブ → ワークフローを選択 → Run workflow ボタンで手動実行します。
各ステップが緑になれば成功。AWS コンソールで VPC とサブネットが作成されていることを確認できます。
振り返り
よかった点
- OIDC 認証の採用 により、AWS のアクセスキーを一切 GitHub に登録せずに済んだ。セキュリティ面で安心感がある。
- Apply と Destroy を別ワークフローに分離 することで、誤ってリソースを削除するリスクを減らせた。
- アクション SHA ピン留め を使用しており、サプライチェーン攻撃への対策ができている。
- S3 バックエンド を使うことで tfstate がリモートで管理され、どこからでも同じ状態で Terraform を実行できる。
改善したい点
-
Terraform Plan の結果をプルリクエストにコメント する仕組みを追加したい(
terraform-plan-notifierなどのアクションが使える)。 -
ブランチ戦略の整理:現状は
workflow_dispatchのみだが、mainブランチへのマージをトリガーにした自動 apply も検討したい。 - tfstate のロック:現在は S3 のみのバックエンドだが、DynamoDB によるステートロックを追加することで、同時実行による競合を防げる。
- モジュール化:VPC やサブネットの定義が増えてきたら、Terraform モジュールとして切り出すと再利用性が上がる。
詰まった点
- Terraform backend で変数が使えずエラー発生 (原因:backend ブロックは 変数禁止 → backend-config ファイルを生成する方式に変更)
-
GitHub Actions の OIDC が AssumeRole に失敗する問題:原因は Trust Policy の sub が GitHub の実際の sub と一致していない、GitHub の新しい OIDC 仕様(2026年以降)で ownerID と repoID が付与される形式 となっていることが判明
従来:repo:owner/repo:ref:refs/heads/main
現在:repo:owner@ownerID/repo@repoID:ref:refs/heads/main
まとめ
GitHub Actions と Terraform を組み合わせることで、インフラの変更をコードレビューのフロー上に乗せることができました。OIDC によるパスワードレス認証は最初の設定こそ少し手間がかかりますが、一度整えてしまえばセキュアで運用しやすい構成になります。
まずは小さなリソース(VPC/Subnet)から始めて、この構成を土台に本番環境のインフラ管理へ拡張していく予定です。