GeekFactory

int128.hatenablog.com

TerraformでプライベートサブネットとNATゲートウェイを管理する

AWSのNATゲートウェイ構成をTerraformで管理する方法を調べたのでまとめます。

NATゲートウェイ構成とは下記のような構成を指します。

次の図は、NAT ゲートウェイを使用した VPCアーキテクチャを示しています。メインルートテーブルは、プライベートサブネットのインスタンスから NAT ゲートウェイにインターネットトラフィックを送信します。NAT ゲートウェイは、NAT ゲートウェイの Elastic IP アドレスをソース IP アドレスとして使用し、インターネットゲートウェイトラフィックを送信します。

https://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/images/nat-gateway-diagram.png https://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpc-nat-gateway.html

マネジメントコンソールでNATゲートウェイを構成する場合は以下の流れで行います。パブリックサブネットはすでに存在する前提です。

  1. プライベートサブネットを作成する。
  2. EIPを確保する。
  3. パブリックサブネットにNATゲートウェイを作成する。
  4. ルートテーブルを作成し、デフォルトゲートウェイをNATゲートウェイに向ける。
  5. プライベートサブネットにルートテーブルをアタッチする。

Terraformの場合は以下のリソースを定義します。

  • プライベートサブネット (aws_subnet)
  • EIP (aws_eip)
  • NATゲートウェイ (aws_nat_gateway)
  • ルートテーブル (aws_route_table)
  • ルートテーブルの関連付け (aws_route_table_association)

実装例

具体的なコードを見ていきましょう。

説明を簡単にするため、ここではVPCとパブリックサブネットがすでに存在しており、そこにNATゲートウェイを付け加える場面を考えます。

# すでに存在するVPCを参照
data "aws_vpc" "example" {
  tags {
    Name = "example_vpc"
  }
}

# すでに存在するパブリックサブネットを参照
data "aws_subnet" "public" {
  vpc_id            = "${data.aws_vpc.example.id}"

  tags {
    Name = "example_public_subnet"
  }
}

resource "aws_subnet" "private" {
  vpc_id     = "${data.aws_vpc.example.id}"
  cidr_block = "${cidrsubnet(data.aws_vpc.example.cidr_block, 3, 4)}"

  tags {
    Name = "example_private_subnet"
  }
}

resource "aws_eip" "nat_gateway" {
  vpc = true

  tags {
    Name = "example_nat_gateway_eip"
  }
}

resource "aws_nat_gateway" "private" {
  allocation_id = "${aws_eip.nat_gateway.id}"
  subnet_id     = "${data.aws_subnet.public.id}"

  tags {
    Name = "example_nat_gateway"
  }
}

resource "aws_route_table" "private" {
  vpc_id = "${aws_subnet.private.vpc_id}"

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = "${aws_nat_gateway.private.id}"
  }

  tags {
    Name = "example_private_subnet_route_table"
  }
}

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

サブネットのCIDRはべた書きしてもよいですが、ここでは cidrsubnet() を使ってVPC CIDRから自動計算しています。以下のように記述すると、VPC CIDRの上位3ビットをサブネットに確保します。

  cidr_block = "${cidrsubnet(data.aws_vpc.example.cidr_block, 3, 0)}"

例えば、VPC CIDRが 172.20.0.0/16 の場合、サブネットのCIDRは 172.20.0.0/19 が割り当てられます。サブネットマスク長が16 + 3 = 19になるということです。

  cidr_block = "${cidrsubnet(data.aws_vpc.example.cidr_block, 3, 4)}"

と記述すると、サブネットのCIDRは 172.20.128.0/19 が割り当てられます。/16 の上位3ビットに4(100)を割り当てるので128(1000 0000)になるということです。説明が難しい。

まとめ

TerraformでプライベートサブネットとNATゲートウェイを定義するのは意外と簡単でした。

See Also: