TFCとAWSを連携してGitのpush時に自動デプロイを実行する仕組みを作った話
はじめに
GitHub に push したコードをトリガーに、Terraform Cloud (TFC) が自動で plan
/ apply
を実行し、AWS上に VPC と EC2 を構築する仕組みを作りました。
ポイントは以下の通りです。
- GitHub ⇔ TFC の連携で push をトリガーにできる
- TFC ⇔ AWS の認証は OIDC + STS を利用(長期キー不要)
-
terraform plan
→apply
が完全自動化される
環境・前提条件
- Terraform Cloud アカウント
- AWS アカウント
- GitHub リポジトリ
- Terraform CLI(ローカルで初期検証用)
- 基本的なIAMの知識
構成イメージ
drawioを使って生成した構成図イメージです。
- GitHubにpush
- TFCが自動で
plan/apply
- AWS上にVPC・サブネット・EC2が構築される
実装したTerraformコード
provider.tf
provider "aws" {
region = "ap-northeast-1"
}
vpc.tf
# 利用するAZは先頭の1つだけ(シングルAZ)
data "aws_availability_zones" "this" {
state = "available"
}
# Amazon Linux 2023 の最新AMI
data "aws_ami" "al2023" {
most_recent = true
owners = ["137112412989"] # Amazon
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
# VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = { Name = "demo-vpc" }
}
# IGW(パブリックサブネット用)
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = { Name = "demo-igw" }
}
# Public Subnet(自動でPublic IP付与)
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.0.0/24"
availability_zone = data.aws_availability_zones.this.names[0]
map_public_ip_on_launch = true
tags = { Name = "demo-public-subnet" }
}
# Private Subnet(EC2はここだけに配置)
resource "aws_subnet" "private" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = data.aws_availability_zones.this.names[0]
tags = { Name = "demo-private-subnet" }
}
# Public用ルートテーブル(0.0.0.0/0 → IGW)
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = { Name = "demo-public-rt" }
}
resource "aws_route_table_association" "public_assoc" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
# Private用ルートテーブル(NATなし)
resource "aws_route_table" "private" {
vpc_id = aws_vpc.main.id
tags = { Name = "demo-private-rt" }
}
resource "aws_route_table_association" "private_assoc" {
subnet_id = aws_subnet.private.id
route_table_id = aws_route_table.private.id
}
# セキュリティグループ(全Outbound許可)
resource "aws_security_group" "ec2_private" {
name = "demo-ec2-private-sg"
description = "No inbound, all egress"
vpc_id = aws_vpc.main.id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = { Name = "demo-ec2-private-sg" }
}
# EC2(プライベートサブネットのみ/Public IPなし)
resource "aws_instance" "private" {
ami = data.aws_ami.al2023.id
instance_type = "t3.micro"
subnet_id = aws_subnet.private.id
associate_public_ip_address = false
vpc_security_group_ids = [aws_security_group.ec2_private.id]
tags = { Name = "demo-ec2-private" }
}
GitHub ⇔ TFC の連携
- TFCのWorkspaceを作成
- VCS ProviderにGitHubを登録
-
main
ブランチへのpushをトリガーにする設定
TFC ⇔ AWS の認証(OIDC + STS)
TFCからAWSに安全にアクセスするため、OIDCを利用しました。
IAMロールの信頼ポリシー例:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/app.terraform.io"
},
"Action": "sts:AssumeRoleWithWebIdentity"
}
]
}
このロールにEC2・VPC関連のポリシーを付与。
TFCのWorkspace側で「環境変数」にRole ARNを設定します。
実際にやったことの流れ
- GitHubにTerraformコードをpush
- TFCが自動で
terraform plan
を実行 - 差分がなければ
apply
も実行 - AWSにVPC+EC2が作成される
動作確認
- TFCのRun画面に
plan
/apply
のログが出力される - AWSコンソールで VPC・EC2 が作成されていることを確認
ハマりどころ
- IAM権限不足 → VPC/EC2に必要な権限をロールに付与すること
-
環境変数忘れ → TFCのWorkspaceにRole ARNを登録しないと
AccessDenied
が出る - State管理 → TFCのRemote Stateを使えばチーム開発でも安全
まとめ
- GitHub push をトリガーに、Terraform Cloud (TFC) で AWSリソースを自動構築 できた
- 認証は OIDC + STS にすることで、よりセキュアに運用可能
- 手動での
terraform apply
から卒業し、CI/CD の第一歩 として有効
今後の展望
今回の取り組みは学習目的として シンプルな自動デプロイ機能の検証 にとどめたが、将来的には以下のような仕組みを整備したい。
-
本番環境と開発環境を分離
- ワークスペースやブランチごとに明確に環境を分ける
-
Plan フェーズの自動化
- 開発ブランチへの push をトリガーに Terraform の Plan を実行
- インフラ変更内容をレビュー可能にする
-
Apply フェーズの自動化
- レビューを経て本番ブランチへ マージ された際に、Terraform の Apply を自動実行
- CI/CD パイプラインとして安定運用できる体制を目指す