DevOctane
TerraformAWSIaCインフラ

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

2026.05.2535 min read
【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に手順書リポジトリ=唯一の情報源
手動構築
属人化・ドリフト
Terraform
HCLでコード定義
AWSリソース
一貫性・再現性

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年現在の比較

Terraform(HashiCorp)
  • ライセンス: BSL 1.1
  • 最新: v1.14.x(2026年)
  • Terraform Registry: 4,800以上のプロバイダー
  • エンタープライズ: HCP Terraform
  • 現場採用率: 依然として最多
OpenTofu(Linux Foundation)
  • ライセンス: MPL 2.0(OSS)
  • Terraform 1.5.x と互換性あり
  • 追加機能: state暗号化・for_each拡張
  • コミュニティ主導で開発継続
  • 新規採用での選択が増加中

どちらを選ぶべきか

既存のTerraform環境で働いているなら: Terraformのまま継続。 BSLはあくまで「HashiCorpと競合するサービス」への制限であり、インフラ管理ツールとして使う分には影響がほぼない。

新規プロジェクトでゼロから始めるなら: OpenTofuも有力な選択肢。 コマンド・構文・プロバイダーはTerraformと互換性があるので、本記事の内容はほぼそのまま適用できる。

この記事ではTerraformで解説するが、OpenTofuユーザーも同じ構文・コマンドで実践できる。


Terraformのインストール

tfenvでバージョン管理する(推奨)

本番環境との乖離を防ぐため、Terraformのバージョン管理ツール tfenv を使う。プロジェクトごとにバージョンを固定できるため、チーム開発での「自分の環境では動くのに」問題を防げる。

tfenvのインストール(macOS)
brew install tfenv
tfenv install 1.14.0
tfenv use 1.14.0
terraform --version
# Terraform v1.14.0
Linuxの場合
git 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 ファイルをリポジトリに含めておくと、全員が同じバージョンを使えるようになる。

.terraform-version
1.14.0

AWSプロバイダーの設定

TerraformはHCL(HashiCorp Configuration Language)という独自言語でインフラを定義する。まずAWSプロバイダーを設定しよう。provider.tfvariables.tf を分けておくと、後からの管理がしやすい。

provider.tf
terraform {
  required_version = ">= 1.9"
 
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}
 
provider "aws" {
  region = var.aws_region
}
variables.tf
variable "aws_region" {
  description = "AWSリージョン"
  type        = string
  default     = "ap-northeast-1"
}

AWS認証の設定

AWS CLIで認証情報を設定
aws configure
# AWS Access Key ID: ...
# AWS Secret Access Key: ...
# Default region name: ap-northeast-1

セキュリティ注意
アクセスキーをコードに直書きしないこと。本番環境ではIAMロールを使った認証が必須。ローカル開発では ~/.aws/credentials にのみ保管し、.gitignore に追加しておくこと。


基本コマンドを覚える

Terraformの作業フローは4ステップで完結する。このサイクルを体に染み込ませることが、Terraform習得の第一歩だ。

1
terraform init
プロバイダープラグインをダウンロード。リポジトリclone後やprovider追加時に実行する
2
terraform plan
実行計画を表示。何が作成・変更・削除されるかをapply前に必ず確認する
3
terraform apply
planの内容を実際にAWSに反映。-auto-approve を付けると確認プロンプトをスキップできる
4
terraform destroy
Terraformで管理しているリソースをすべて削除。学習・検証後は必ず実行してコストを削減する
基本コマンドの実行例
# 初期化(初回または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とサブネットの定義

vpc.tf
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を書く必要がなく、依存関係も自動解決される。

セキュリティグループ

security_group.tf
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インスタンス

ec2.tf
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"
  }
}
variables.tf(全量)
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
}
outputs.tf
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を設定することでこれらの問題を一気に解決できる。

ローカルstate
競合・紛失リスク
S3バケット
tfstateを安全に保管
+
DynamoDB
state lockで競合防止

backend用のS3・DynamoDBを作成する

backendリソース自体はTerraformで管理できない(鶏と卵の問題)ため、初回のみ手動で作成するか別のTerraform workspaceで管理する。

backend-setup/main.tf(初回のみapply)
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の設定

backend.tf
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.tfvars
environments/prod/main.tf
module "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"
}
environments/staging/main.tf
module "vpc" {
  source = "../../modules/vpc"
 
  project_name = "myapp"
  vpc_cidr     = "172.16.0.0/16"
  environment  = "staging"
}

変数を変えるだけで同一モジュールから異なる環境を作れる。本番・ステージングの構成ずれがコードレベルで防止できる。

Terraform Registryの公式モジュールを活用する

自分でモジュールをゼロから書かなくても、Terraform Registryにはコミュニティが作成した高品質なモジュールが多数公開されている。VPC・EKS・RDSなどの複雑なリソースは公式モジュールを使うのが現場の定石だ。

公式VPCモジュールの利用例
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を貼り付けるコミュニケーションコストをゼロにできる。

.github/workflows/terraform.yml
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を先に読んでおくといい。

Terraform習得ロードマップ
【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 } を設定しておくのが定石だ。

destroy保護の設定例
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 コースを探す →

※本リンクはアフィリエイトリンクです