Terraform AWS入門完全ガイド2026【実務で使う基本構成・サンプルコード一覧・失敗しない初期設定】

IT実務・技術メモ

AWSでインフラを構築したいけど、手作業は煩雑で一貫性がない。そんな課題をTerraformで一気に解決できます。

結論:Terraform×AWSで実務レベルのIaC環境を作るなら、EC2+RDS+S3の基本3構成をコードテンプレートで始めるのがコスパ最強

本記事では、初心者でも即座に実務で使える「Terraform基本構成」を厳選しました。実際のサンプルコード+設定手順+よくある失敗例を網羅しているため、1記事で初期導入~本番運用前までの全フローが完結します。

特に「tfstateファイル管理」「複数環境分け」「セキュリティ設定」の3つは実務で必須ですが、これらをセットで解説している入門記事は少ないため、差分として提供します。

項目 学習コスト 実務適用度 推奨対象
CloudFormation 高(AWS純正) AWS専用を徹底したい企業
Terraform 高(マルチクラウド対応) 汎用性重視・複数クラウド運用
Pulumi プログラミング言語統一したい組織
手動構築 最低 低(再現性なし) 学習用・小規模テスト環境

Terraformがコスパ最強な理由は、無料かつHCL言語がシンプルで、AWS・GCP・Azureなど複数クラウドに対応している点です。

Terraform基本構成を実務レベルで使う4つのステップ

ステップ1:Terraformのセットアップ(Windows・Mac・Linux対応)

まずはTerraformをインストールします。公式サイトから最新版をダウンロードするのが最速です。

# Macの場合(Homebrewで管理)
brew tap hashicorp/tap
brew install hashicorp/tap/terraform

# Windowsの場合(Choco)
choco install terraform

# バージョン確認
terraform version

バージョン確認で「Terraform v1.6.x」以上が表示されれば成功です。次にAWS CLIもセットアップします。これがないとAWSとの連携ができません。

# AWS CLIインストール
brew install awscli

# AWS認証情報を設定
aws configure
# アクセスキー・シークレットキーを入力

IAMユーザーのアクセスキーを取得していない場合は、AWSコンソール→IAM→ユーザー→セキュリティ認証情報から生成してください。

ステップ2:プロジェクトディレクトリの構成(実務標準形式)

Terraformは複数ファイルで構成するため、ディレクトリ設計が重要です。以下の構成が業界標準です。

terraform-aws/
├── main.tf              # メインリソース定義
├── variables.tf         # 変数定義
├── outputs.tf           # 出力値設定
├── terraform.tfvars     # 環境別設定値
├── backend.tf           # 状態ファイル管理
└── environments/        # 本番・ステージ分け
    ├── dev/
    ├── staging/
    └── prod/

この構成で、開発環境と本番環境を簡単に切り替えられます。

ステップ3:実務必須の基本3構成サンプルコード(EC2+RDS+S3)

以下は、Webサーバー(EC2)+データベース(RDS)+ストレージ(S3)の基本構成です。実務で最も使われるパターンです。

main.tf:メインリソース定義

terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
}

# VPC設定
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "${var.environment}-vpc"
  }
}

# パブリックサブネット
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "${var.aws_region}a"
  map_public_ip_on_launch = true

  tags = {
    Name = "${var.environment}-public-subnet"
  }
}

# インターネットゲートウェイ
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.environment}-igw"
  }
}

# セキュリティグループ(EC2用)
resource "aws_security_group" "ec2" {
  name   = "${var.environment}-ec2-sg"
  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.ssh_cidr]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "${var.environment}-ec2-sg"
  }
}

# EC2インスタンス
resource "aws_instance" "web" {
  ami                    = "ami-0c55b159cbfafe1f0"
  instance_type          = var.instance_type
  subnet_id              = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.ec2.id]

  user_data = base64encode(templatefile("${path.module}/user_data.sh", {
    db_endpoint = aws_db_instance.main.endpoint
  }))

  tags = {
    Name = "${var.environment}-web-server"
  }

  depends_on = [aws_db_instance.main]
}

# RDSセキュリティグループ
resource "aws_security_group" "rds" {
  name   = "${var.environment}-rds-sg"
  vpc_id = aws_vpc.main.id

  ingress {
    from_port       = 3306
    to_port         = 3306
    protocol        = "tcp"
    security_groups = [aws_security_group.ec2.id]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "${var.environment}-rds-sg"
  }
}

# RDSインスタンス
resource "aws_db_instance" "main" {
  identifier     = "${var.environment}-mysql-db"
  engine         = "mysql"
  engine_version = "8.0.35"
  instance_class = var.db_instance_class

  allocated_storage = 20
  storage_type      = "gp2"

  db_name  = var.db_name
  username = var.db_username
  password = var.db_password

  vpc_security_group_ids = [aws_security_group.rds.id]
  db_subnet_group_name   = aws_db_subnet_group.main.name

  skip_final_snapshot       = false
  final_snapshot_identifier = "${var.environment}-mysql-final-snapshot"

  tags = {
    Name = "${var.environment}-mysql-db"
  }
}

# DBサブネットグループ
resource "aws_db_subnet_group" "main" {
  name       = "${var.environment}-db-subnet-group"
  subnet_ids = [aws_subnet.public.id]

  tags = {
    Name = "${var.environment}-db-subnet-group"
  }
}

# S3バケット
resource "aws_s3_bucket" "main" {
  bucket = "${var.environment}-app-bucket-${data.aws_caller_identity.current.account_id}"

  tags = {
    Name = "${var.environment}-app-bucket"
  }
}

# S3バージョニング
resource "aws_s3_bucket_versioning" "main" {
  bucket = aws_s3_bucket.main.id

  versioning_configuration {
    status = "Enabled"
  }
}

# S3ブロックパブリックアクセス
resource "aws_s3_bucket_public_access_block" "main" {
  bucket = aws_s3_bucket.main.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

# カレントAWSアカウントID取得
data "aws_caller_identity" "current" {}

variables.tf:変数定義(環境別切り替え用)

variable "aws_region" {
  type        = string
  description = "AWS region"
  default     = "ap-northeast-1"
}

variable "environment" {
  type        = string
  description = "Environment name"
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

variable "instance_type" {
  type        = string
  description = "EC2 instance type"
  default     = "t3.micro"
}

variable "db_instance_class" {
  type        = string
  description = "RDS instance class"
  default     = "db.t3.micro"
}

variable "db_name" {
  type        = string
  description = "Database name"
  sensitive   = true
}

variable "db_username" {
  type        = string
  description = "Database master username"
  sensitive   = true
}

variable "db_password" {
  type        = string
  description = "Database master password"
  sensitive   = true
}

variable "ssh_cidr" {
  type        = string
  description = "CIDR block for SSH access"
  default     = "0.0.0.0/0"
}
🤖 このブログはAIで自動運営しています。 同じ仕組みを御社にも導入できます。 無料相談はこちら
タイトルとURLをコピーしました