【AWSチュートリアル】ネットワークを作ってみよう!②

aws-network-02AWS

前回から引き続き、AWS上にネットワークを構築していきます。

今回使用するコードは以下になります。ご参考まで!

GitHub - katsuya-yamaguchi/study-infra-aws-tutorial at blog/002
Contributetokatsuya-yamaguchi/study-infra-aws-tutorialdevelopmentbycreatinganaccountonGitHub.

前提

  1. 前回までの記事を読んでいること!

今回の目標

AWS内にネットワークを構築します。作成するリソースは以下の通り。

  • ルートテーブル
  • NATゲートウェイ
  • インターネットゲートウェイ
archtecture

インターネットゲートウェイとは?

インターネットゲートウェイは、VPCとインターネット間の通信を可能にするコンポーネントです。内部では、プライベートIPとパブリックIP or ElPのNAT変換を行い、インターネットと通信しています。

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

インターネットゲートウェイを作成する。

パブリックサブネットからインターネットにアクセスできるように、インターネットゲートウェイを作成していきます。

使用するリソースは aws_internet_gateway です。

network/modules/gateway.tf

resource "aws_internet_gateway" "study_infra" {
  vpc_id = aws_vpc.study_infra.id
  tags = {
    Name = var.common_tags["System"]
  }
}

インターネットゲートウェイを作成するVPCとの紐付け、Nameタグの設定を行っています。

NATゲートウェイとは?

NATゲートウェイを利用することで、本来インターネットにアクセスできないサブネット(プライベートサブネット)がアクセスできるようになります。また、インターネットにはプライベートサブネットからアクセスしつつ、インターネット側からのアクセスを拒否することが可能になりセキュアな環境を作成することができます

NATゲートウェイはAZ障害に備え、AZ毎に1台ずつ作成することが推奨されているため今回は2台作成します。

NATゲートウェイ

EIPを作成する。

NATゲートウェイには、EIPを付与する必要があります。そのため、まずはEIPを作成します。

使用するリソースは aws_eip です。

network/gateway.tf

resource "aws_eip" "nat_gateway_public_a" {
  count = abs(var.public_subnets.public_a["nat_gateway_count"]) == 0 ? 0 : 1

  # VPCで使用するためtrueを設定。
  vpc = true
  tags = {
    Name = var.public_subnets.public_a["name"]
  }
}

resource "aws_eip" "nat_gateway_public_c" {
  count = abs(var.public_subnets.public_c["nat_gateway_count"]) == 0 ? 0 : 1

  vpc = true
  tags = {
    Name = var.public_subnets.public_c["name"]
  }
}

ポイントは count = ~ の部分。

NATゲートウェイは作成するだけで費用が発生します。そのため、変数で作成有無を簡単に選択できるようにしたいと思います。これは、NATゲートウェイに関連するEIPやルーティング設定も同様です。(NATゲートウェイを作成しない場合は関連のリソースも作成しない!のように。)

count = abs(var.public_subnets.public_a["nat_gateway_count"]) == 0 ? 0 : 1

これは、以下の nat_gateway_count の値が「0」ならcountに「0」を設定する(「=EIPを作成しない」となります。)。 nat_gateway_count の値が「1」ならcountに「1」を設定します。(「=EIPを作成する」となります。)

network/staging/variables.tf

variable "public_subnets" {
  type = map(map(string))
  default = {
    public_a = {
      name              = "public-a"
      cidr              = "20.0.1.0/24"
      az                = "ap-northeast-1a"
      **nat_gateway_count** = 0
    }
    public_c = {
      name              = "public-c"
      cidr              = "20.0.2.0/24"
      az                = "ap-northeast-1c"
      **nat_gateway_count** = 0
    }
  }
}

NATゲートウェイを作成する。

NATゲートウェイは冗長化のために2台作成します。

使用するリソースは aws_nat_gateway です。

network/modules/gateway.tf

resource "aws_nat_gateway" "public_a" {
  count = abs(var.public_subnets.public_a["nat_gateway_count"]) == 0 ? 0 : 1

  # 紐付けるEIPを設定します。EIPはcountを使って作成しているため、インデックスが必要です。
  # aws_eip.nat_gateway_public_a**[0] ← この部分。**
  allocation_id     = aws_eip.nat_gateway_public_a[0].id

  # インターネットの接続にNATゲートウェイを使用したいので、publicタイプを選択します。
  connectivity_type = "public"

  # NATゲートウェイを作成するサブネットを指定します。
  subnet_id         = aws_subnet.public["public_a"].id
  tags = {
    Name = var.public_subnets.public_a["name"]
  }
}

resource "aws_nat_gateway" "public_c" {
  count = abs(var.public_subnets.public_c["nat_gateway_count"]) == 0 ? 0 : 1

  allocation_id     = aws_eip.nat_gateway_public_c[0].id
  connectivity_type = "public"
  subnet_id         = aws_subnet.public["public_c"].id
  tags = {
    Name = var.public_subnets.public_c["name"]
  }
}

ルートテーブルを作成する。

ここまでで、インターネットゲートウェイやNATゲートウェイを作成しました。

まだ、ルートテーブルを作成していないので、このままではそれぞれ通信することができません。そのため、ルートテーブルを作成していきます。

使用するリソースは3つ。

1つ目は、ルートテーブルの作成に必要な aws_route_table

2つ目は、ルートテーブルに登録するルート設定に必要な aws_route

3つ目は、ルートテーブルとサブネットの紐付けに必要な aws_route_table_association

まずは、以下のルートテーブルを作成します。

  • パブリックサブネットに紐付けるルートテーブルを1つ。AZ毎にサブネットは作成していますが、ルートテーブルは共通のものを使用する。
  • プライベートサブネットに紐付けるルートテーブル。AZ毎にルートテーブルを作成します。というのも、NATゲートウェイをAZ毎に作成するため、同じAZに存在するNATゲートウェイにルーティングするようにしたいため。
  • セキュアサブネットに紐付けるルートテーブルを1つ。AZ毎にサブネットは作成していますが、ルートテーブルは共通のものを使用する。

network/modules/route_table.tf

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.study_infra.id
  tags = {
    Name = "public"
  }
}

resource "aws_route_table" "private_a" {
  vpc_id = aws_vpc.study_infra.id
  tags = {
    Name = "private-a"
  }
}

resource "aws_route_table" "private_c" {
  vpc_id = aws_vpc.study_infra.id
  tags = {
    Name = "private-c"
  }
}

resource "aws_route_table" "secure" {
  vpc_id = aws_vpc.study_infra.id
  tags = {
    Name = "secure"
  }
}

vpc_id でルートテーブルを作成するVPCを指定します。

続いて、各ルートテーブルに以下のルーティング設定を追加していきます。

サブネットルートテーブルの内容
①パブリックサブネット全ての送信はインターネットゲートウェイに行くようにする。
②プライベートサブネット(ap-northeast-1a)全ての送信はap-northeast-1aのNATゲートウェイに行くようにする。
③プライベートサブネット(ap-northeast-1c)全ての送信はap-northeast-1cのNATゲートウェイに行くようにする。

network/modules/route_table.tf

# ①パブリックサブネット
resource "aws_route" "to_internet_gateway" {
  route_table_id         = aws_route_table.public.id

  # 送信先のCIDR。全ての通信のため「0.0.0.0/0」を設定。
  destination_cidr_block = "0.0.0.0/0"

  # インターネットゲートウェイに向くように、gateway_idにインターネットゲートウェイを設定。
  gateway_id = aws_internet_gateway.study_infra.id
}

# ②プライベートサブネット(ap-northeast-1a)
resource "aws_route" "private_a_to_nat_gateway" {
  # NATゲートウェイを作成しない場合は、このルーティング設定も作成しない。
  count = var.public_subnets.public_a["nat_gateway_count"] == "0" ? 0 : 1

  route_table_id         = aws_route_table.private_a.id
  destination_cidr_block = "0.0.0.0/0"

  # NATゲートウェイを向くように、nat_gateway_idにNATゲートウェイを設定。
  nat_gateway_id         = aws_nat_gateway.public_a[0].id
}

# ③プライベートサブネット(ap-northeast-1c)
resource "aws_route" "private_c_to_nat_gateway" {
  count = var.public_subnets.public_c["nat_gateway_count"] == "0" ? 0 : 1

  route_table_id         = aws_route_table.private_c.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.public_c[0].id
}

インターネットゲートウェイとNATゲートウェイで設定する項目が微妙に異なるのでご注意を( gateway_idnat_gateway_id )!

最後にルートテーブルとサブネットの紐付けします。

network/modules/route_table.tf

resource "aws_route_table_association" "public" {
  # 前回記事で紹介したfor_eachを使用。変数をループさせてコードの効率化を図っています。
  # https://study-infra.com/aws-network-01/
  for_each       = var.public_subnets
  subnet_id      = aws_subnet.public[each.key].id
  route_table_id = aws_route_table.public.id
}

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

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

resource "aws_route_table_association" "secure" {
  for_each       = var.secure_subnets
  subnet_id      = aws_subnet.secure[each.key].id
  route_table_id = aws_route_table.secure.id
}

それでは作成したコードを適用していきたいと思います。

Terraformの実行

1. network/staging/variables.tf のNATゲートウェイの数をそれぞれ「1」に設定する。

variable "public_subnets" {
  type = map(map(string))
  default = {
    public_a = {
      name              = "public-a"
      cidr              = "20.0.1.0/24"
      az                = "ap-northeast-1a"
      nat_gateway_count = 1 ★この部分
    }
    public_c = {
      name              = "public-c"
      cidr              = "20.0.2.0/24"
      az                = "ap-northeast-1c"
      nat_gateway_count = 1 ★この部分
    }
  }
}

2. terraform plan を実行する。

planの結果、エラーが無いようであればOKです。

$ terraform plan

...

Plan: 18 to add, 0 to change, 0 to destroy.

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
$

3. terraform apply を実行してリソースを構築する。

$ terraform apply

...

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes ←入力してEnterキーを押下!

...

Apply complete! Resources: 18 added, 0 changed, 0 destroyed.

4. network/staging/variables.tf のNATゲートウェイの数をそれぞれ「0」に設定する。(コスト削減のため、利用しないときは削除する。)

variable "public_subnets" {
  type = map(map(string))
  default = {
    public_a = {
      name              = "public-a"
      cidr              = "20.0.1.0/24"
      az                = "ap-northeast-1a"
      nat_gateway_count = 1 ★この部分
    }
    public_c = {
      name              = "public-c"
      cidr              = "20.0.2.0/24"
      az                = "ap-northeast-1c"
      nat_gateway_count = 1 ★この部分
    }
  }
}

5. terraform destroy を実行する。

$ terraform apply

...

Plan: 0 to add, 0 to change, 6 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

...

Apply complete! Resources: 0 added, 0 changed, 6 destroyed.
$

NATゲートウェイ、NATゲートウェイを指定したルート、EIPが削除されます。

以上で、前回から作成してきたネットワークが構築できました。

次回は、ECSを使ったサーバー構築をやっていきたいと思います。

これにて本記事は終了です。

コメント

タイトルとURLをコピーしました