🌏

TerraformでAWSのお気軽VPC/サブネット作り

2024/05/06に公開

はじめに

TerraformでVPCとサブネットを作るのは簡単です。というのも、VPCとサブネットはAWSのリソースの中でも基本的なもので特別な理由がなければ、たいていはデフォルトの設定で問題ないからです。つまりコピペで作れるわけです。

とはいえコピペするにも、変えたい部分がないわけではない、わけです。VPCのCIDRブロックやサブネットのプレフィクス長、リージョンなどです。

コピペを楽にするにはどうすればいいか、という「楽をするための苦労はいとわない」がモットーの私らしいネタだと、個人的には気に入ってます。

コードはこちら

GitHub にコードがあるのでコピーするだけで使えます:
https://github.com/keioni/blog-sample/blob/main/terraform-easy-vpc/main.tf

統一感を気にしなければ、そのまま使ってもいいですし、設計に合わせて変更するのもいいでしょう。

必要な変数は以下の通りです:
https://github.com/keioni/blog-sample/blob/main/terraform-easy-vpc/variables.tf

これらを試してみたいときは、このディレクトリにある README.md を参照してください。

このコードのポイント

サブネットのIPv4プレフィクス長の指定方法

  cidr_block = cidrsubnet(
    var.vpc_cidr_block,
    var.subnet_mask_length - tonumber(regex("[0-9]+$", var.vpc_cidr_block)),
    count.index
  )

ネットワークを扱うとき、CIDRのプレフィクスは、だいたい /24 とか /28 といった形(スラッシュの後にサブネットのプレフィクス長)で表現することが普通だと思います。しかし Terraform の cidrsubnet 関数の第2引数 newbits は、VPCのCIDRブロックとサブネットのCIDRブロックの、プレフィクス長の差を指定する必要があります。

つまりVPCのCIDRブロックのプレフィクス長が16で、このVPCにプレフィクス長24のサブネットを作りたいときは24-16なので8を指定する、ということですね。

これはあまり直感的ではない、と私は思います。またVPCのCIDRブロックのプレフィクス長を変えたときサブネットのプレフィクス長が変わってしまう点を、うっかり見落としそうです。

そこで、普段から使うプレフィクス長を使えるようにしています。

var.subnet_mask_length - tonumber(regex("[0-9]+$", var.vpc_cidr_block)),

subnet_mask_length が、私たちが普段使うサブネットのプレフィクス長を指定する変数です。

vpc_cidr_block はVPCのCIDRブロックを指定する変数で、これを regex("[0-9]+$", ...) でVPCのCIDRブロックのプレフィクス長を正規表現を使って取得しています。これを tonumber で整数型にし、サブネットのプレフィクス長から引いています。

サブネットのIPv6プレフィクス

IPv6、使ってますか? 使ってくださいね!

  ipv6_cidr_block = cidrsubnet(
    aws_vpc.main.ipv6_cidr_block,
    8,
    parseint(replace(data.aws_availability_zones.available.names[count.index], "/^.+?([a-z])$/", "0$1"), 16)
  )

こちらでは、サブネットのプレフィクス長は64で固定です[1]。VPCに割り当てられるIPv6のプレフィクス長は56なので、これでもサブネットは256個作れる計算ですから困ることはないでしょう。

工夫しているのは(というか無駄にこだわっているのは)IPv6のネットワークプレフィクスの末尾を availability zone の文字にしているところです。これだと分かりやすい気がします……と、書いていたときは思っていたんですが、そんなでもない気がしてきました。IPv4と合わせた方がいい場合もあるかもしれません。まあ、いいか……。

最後に

せっかくなので、サブネットの名前もちゃんと設定しましょう。ここだと availability zone の文字を使うのは便利かな、と思います。

  tags = {
    Name = "subnet-${var.app}-${var.env}-${replace(data.aws_availability_zones.available.names[count.index], "/^.+?([a-z])$/", "$1")}"
  }

おまけ

「あれ? プライベートサブネットは?」と思った方も多いと思います。

私自身は、パブリッククラウド上のプライベートサブネットに意味・意義を見いだせないんですが、仕事で求められることはよくあるので、用意はしてあります。……が、そういうものを積極的に解説するのはちょっと、なんというか……一言で言うと楽しくないので、コードを各々で見ていただけるといいのかな、と思います。

脚注
  1. 一般的にも64が使われます ↩︎

Discussion