LoginSignup
28
23

Terraformを使ってAWSのVPCをはじめとしたネットワークを構築しよう!

Last updated at Posted at 2023-01-08

概要

今回はTerraformを使って

  • VPC
  • パブリックサブネットとプライベートサブネット
  • IGW
  • ルートテーブルおよびルーティングの設定
  • Elastic IP
  • NATゲートウェイ

を構築したいと思います
今回作成するインフラ構成は下記の図のようになります
terraform-vpc.drawio.png

前提

  • 東京リージョンを使用
  • AWSを使用
  • main.tfとvariables.tfを設定済み
  • ネットワークに関する基本的な知識をある程度持っている

上記のファイルをまだ作成していない方は下記の記事を参考にしてください

AWSにおけるネットワークの概要について知りたい方は以下の記事を参考にしてください

また、コンテナ経由でTerraformを使用すると複数ブロジェクトで使用する際にバージョンによる違いを意識せずに済みます
コンテナを使用したい方はこちらの記事も参考にしてみてください

ディレクトリ構成

構成は以下の通りです

tree 
.
├── main.tf
├── network.tf
└── variables.tf

network.tfにネットワーク関連の設定を記載していきます

network.tf

network.tf
# ------------------------------
# VPC Configuration
# ------------------------------
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  # DNSによる名前解決をサポートする
  enable_dns_support = true
  # パブリックIPアドレスを持つインスタンスが対応するDNSホスト名を取得できるよう明示する
  enable_dns_hostnames = true

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-vpc" })
  )
}

# ------------------------------
# Internert Gateway Configuration
# ------------------------------
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-igw" })
  )
}

# ------------------------------
# Public Subnet Configuration
# ------------------------------
resource "aws_subnet" "public_a" {
  cidr_block = "10.0.1.0/24"
  # サブネットに配置されたインスタンスにパブリックIPアドレスが付与される
  map_public_ip_on_launch = true
  vpc_id                  = aws_vpc.main.id
  availability_zone       = "${data.aws_region.current.name}a"

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-a" })
  )
}

# ルートテーブルの設定
resource "aws_route_table" "public_a" {
  vpc_id = aws_vpc.main.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-a-rt" })
  )
}

# ルートテーブルをパブリックサブネットaと紐付ける
# タグをサポートしてないのでつけない
resource "aws_route_table_association" "public_a" {
  subnet_id      = aws_subnet.public_a.id
  route_table_id = aws_route_table.public_a.id
}

# IGWへのルーティングを設定
# タグをサポートしてないのでつけない
resource "aws_route" "public_internet_access_a" {
  route_table_id = aws_route_table.public_a.id
  # インターネット(0.0.0.0/0)へのアクセスを許可
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id
}

# NATゲートウェイ用のElasticIPをpublic_a内に作成
resource "aws_eip" "public_a" {
  # EIPはVPC内に存在する
  vpc = true

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-a-eip" })
  )
}

# NATゲートウェイ
resource "aws_nat_gateway" "public_a" {
  # パブリックサブネットaに作成したElasticIPをNATに割り当てる(allocateする)
  allocation_id = aws_eip.public_a.id
  subnet_id     = aws_subnet.public_a.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-a-ngw" })
  )
}

resource "aws_subnet" "public_c" {
  cidr_block = "10.0.2.0/24"
  # サブネットに配置されたインスタンスにパブリックIPアドレスが付与される
  map_public_ip_on_launch = true
  vpc_id                  = aws_vpc.main.id
  availability_zone       = "${data.aws_region.current.name}c"

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-c" })
  )
}
resource "aws_route_table" "public_c" {
  vpc_id = aws_vpc.main.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-c-rt" })
  )
}

resource "aws_route_table_association" "public_c" {
  subnet_id      = aws_subnet.public_c.id
  route_table_id = aws_route_table.public_c.id
}

resource "aws_route" "public_internet_access_c" {
  route_table_id         = aws_route_table.public_c.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id
}

resource "aws_eip" "public_c" {
  vpc = true

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-c-eip" })
  )
}

resource "aws_nat_gateway" "public_c" {
  allocation_id = aws_eip.public_c.id
  subnet_id     = aws_subnet.public_c.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-c-ngw" })
  )
}
# ------------------------------
# Private Subnet Configuration
# ------------------------------
resource "aws_subnet" "private_a" {
  cidr_block        = "10.0.11.0/24"
  vpc_id            = aws_vpc.main.id
  availability_zone = "${data.aws_region.current.name}a"

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-private-a" })
  )
}

resource "aws_route_table" "private_a" {
  vpc_id = aws_vpc.main.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-private-a-rt" })
  )
}

resource "aws_route_table_association" "private_a" {
  subnet_id      = aws_subnet.private_a.id
  route_table_id = aws_route_table.private_a.id
}

resource "aws_route" "private_a_internet_out" {
  route_table_id = aws_route_table.private_a.id
  # インターネットへのアウトバウンドアクセスを可能にするためにNATの設定を行う
  nat_gateway_id         = aws_nat_gateway.public_a.id
  destination_cidr_block = "0.0.0.0/0"
}

resource "aws_subnet" "private_c" {
  cidr_block        = "10.0.12.0/24"
  vpc_id            = aws_vpc.main.id
  availability_zone = "${data.aws_region.current.name}c"

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-private-c" })
  )
}

resource "aws_route_table" "private_c" {
  vpc_id = aws_vpc.main.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-private-c-rt" })
  )
}

resource "aws_route_table_association" "private_c" {
  subnet_id      = aws_subnet.private_c.id
  route_table_id = aws_route_table.private_c.id
}

resource "aws_route" "private_c_internet_out" {
  route_table_id = aws_route_table.private_c.id
  # インターネットへのアウトバウンドアクセスを可能にするためにNATの設定を行う
  nat_gateway_id         = aws_nat_gateway.public_c.id
  destination_cidr_block = "0.0.0.0/0"
}

VPC

VPCには10.0.0.0/16を割り当てます
また、

  • DNSによる名前解決
  • パブリックIPアドレスを持つインスタンスが対応するDNSホスト名を取得

する設定を有効化します

network.tf
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  # DNSによる名前解決をサポートする
  enable_dns_support = true
  # パブリックIPアドレスを持つインスタンスが対応するDNSホスト名を取得できるよう明示する
  enable_dns_hostnames = true

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-vpc" })
  )
}

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

VPC内にインターネットゲートウェイがないとパブリックサブネットからインターネットへアクセスできないので作成します
その際にVPCのIDと紐付けます

network.tf
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-igw" })
  )
}

パブリックサブネット

今回は

  • public_a
  • public_c

の2種類のサブネットを作成します
構成は以下の通りです

パブリックサブネット public_a public_c
IPレンジ 10.0.1.0/24 10.0.2.0/24
AZ ap-northeast-1a ap-northeast-1c

AZ内にパブリックサブネットを作成し、サブネットをVPCのIDと紐付けます

resource "aws_subnet" "public_a" {
  cidr_block = "10.0.1.0/24"
  # サブネットに配置されたインスタンスにパブリックIPアドレスが付与される
  map_public_ip_on_launch = true
  vpc_id                  = aws_vpc.main.id
  availability_zone       = "${data.aws_region.current.name}a"

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-a" })
  )
}

パブリックサブネットのルーティングの設定

  • aws_route_table
  • aws_route_table_association
  • aws_route

を設定します

ルートテーブルをどの

  • サブネット
  • VPC
  • インタネットゲートウェイ

と紐づけるかと

  • ルーティング(パブリックなのですべてのIPアドレスを許可)

を設定する必要があります

# ルートテーブルの設定
resource "aws_route_table" "public_a" {
  vpc_id = aws_vpc.main.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-a-rt" })
  )
}

# ルートテーブルをパブリックサブネットaと紐付ける
# タグをサポートしてないのでつけない
resource "aws_route_table_association" "public_a" {
  subnet_id      = aws_subnet.public_a.id
  route_table_id = aws_route_table.public_a.id
}

# IGWへのルーティングを設定
# タグをサポートしてないのでつけない
resource "aws_route" "public_internet_access_a" {
  route_table_id = aws_route_table.public_a.id
  # インターネット(0.0.0.0/0)へのアクセスを許可
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id

NATの設定

NATゲートウェイはブライベートサブネットのインスタンスが使用するのでパブリックサブネット側で設定をします
パブリックサブネット内にNATゲートウェイとNATゲートウェイに割り当てるElasticIPを作成します

# NATゲートウェイ用のElasticIPをpublic_a内に作成
resource "aws_eip" "public_a" {
  # EIPはVPC内に存在する
  vpc = true

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-a-eip" })
  )
}

# NATゲートウェイ
resource "aws_nat_gateway" "public_a" {
  # パブリックサブネットaに作成したElasticIPをNATに割り当てる(allocateする)
  allocation_id = aws_eip.public_a.id
  subnet_id     = aws_subnet.public_a.id

  tags = merge(
    local.common_tags,
    tomap({ "Name" = "${local.prefix}-public-a-ngw" })
  )
}

プライベートサブネット

今回は

  • private_a
  • private_c

の2種類のサブネットを作成します
プライベートサブネットのホスト部を11からにしたのは今後パブリックサブネットを追加する際に
ホスト部の1から10までをパブリックサブネットにできて管理しやすいと思ったからです
構成は以下の通りです

プライベートサブネット private_a private_c
IPレンジ 10.0.11.0/24 10.0.12.0/24
AZ ap-northeast-1a ap-northeast-1c

パブリックサブネットでの設定を被る箇所が多いので違うところのみ解説します

プライベートサブネットのルーティングの設定

NATゲートウェイを通じたインターネットへのアウトバウンドアクセスのみ許可します

resource "aws_route" "private_a_internet_out" {
  route_table_id = aws_route_table.private_a.id
  # インターネットへのアウトバウンドアクセスを可能にするためにNATの設定を行う
  nat_gateway_id         = aws_nat_gateway.public_a.id
  destination_cidr_block = "0.0.0.0/24"
}

tagの作成

こちらに関しては任意です
ハードコーディングしてもいいのですが今回はmain.tfで定義した変数を使用します
mergeを使ってmain.tfにあるlocal.common_tags変数に任意の変数を追加します
共通部分は繰り返し使用でき、なおかつ独自の変数を追加できるのでおすすめです

variables.tf
# ------------------------------
# Variables
# ------------------------------

# プリフィックスを設定
variable "prefix" {
  default = "tf-pg"
}

# プロジェクトを識別する一意の識別子を設定
variable "project" {
  default = "terraform-playground"
}

# プロジェクトのオーナーを設定
variable "owner" {
  default = "shun198"
}
main.tf
# ------------------------------
# Locals
# ------------------------------
locals {
  # variables.tfから変数を取得
  # terraformのworkspaceの一覧から該当するworkspace(dev,stg,prdなど)を取得
  prefix = "${var.prefix}-${terraform.workspace}"
  common_tags = {
    Environmnet = terraform.workspace
    Project     = var.project
    Owner       = var.owner
    ManagedBy   = "Terraform"
  }
}

実際に作成してみよう!

フォーマットの修正、validateやplanによる確認が終わったら以下のコマンドで適用します

terraform apply -auto-approve

作成されたか確認してみよう!

  • VPC
  • パブリックとサブネット
  • インターネットげードウェイ
  • ルートテーブル
  • NATゲートウェイ

が作成および該当するタグが付けられていることを確認します

VPC

スクリーンショット 2023-01-08 9.50.01.png

サブネット

スクリーンショット 2023-01-08 9.41.31.png

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

スクリーンショット 2023-01-08 9.49.32.png

ルートテーブル

スクリーンショット 2023-01-08 9.53.21.png
スクリーンショット 2023-01-08 9.53.30.png

ElasticIP

スクリーンショット 2023-01-08 10.08.28.png

NATゲートウェイ

スクリーンショット 2023-01-08 9.47.25.png

スクリーンショット 2023-01-08 9.47.44.png

リソースの削除

使用しないリソースは以下のコマンドで削除しましょう

terraform destroy

まとめ

VPCをはじめとしてネットワークの設定をたった1コマンドで作成できるのは楽でいいですね
ただし、NACLやALBの設定などをしてなくて心もとないので別記事で作成したいと思います

参考

28
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
23