🌎 Terraform で AWS Route Table を作成するシンプルな手順

# 📌 概要

Terraform を使って AWS のルートテーブル (Route Table) を設定する方法 を解説します 🛜

ルートテーブルを設定することで、VPC 内の通信を適切に制御し、インターネットや内部リソースへのルートを定義 できます ✨  

ここでは、パブリックルートテーブル と プライベートルートテーブル の 2 つを作成します！ 🚀

✅ パブリックルートテーブル 
　➡ インターネットゲートウェイを指定し、外部と 直接通信 できるように設定

✅ プライベートルートテーブル 🔒
　➡ NAT の役割をする EC2 インスタンス を経由して外部アクセスを可能にする

# 📌 事前に準備するもの

##### main.tf 

main.tf の作成がまだの方は以下の記事を参考にファイルを作成してください。

https://qiita.com/nobumory/items/624275ac0b08660a2637

##### VPC

VPCを作成していない場合は以下を参考に作成します。

https://qiita.com/nobumory/items/72ab7a109b24b5a08287

##### インターネットゲートウェイ

インターネットゲートウェイを作成していない場合は以下を参考に作成します。

https://qiita.com/nobumory/items/35db2157a1c1c6734363

##### サブネット

サブネットを作成していない場合は以下を参考に作成します。

https://qiita.com/nobumory/items/4626953585c964f12f73

##### EC2インスタンス

EC2インスタンスを作成していない場合は以下を参考に作成します。

https://qiita.com/nobumory/items/1cee486b2e877d91a038

# 📌 ディレクトリ構成

```
terraform-project/
│── main.tf
│── modules/
│   ├── ec2/
│   │   ├── main.tf
│   ├── internet_gateway/
│   │   ├── main.tf
│   ├── route_table/
│   │   ├── main.tf
│   ├── subnet/
│   │   ├── main.tf
│   ├── security_group/
│   │   ├── main.tf
│   ├── vpc/
│   │   ├── main.tf
```

# 📌 コード


### main.tf

AWS のプロバイダーを設定し、Route Table の作成に必要なモジュールを読み込みます。

```hcl
# AWS プロバイダーの設定
provider "aws" {
  region = "ap-northeast-1"
}


# VPC モジュールの読み込み
module "vpc" {
  source = "./vpc"
}


# インターネットゲートウェイのモジュールを読み込み
module "internet_gateway" {
  source = "./internet_gateway"
  vpc_id = module.vpc.vpc_id
}

# サブネットモジュールの読み込み
module "subnet" {
  source = "./subnet"
  vpc_id = module.vpc.vpc_id
}

# セキュリティグループモジュールの読み込み
module "security_group" {
  source = "./security_group"
  vpc_id = module.vpc.vpc_id
}

# EC2 インスタンスモジュールの読み込み
module "ec2" {
  source = "./ec2"
  vpc_id = module.vpc.vpc_id
  subnet_id = module.subnet.subnet_public_id
  public_sg_id = module.security_group.public_sg_id
}

# ルートテーブルモジュールの読み込み
module "route_table" {
  source = "./route_table"
  vpc_id = module.vpc.vpc_id
  subnet_public_id = module.subnet.subnet_public_id
  subnet_private_id = module.subnet.subnet_private_id
  internet_gateway_id = module.internet_gateway.internet_gateway_id
  ec2_primary_network_interface_id = module.ec2.ec2_primary_network_interface_id
}
```

### internet_gateway.tf

Internet Gateway（IGW） を作成し、指定した VPC にアタッチします。

```hcl
# VPC の ID を受け取る変数を定義
variable "vpc_id" {
  description = "Internet Gateway を関連付ける VPC の ID"
  type        = string
}

# Internet Gateway を作成
resource "aws_internet_gateway" "main" {
  vpc_id = var.vpc_id

  tags = {
    # Internet Gateway に "sandbox-terraform" という名前タグを付与
    Name = "sandbox-terraform"
  }
}

# 作成した Internet Gateway の ID を出力
output "internet_gateway_id" {
  value = aws_internet_gateway.main.id
}
```

### security_group/main.tf

```hcl
# VPC の ID を受け取る変数を定義
variable "vpc_id" {
  description = "Internet Gateway を関連付ける VPC の ID"
  type        = string
}

# セキュリティグループを作成
resource "aws_security_group" "public" {
  name        = "sandbox-terraform-public"
  description = "Security group for public EC2 instances"
  vpc_id      = var.vpc_id

  tags = {
    Name = "sandbox-terraform-public"
  }
}

# プライベートSGからの全トラフィックを許可
resource "aws_security_group_rule" "public_private_sg" {
  type                     = "ingress"
  from_port                = 0
  to_port                  = 0
  protocol                 = "-1"
  security_group_id        = aws_security_group.public.id
  source_security_group_id = aws_security_group.private.id
  description              = "Allow all traffic from private security group"
}

# HTTPS (443) を許可
resource "aws_security_group_rule" "public_https" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  security_group_id = aws_security_group.public.id
  cidr_blocks       = ["0.0.0.0/0"]
  description       = "Allow HTTPS from everywhere"
}

# HTTP (80) を許可
resource "aws_security_group_rule" "public_http" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  security_group_id = aws_security_group.public.id
  cidr_blocks       = ["0.0.0.0/0"]
  description       = "Allow HTTP from everywhere"
}

# SSH (22) を許可
resource "aws_security_group_rule" "public_ssh" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  security_group_id = aws_security_group.public.id
  cidr_blocks       = ["0.0.0.0/0"]
  description       = "Allow SSH from everywhere"
}

output "public_sg_id" {
  value = aws_security_group.public.id
}
```

### subnet/main.tf

パブリックサブネット を作成します。

```hcl
# VPC の ID を受け取る変数を定義
variable "vpc_id" {
  description = "Internet Gateway を関連付ける VPC の ID"
  type        = string
}

# サブネットの作成
resource "aws_subnet" "public" {
  vpc_id                  = var.vpc_id
  cidr_block              = "192.168.250.128/25"
  availability_zone       = "ap-northeast-1a"
  tags = {
    Name = "sandbox-terraform-public"
  }
}


# 作成したサブネットの ID を出力し、他のモジュールで利用できるようにする
output "subnet_public_id" {
  value = aws_subnet.public.id
}
```


### ec2/main.tf

EC2 インスタンスを作成し、Elastic IP を関連付けることで、インターネットからアクセスできる Web サーバーとします。

```hcl
# VPC の ID を受け取る変数を定義
variable "vpc_id" {
  description = "Internet Gateway を関連付ける VPC の ID"
  type        = string
}

# サブネット の ID を受け取る変数を定義
variable "subnet_id" {
  description = "Subnet の ID"
  type        = string
}

# セキュリティー の ID を受け取る変数を定義
variable "public_sg_id" {
  description = "Public Security Group の ID"
  type        = string
}

# ------ ec2 の作成

# インスタンスの作成
resource "aws_instance" "ec2" {
  ami                    = "ami-0b28346b270c7b165" # Amazon Linux 2023 の AMI ID
  instance_type          = "t2.nano" # 小規模な開発用インスタンス
  key_name               = "key-name" # SSH キーペアの指定
  subnet_id              = var.subnet_id # 指定したパブリックサブネットに配置
  associate_public_ip_address = true # インターネットに公開するためのパブリック IP を付与
  security_groups        = [var.public_sg_id] # 指定したセキュリティグループを適用

  # ルートボリューム（EBS）の設定
  root_block_device {
    volume_size = 8 # ルートボリュームのサイズ（GB）
    volume_type = "gp2" # 一般的な SSD ストレージ
  }

  tags = {
    Name = "sandbox-terraform-ec2" # EC2 の名前タグ
  }
}

# ------ Elastic IP の作成と関連付け

# Elastic IPの作成
resource "aws_eip" "main" {
  domain = "vpc"
  tags = {
    Name = "sandbox-terraform-eip"
  }
}

# Elastic IP を EC2 インスタンスに関連付け
resource "aws_eip_association" "ec2_eip_assoc" {
  instance_id   = aws_instance.ec2.id
  allocation_id = aws_eip.main.id
}

# -------------------------------- 出力

# EC2 のネットワークインターフェース ID
output "ec2_primary_network_interface_id" {
  value = aws_instance.ec2.primary_network_interface_id
}

# Elastic IP のパブリック IP アドレス
output "ec2_elastic_ip" {
  value = aws_eip.main.public_ip
}

```

### route_table/main.tf

パブリックルートテーブル と プライベートルートテーブル を作成します。

```hcl
# VPC の ID を受け取る変数
variable "vpc_id" {
  description = "Internet Gateway を関連付ける VPC の ID"
  type        = string
}

# パブリックサブネットの ID
variable "subnet_public_id" {
  description = "Subnet の ID"
  type        = string
}

# プライベートサブネットの ID
variable "subnet_private_id" {
  description = "Subnet の ID"
  type        = string
}

# インターネットゲートウェイの ID
variable "internet_gateway_id" {
  description = "Internet Gateway の ID"
  type        = string
}

# EC2 のプライマリネットワークインターフェースの ID（プライベートサブネットのルート先として利用する）
variable "ec2_primary_network_interface_id" {
  description = "EC2 のプライマリネットワークインターフェースの ID"
  type        = string
}

# -------------------------------- ルートテーブル（パブリック）
resource "aws_route_table" "public" {
  vpc_id = var.vpc_id

  route {
    cidr_block = "0.0.0.0/0" # すべての外部ネットワークに適用
    gateway_id = var.internet_gateway_id # インターネットゲートウェイを使用
  }

  tags = {
    Name = "sandbox-terraform-public-route"
  }
}

# -------------------------------- ルートテーブル（プライベート）
resource "aws_route_table" "private" {
  vpc_id = var.vpc_id

  route {
    cidr_block           = "0.0.0.0/0" # すべての外部ネットワークに適用
    network_interface_id = var.ec2_primary_network_interface_id # NAT の役割をする EC2 インスタンスを指定
  }

  tags = {
    Name = "sandbox-terraform-private-route"
  }
}

# -------------------------------- ルートテーブルの関連付け

# Public サブネットと Public ルートテーブルの関連付け
resource "aws_route_table_association" "public" {
  subnet_id      = var.subnet_public_id
  route_table_id = aws_route_table.public.id
}

# Private サブネットと Private ルートテーブルの関連付け
resource "aws_route_table_association" "private" {
  subnet_id      = var.subnet_private_id
  route_table_id = aws_route_table.private.id
}
```


# 📌 実行

準備ができたらコマンド実行しましょう！

1. `terraform init`
2. `terraform plan`
3. `terraform apply`

Terraform関連のコマンドについては以下の記事を参考にしてください ☺️

https://qiita.com/nobumory/items/9f3c84f016fbf37363ed