【2026年版】Terraform × AWS IaC入門ガイド

コンソールをポチポチするのは「今日で最後」にしよう。
AWSで手動構築を続けているエンジニアが、転職・副業・現場のコードレビューで最初にぶつかる壁が「IaCを知らない」という問題だ。Terraformはそのデファクトスタンダードであり、インフラエンジニアにとって避けては通れないスキルになった。
この記事ではTerraform × AWSの組み合わせを使い、VPC・EC2の基本構築からtfstate管理・モジュール化・GitHub Actions CI/CD連携まで、現場で通用するレベルの知識を体系的に解説する。
この記事の対象読者
- AWSは使えるが、コンソール手動構築がメインのインフラエンジニア
- SES案件でインフラを触っているが、自社開発チームへの転職を目指している
- Terraformという言葉は知っているが、実際に書いたことがない
- チーム開発でのIaC標準化を任されそうで焦っている
IaC(Infrastructure as Code)とは何か
IaCとは、サーバーやネットワークなどのインフラ設定を「コードファイル」として記述し、そのファイルを実行してインフラを構築・変更・削除する手法だ。
従来の「コンソール手動構築」とIaCの違いを整理しよう。
| 観点 | コンソール手動 | IaC(Terraform) |
|---|---|---|
| 再現性 | 手順書が古くなる・属人化 | コードが常に正 |
| 差分管理 | 誰が何を変えたか不明 | git diff で一目瞭然 |
| 複数環境 | 本番・ステージの差異が生まれやすい | 変数を変えるだけで同一構成 |
| ロールバック | 手動で元に戻す | コードを戻してapply |
| チーム共有 | Slack・Confluenceに手順書 | リポジトリ=唯一の情報源 |
IaCの導入によって「誰が実行しても同じ結果になる」という状態が作れる。これが自社開発チームで当たり前に求められているレベルだ。
Terraform vs OpenTofu:2026年版どちらを選ぶか
Terraformを学ぶ前に、2026年現在の「Terraformを取り巻く状況」を把握しておく必要がある。
ライセンス変更問題(2023年)
2023年8月、HashiCorpはTerraformのライセンスをオープンソース(MPL 2.0)から**BSL 1.1(Business Source License)**に変更した。BSLはOSIが認定するオープンソースライセンスではなく、競合製品への利用が制限される。
これを受けてLinux Foundation のもとでOpenTofuが誕生した。Terraform 1.5.xからのフォークで、MPL 2.0のオープンソースライセンスで開発が続いている。
2026年現在の比較
- ライセンス: BSL 1.1
- 最新: v1.14.x(2026年)
- Terraform Registry: 4,800以上のプロバイダー
- エンタープライズ: HCP Terraform
- 現場採用率: 依然として最多
- ライセンス: MPL 2.0(OSS)
- Terraform 1.5.x と互換性あり
- 追加機能: state暗号化・for_each拡張
- コミュニティ主導で開発継続
- 新規採用での選択が増加中
どちらを選ぶべきか
既存のTerraform環境で働いているなら: Terraformのまま継続。 BSLはあくまで「HashiCorpと競合するサービス」への制限であり、インフラ管理ツールとして使う分には影響がほぼない。
新規プロジェクトでゼロから始めるなら: OpenTofuも有力な選択肢。 コマンド・構文・プロバイダーはTerraformと互換性があるので、本記事の内容はほぼそのまま適用できる。
この記事ではTerraformで解説するが、OpenTofuユーザーも同じ構文・コマンドで実践できる。
Terraformのインストール
tfenvでバージョン管理する(推奨)
本番環境との乖離を防ぐため、Terraformのバージョン管理ツール tfenv を使う。プロジェクトごとにバージョンを固定できるため、チーム開発での「自分の環境では動くのに」問題を防げる。
brew install tfenv
tfenv install 1.14.0
tfenv use 1.14.0
terraform --version
# Terraform v1.14.0git clone --depth=1 https://github.com/tfutils/tfenv.git ~/.tfenv
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
tfenv install 1.14.0
tfenv use 1.14.0チームで .terraform-version ファイルをリポジトリに含めておくと、全員が同じバージョンを使えるようになる。
1.14.0AWSプロバイダーの設定
TerraformはHCL(HashiCorp Configuration Language)という独自言語でインフラを定義する。まずAWSプロバイダーを設定しよう。provider.tf と variables.tf を分けておくと、後からの管理がしやすい。
terraform {
required_version = ">= 1.9"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}variable "aws_region" {
description = "AWSリージョン"
type = string
default = "ap-northeast-1"
}AWS認証の設定
aws configure
# AWS Access Key ID: ...
# AWS Secret Access Key: ...
# Default region name: ap-northeast-1セキュリティ注意
アクセスキーをコードに直書きしないこと。本番環境ではIAMロールを使った認証が必須。ローカル開発では ~/.aws/credentials にのみ保管し、.gitignore に追加しておくこと。
基本コマンドを覚える
Terraformの作業フローは4ステップで完結する。このサイクルを体に染み込ませることが、Terraform習得の第一歩だ。
-auto-approve を付けると確認プロンプトをスキップできる# 初期化(初回またはprovider追加後)
terraform init
# 実行計画の確認(必ずapply前に実行する)
terraform plan
# インフラの構築
terraform apply
# コードのフォーマット整形
terraform fmt
# 構文チェック
terraform validate
# リソースの削除(学習後は忘れずに)
terraform destroy実践:VPC + EC2 + セキュリティグループを構築する
基本的なWebサーバー構成をTerraformで定義してみよう。AWSコンソールでぽちぽちやってきた作業がコードに変わる体験が、IaC習得の一番の近道だ。
ディレクトリ構成
terraform-aws-sample/
├── provider.tf # プロバイダー設定
├── variables.tf # 変数定義
├── outputs.tf # 出力値
├── vpc.tf # VPC・サブネット・IGW
├── security_group.tf # セキュリティグループ
└── ec2.tf # EC2インスタンスファイルは1つの main.tf にまとめることもできるが、リソース種別で分割するとコードが見つけやすく、レビューもしやすくなる。どちらでも動作は同じだ。
VPCとサブネットの定義
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-vpc"
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-public-subnet"
}
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-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.main.id
}
tags = {
Name = "${var.project_name}-rtb-public"
}
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}aws_vpc.main.id のように リソースタイプ.リソース名.属性名 でリソース間を参照できる。ハードコードしたIDを書く必要がなく、依存関係も自動解決される。
セキュリティグループ
resource "aws_security_group" "web" {
name = "${var.project_name}-web-sg"
description = "Web server security group"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.my_ip]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-web-sg"
}
}SSHのingressは var.my_ip で自分のIPアドレスのみに絞ることを強く推奨する。0.0.0.0/0 を開放したままにしておくと、ブルートフォース攻撃の標的になる。
EC2インスタンス
data "aws_ami" "amazon_linux_2023" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux_2023.id
instance_type = var.instance_type
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web.id]
key_name = var.key_pair_name
tags = {
Name = "${var.project_name}-web"
}
}variable "aws_region" {
description = "AWSリージョン"
type = string
default = "ap-northeast-1"
}
variable "project_name" {
description = "プロジェクト名(リソース名のプレフィックスに使用)"
type = string
default = "myapp"
}
variable "instance_type" {
description = "EC2インスタンスタイプ"
type = string
default = "t3.micro"
}
variable "key_pair_name" {
description = "EC2キーペア名"
type = string
}
variable "my_ip" {
description = "SSH接続を許可するIPアドレス(/32形式)"
type = string
}output "instance_public_ip" {
description = "EC2パブリックIPアドレス"
value = aws_instance.web.public_ip
}
output "vpc_id" {
description = "VPC ID"
value = aws_vpc.main.id
}変数は terraform.tfvars ファイルに定義して渡すか、apply時に -var="key_pair_name=my-key" のように渡す。terraform.tfvars は .gitignore に入れてリポジトリに含めないこと。
tfstateをS3 + DynamoDBで管理する(チーム開発必須)
TerraformはインフラのCurrentな状態をtfstateファイルに記録する。このファイルがなければTerraformは「今何があるか」を判断できない。
デフォルトではローカルの terraform.tfstate に保存されるが、チーム開発ではこれが重大な問題を引き起こす。
| 問題 | 詳細 |
|---|---|
| 競合 | 複数人が同時にapplyするとstateが壊れる |
| 紛失 | ローカルPCが壊れるとstateが消える |
| 共有不可 | チームメンバーが現在のインフラ状態を確認できない |
| セキュリティ | tfstateにはARN・IP・パスワードが含まれることがある |
S3 + DynamoDBでremote backendを設定することでこれらの問題を一気に解決できる。
backend用のS3・DynamoDBを作成する
backendリソース自体はTerraformで管理できない(鶏と卵の問題)ため、初回のみ手動で作成するか別のTerraform workspaceで管理する。
resource "aws_s3_bucket" "tfstate" {
bucket = "myapp-tfstate-${data.aws_caller_identity.current.account_id}"
}
resource "aws_s3_bucket_versioning" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_dynamodb_table" "tfstate_lock" {
name = "myapp-tfstate-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
data "aws_caller_identity" "current" {}backendの設定
terraform {
backend "s3" {
bucket = "myapp-tfstate-123456789012"
key = "prod/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
dynamodb_table = "myapp-tfstate-lock"
}
}terraform init を再実行するとstateがS3に移行される。以降はapplyのたびにDynamoDBでロックが取得され、同時実行による競合を防げる。
環境別にkeyを分ける
key = "prod/terraform.tfstate" のように環境ごとに異なるkeyを設定すると、同じS3バケットで本番・ステージング・開発のstateを安全に管理できる。
モジュールでコードを再利用する
複数の環境(本番・ステージング・開発)を管理するとき、同じコードをコピペするのは危険だ。片方を直して片方を忘れる「ドリフト」が発生しやすい。モジュールを使って共通部分を一元管理しよう。
モジュールの基本構成
terraform/
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── ec2/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── environments/
├── prod/
│ ├── main.tf
│ └── terraform.tfvars
└── staging/
├── main.tf
└── terraform.tfvarsmodule "vpc" {
source = "../../modules/vpc"
project_name = "myapp"
vpc_cidr = "10.0.0.0/16"
environment = "prod"
}
module "web" {
source = "../../modules/ec2"
project_name = "myapp"
subnet_id = module.vpc.public_subnet_id
security_groups = [module.vpc.web_sg_id]
environment = "prod"
}module "vpc" {
source = "../../modules/vpc"
project_name = "myapp"
vpc_cidr = "172.16.0.0/16"
environment = "staging"
}変数を変えるだけで同一モジュールから異なる環境を作れる。本番・ステージングの構成ずれがコードレベルで防止できる。
Terraform Registryの公式モジュールを活用する
自分でモジュールをゼロから書かなくても、Terraform Registryにはコミュニティが作成した高品質なモジュールが多数公開されている。VPC・EKS・RDSなどの複雑なリソースは公式モジュールを使うのが現場の定石だ。
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "myapp-vpc"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a", "ap-northeast-1c"]
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.11.0/24", "10.0.12.0/24"]
enable_nat_gateway = true
}ベストプラクティスが組み込まれており、マルチAZ・NAT Gateway・タグ設定などを数行で実現できる。自前実装より安全で保守コストも低い。
GitHub ActionsでCI/CDを組む
チーム開発ではPRをトリガーに terraform plan を自動実行し、レビュワーが差分を確認できる状態にするのが標準フローだ。手動でplanを貼り付けるコミュニケーションコストをゼロにできる。
name: Terraform CI
on:
pull_request:
branches: [main]
paths:
- 'terraform/**'
jobs:
plan:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.14.0
- name: Terraform Init
run: terraform init
working-directory: terraform/environments/prod
- name: Terraform Plan
id: plan
run: terraform plan -no-color 2>&1
working-directory: terraform/environments/prod
- name: Comment Plan Result on PR
uses: actions/github-script@v7
if: always()
with:
script: |
const output = `#### Terraform Plan 📋
\`\`\`
${{ steps.plan.outputs.stdout }}
\`\`\``;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
});注意:アクセスキーを使わない
GitHub ActionsのAWS認証はIAM OIDCを使うのが必須。AWS_ACCESS_KEY_ID を Secrets に入れる方法は非推奨。OIDCなら短命トークンで安全に認証でき、キーローテーションも不要になる。
mainブランチへのマージ後に terraform apply を自動実行するステップを追加することで、完全なCI/CDパイプラインが完成する。ただし本番環境への自動applyは慎重に検討すること。
学習ロードマップとおすすめUdemyコース
Terraformを体系的に習得するためのロードマップを示す。AWS自体の基礎知識(VPC・EC2・S3・IAM)があることが前提になる。まだの場合はクラウドエンジニア学習ロードマップ2026を先に読んでおくといい。
【PHASE 1: 基礎固め(2〜3週間)】
HCLの文法・基本コマンドを理解する
ローカルtfstateでVPC・EC2を動かしてみる
terraform destroyまで通しで体験する
【PHASE 2: 実践(1〜2ヶ月)】
remote backend(S3 + DynamoDB)を設定する
モジュール化でコードを整理する
本記事のサンプルを自分の環境で再現する
【PHASE 3: チーム開発対応(継続)】
GitHub ActionsでCI/CDを組む
コードレビューの観点を身につける
Terraform Associate資格を取得するTerraform Associateとは
HashiCorpが提供する**Terraform Associate(003)**はインフラエンジニアの実力証明として転職・副業市場で有効だ。AWSのクラウド認定資格と組み合わせると市場価値がさらに上がる。
| 項目 | 内容 |
|---|---|
| 試験形式 | オンライン、57問 |
| 合格ライン | 70%以上 |
| 受験料 | $70.50(USD) |
| 有効期限 | 2年間 |
| 出題範囲 | IaC概念・CLI・HCL・ステート管理・モジュール・ワークフロー |
おすすめUdemyコース
体系的にインプットするならUdemyの動画コースが最も効率がいい。セール時(1,500〜2,000円)を狙うと費用対効果が高い。「Terraform AWS」で検索すると**「AWS と Terraform で実現する Infrastructure as Code」や「Terraform 入門ハンズオン with AWS」**といった日本語コースが複数見つかる。ハンズオン形式で実際に手を動かしながら学べるものを選ぶと定着が早い。
Udemy で Terraform コースを探す →
よくある質問(FAQ)
Q. Terraform と AWS CloudFormation、どちらを覚えるべきですか?
AWS専業の現場ならCloudFormationでも十分だが、転職市場での汎用性を考えるとTerraformを優先すべきだ。TerraformはマルチクラウドでAWS・GCP・Azureを横断するプロジェクトでも同じ知識を活かせる。採用面接でもTerraformの経験は評価が高い。CloudFormationはAWSコンソールを使いこなしている前提があれば1〜2週間で習得できるため、Terraform後に補完として学ぶのが効率的だ。
Q. tfstateファイルはgitに含めていいですか?
含めてはいけない。tfstateにはリソースのARN・パスワード・シークレットが平文で入ることがある。必ず .gitignore に *.tfstate と *.tfstate.backup を追加すること。管理は必ずS3 backendで行う。もし誤ってコミットしてしまった場合は、git filter-branch または git filter-repo で履歴から削除する必要がある。
Q. terraform destroy を間違えて本番で実行してしまいました。防ぐ方法は?
重要なリソースには lifecycle { prevent_destroy = true } を設定しておくのが定石だ。
resource "aws_rds_cluster" "main" {
# ...省略
lifecycle {
prevent_destroy = true
}
}さらに本番AWSアカウントではIAM権限でdelete系アクションを制限しておくことを強く推奨する。destroy を実行しようとするとプランの段階でエラーになり、事故を未然に防げる。
Q. Terraformの学習にどれくらいの時間がかかりますか?
バックエンド・インフラの実務経験があれば1〜2ヶ月で現場レベルに到達できる。HCLの文法はYAML・JSONに慣れていれば1週間で読めるようになる。AWS基礎知識(VPC・EC2・S3・IAM)があることが前提になるため、まだの場合は先にAWS入門から始めること。
Q. モジュールはいつから使い始めるべきですか?
最初からモジュールを作ろうとする必要はない。同じパターンが3回出てきたらモジュール化というルールが現場での目安だ。最初から抽象化しすぎると複雑さが上がり、かえって管理しにくくなる。まず動くコードを書き、繰り返しが発生してからリファクタリングする。
Q. Xserver VPS上でTerraformを使って本番構成を管理できますか?
Terraformは基本的にAWS・GCP・AzureなどのパブリッククラウドのAPIに対して動作する。XserverやConoHaのVPSはTerraformプロバイダーが提供されていない場合が多いため、VPS上にアプリをデプロイする部分はAnsibleやDockerを使うのが一般的だ。Xserver VPSのDockerセットアップも合わせて参照してほしい。
Q. OpenTofuに移行すべきですか?
既存のTerraformコードベースがある場合、移行コストに見合うメリットは現時点では少ない。新規プロジェクトでOSSライセンスにこだわる場合はOpenTofuの採用も選択肢に入れていい。コマンド・構文・プロバイダーはTerraformと互換性があるため、本記事の内容はどちらでも適用できる。
まとめ:今日からできるアクション
tfenvをインストールしてTerraformの動作環境を作る- サンプルコードでVPC + EC2を構築し、
terraform destroyまで通しで実行する - S3 + DynamoDBでremote backendを設定し、ローカルstateを卒業する
- モジュール化でコードを整理し、本番・ステージング環境を分離する
- GitHub Actionsで
terraform planを自動化し、PRレビューに組み込む - Udemyの動画コースで体系的にインプットし、Terraform Associateを目指す
コンソール手動構築からの脱却は、自社開発チームへの転職・副業案件の獲得・現場での評価向上に直結する。まずは手元のAWSアカウントで一度動かしてみることが最短の近道だ。
Udemy で Terraform コースを探す →