AWS事業本部のイシザワです。
マルチVPC環境での各種リソースの集約をやってみたかったので、手始めに名前解決の集約構成を構築してみます。
また、個人的にTerraformの勉強をしているのでTerraformで構築してみようと思います。
構成要素
Route 53 Resolver
Route 53 ResolverはEC2等のAWSリソースからのDNSクエリに再帰的に応答するDNSサーバーです。VPCの構築時に自動的に作成され、IPアドレスはVPCのネットワークアドレス+2(VPC+2アドレス)となります。例えばVPCのCIDRが10.8.0.0/24
の場合は10.8.0.2
に接続することでRoute 53 Resolverにアクセスできます。
EC2が名前解決に利用するDNSサーバーはデフォルトでVPC+2アドレスとなっています。
$ resolvectl dns
Global:
Link 2 (ens5): 10.8.0.2
Link 3 (docker0):
このエンドポイントにVPC外からアクセスすることはできません。VPCにRoute 53 Resolver Inbound Endpointを作成することでVPC外からのアクセスを受け付けることができます。
DHCPオプションセット
DHCPオプションセットでEC2インスタンスのネットワーク構成を設定できます。EC2インスタンスが利用するDNSサーバーはデフォルトでVPC+2アドレスとなっていますが、DHCPオプションセットを使えば変更することができます。
Transit Gateway
Transit GatewayはVPCやオンプレミスネットワークの中継ハブです。VPCどうしを接続するために利用します。
VPC IPAM (IP Address Manager)
IPAMはCIDRの払い出しやIPアドレスの管理を行うリソースです。名前解決の集約を行うのに必須ではありませんが、重複するCIDRが無いことを保証できるのがTransit Gatewayを使う上で便利なので使っています。
VPCの構築時にIPAMプールを指定することで、VPCのCIDRをプール内から自動的に払い出して設定してくれます。
IPAMプールは階層構造を作ることができ、今回は以下のような階層構造のIPAMプールを作成します。
- トップレベルIPAMプール(10.0.0.0/12)
- 基盤用IPAMプール(10.0.0.0/13)
- ワークロード用IPAMプール(10.8.0.0/13)
全体構成
以下の設定によりDNSの設定を名前解決用VPCに集約します。
- 名前解決用VPCにRoute 53 Resolver Inbound Endpointを作成する
- 他VPCのDHCPオプションセットでDNSサーバーとして↑で作成したエンドポイントを指定する。
全体の構成は以下の図の通りです。
Terraformコード
ソースコードはGitHubに載せています。いくつかピックアップして解説をしていきます。
Transit Gateway
今回の構成だとVPC間の接続はAny-to-Any接続で十分のため、Transit Gatewayのデフォルト関連付けルートテーブルとデフォルト伝播ルートテーブルを有効にしています。
modules/transit_gateway/transit_gateway.tf
resource "aws_ec2_transit_gateway" "main" {
default_route_table_association = "enable"
default_route_table_propagation = "enable"
auto_accept_shared_attachments = "enable"
dns_support = "enable"
tags = {
Name = "${var.system_id}-tgw"
}
}
Route 53 Resolver Inbound Endpoint
Route 53 Resolver Inbound Endpointにはセキュリティグループを設定する必要があります。名前解決を行うVPCからのtcp/53とudp/53を許可すればOKです。ここではトップレベルIPAMプールのCIDRからのtcp/53とudp/53を許可しています。
エンドポイントはip_address
を2つ以上設定する必要があります。今回は同じサブネット内に設定していますが、高可用性構成の場合は異なるAZのサブネットを指定します。
modules/dns_aggregation/dns.tf
resource "aws_Route 53_resolver_endpoint" "main" {
name = "${var.system_id}-dns-endpoint"
direction = "INBOUND"
security_group_ids = [
aws_security_group.allow_dns.id
]
ip_address {
subnet_id = aws_subnet.private.id
ip = local.primary_dns_ip_address
}
ip_address {
subnet_id = aws_subnet.private.id
ip = local.secondary_dns_ip_address
}
}
resource "aws_security_group" "allow_dns" {
name = "allow_dns"
description = "Allow DNS inbound traffic"
vpc_id = aws_vpc.main.id
ingress {
from_port = 53
to_port = 53
protocol = "udp"
cidr_blocks = [var.toplevel_pool_cidr]
}
ingress {
from_port = 53
to_port = 53
protocol = "tcp"
cidr_blocks = [var.toplevel_pool_cidr]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "allow_dns"
}
}
DHCPオプションセット
DHCPオプションセットの設定でRoute 53 Resolver Inbound EndpointのIPアドレスをDNSサーバーに指定します。このDHCPオプションセットをワークロード用VPCと関連付けます。
modules/workload/network.tf
resource "aws_vpc_dhcp_options" "main" {
domain_name = "${var.region_name}.compute.internal"
domain_name_servers = [
var.primary_dns_ip_address,
var.secondary_dns_ip_address,
]
tags = {
Name = "${local.prefix}-dhcp-options"
}
}
resource "aws_vpc_dhcp_options_association" "main" {
vpc_id = aws_vpc.main.id
dhcp_options_id = aws_vpc_dhcp_options.main.id
}
テスト用インスタンス
テスト用インスタンスにはSSMセッションマネージャーでログインするため、それ用のIAMロールを作成してアタッチします。
modules/common_iam/iam_role.tf
data "aws_iam_policy_document" "instance_assume_role_policy" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
resource "aws_iam_role" "instance_ssm_role" {
name = "${var.system_id}-iamrole-instance-ssm"
path = "/"
assume_role_policy = data.aws_iam_policy_document.instance_assume_role_policy.json
managed_policy_arns = [
"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
]
}
resource "aws_iam_instance_profile" "instance_ssm_role" {
name = "${var.system_id}-instance-profile-instance-ssm"
role = aws_iam_role.instance_ssm_role.name
}
疎通確認のためのICMPを許可するセキュリティグループをアタッチします。
modules/workload/instance.tf
resource "aws_instance" "test_instance" {
ami = data.aws_ami.latest_amazon_linux_2023.id
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id
iam_instance_profile = var.instance_profile_name
vpc_security_group_ids = [aws_security_group.allow_icmp.id]
tags = {
Name = "${local.prefix}-test-instance"
}
}
resource "aws_security_group" "allow_icmp" {
name = "allow_icmp"
description = "Allow ICMP inbound traffic"
vpc_id = aws_vpc.main.id
ingress {
from_port = -1
to_port = -1
protocol = "icmp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "allow_icmp"
}
}
また、名前解決用VPCのPrivate Hosted Zoneにテスト用インスタンスのDNSレコードを登録します。
modules/workload/instance.tf
resource "aws_Route 53_record" "test_instance" {
zone_id = var.Route 53_zone_id
name = "${local.domain_host_name}.${var.parent_domain_name}"
type = "A"
ttl = 300
records = [aws_instance.test_instance.private_ip]
}
動作確認
以下の変数の設定でリソースの構築を行います。
terraform.tfvars
system_id = "sample"
ipam_topleve_pool_cidr = "10.0.0.0/12"
domain_name = "example.com"
作成されたテスト用インスタンスsample-workload0-test-instance
にSSMセッションマネージャーでログインします。
DNSサーバーにRoute 53 Resolver Inbound EndpointのIPアドレスが設定されていることが確認できます。
$ resolvectl dns
Global:
Link 2 (ens5): 10.0.0.253 10.0.0.254
Link 3 (docker0):
名前解決用VPCのPrivate Hosted Zoneに、別のワークロードVPCに作成したインスタンスのDNS名が登録されています。 このDNS名が解決できることを確認できます。
$ resolvectl query workload1.example.com
workload1.example.com: 10.8.2.237 -- link: ens5
-- Information acquired via protocol DNS in 4.0ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: network
このDNS名に対してpingが通ることが確認できます。
$ ping workload1.example.com -c 5
PING workload1.example.com (10.8.2.237) 56(84) bytes of data.
64 bytes from ip-10-8-2-237.ap-northeast-1.compute.internal (10.8.2.237): icmp_seq=1 ttl=126 time=0.565 ms
64 bytes from ip-10-8-2-237.ap-northeast-1.compute.internal (10.8.2.237): icmp_seq=2 ttl=126 time=0.395 ms
64 bytes from ip-10-8-2-237.ap-northeast-1.compute.internal (10.8.2.237): icmp_seq=3 ttl=126 time=0.379 ms
64 bytes from ip-10-8-2-237.ap-northeast-1.compute.internal (10.8.2.237): icmp_seq=4 ttl=126 time=0.391 ms
64 bytes from ip-10-8-2-237.ap-northeast-1.compute.internal (10.8.2.237): icmp_seq=5 ttl=126 time=0.384 ms
--- workload1.example.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 0.379/0.422/0.565/0.071 ms
注意
リソース削除時、IPAMプールの削除に失敗することがあります。これはVPCの削除とIPAMプールの割り当てIPアドレス領域の解放との間でタイムラグがあるのが原因です。少し時間を置けば削除できます。
まとめ
マルチVPC環境における名前解決の集約構成をTerraformで構築しました。今回は単独アカウントで行いましたが、マルチアカウントでも同様の構成を取ることができると思います。
次回はVPCエンドポイントの集約構成をTerraformで構築してみたいと思います。
2023/04/20 追記)VPCエンドポイントの集約構成も試してみました。