diff --git a/ec2.tf b/ec2.tf index 5585c88..293080f 100644 --- a/ec2.tf +++ b/ec2.tf @@ -57,6 +57,7 @@ resource "aws_launch_template" "main" { subnet_id = var.subnet_id associate_public_ip_address = true security_groups = local.security_groups + ipv6_address_count = var.use_nat64 ? 1 : null } dynamic "instance_market_options" { diff --git a/examples/full/main.tf b/examples/full/main.tf index 0943ad9..2359c9e 100644 --- a/examples/full/main.tf +++ b/examples/full/main.tf @@ -1,6 +1,7 @@ locals { - name = "fck-nat-example" - vpc_cidr = "10.255.255.0/24" + name = "fck-nat-example" + vpc_cidr = "10.255.255.0/24" + ipv6_support = true } data "aws_region" "current" {} @@ -11,10 +12,14 @@ module "fck-nat" { name = local.name vpc_id = aws_vpc.main.id subnet_id = aws_subnet.public.id - ha_mode = true + ha_mode = false + use_nat64 = local.ipv6_support - update_route_tables = true + update_route_table = true route_tables_ids = { "private" = aws_route_table.private.id } -} \ No newline at end of file + route_tables6_ids = { + "public" = aws_route_table.public6[0].id + } +} diff --git a/examples/full/network.tf b/examples/full/network.tf index e5c52b3..cf09cad 100644 --- a/examples/full/network.tf +++ b/examples/full/network.tf @@ -1,5 +1,6 @@ resource "aws_vpc" "main" { - cidr_block = local.vpc_cidr + cidr_block = local.vpc_cidr + assign_generated_ipv6_cidr_block = local.ipv6_support tags = { Name = local.name @@ -12,6 +13,7 @@ resource "aws_subnet" "public" { vpc_id = aws_vpc.main.id cidr_block = cidrsubnet(local.vpc_cidr, 4, 0) availability_zone = "${data.aws_region.current.name}a" + ipv6_cidr_block = local.ipv6_support ? cidrsubnet(aws_vpc.main.ipv6_cidr_block, 8, 0) : null tags = { Name = "${local.name}-public" @@ -38,7 +40,14 @@ resource "aws_route" "public_igw" { route_table_id = aws_route_table.public.id destination_cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.gw.id +} + +resource "aws_route" "public_ipv6_igw" { + count = local.ipv6_support ? 1 : 0 + route_table_id = aws_route_table.public.id + destination_ipv6_cidr_block = "::0/0" + gateway_id = aws_internet_gateway.gw.id } resource "aws_route_table_association" "public" { @@ -52,6 +61,7 @@ resource "aws_subnet" "private" { vpc_id = aws_vpc.main.id cidr_block = cidrsubnet(local.vpc_cidr, 4, 1) availability_zone = "${data.aws_region.current.name}a" + ipv6_cidr_block = local.ipv6_support ? cidrsubnet(aws_vpc.main.ipv6_cidr_block, 8, 1) : null tags = { Name = "${local.name}-private" @@ -70,3 +80,46 @@ resource "aws_route_table_association" "private" { subnet_id = aws_subnet.private.id route_table_id = aws_route_table.private.id } + +### Public IPv6 + +resource "aws_subnet" "public6" { + count = local.ipv6_support ? 1 : 0 + + vpc_id = aws_vpc.main.id + ipv6_cidr_block = cidrsubnet(aws_vpc.main.ipv6_cidr_block, 8, 2) + availability_zone = "${data.aws_region.current.name}a" + enable_dns64 = true + ipv6_native = true + assign_ipv6_address_on_creation = true + enable_resource_name_dns_aaaa_record_on_launch = true + + tags = { + Name = "${local.name}-public6" + } +} + +resource "aws_route_table" "public6" { + count = local.ipv6_support ? 1 : 0 + + vpc_id = aws_vpc.main.id + + tags = { + Name = "${local.name}-public6" + } +} + +resource "aws_route" "public6_igw" { + count = local.ipv6_support ? 1 : 0 + + route_table_id = aws_route_table.public6[0].id + destination_ipv6_cidr_block = "::0/0" + gateway_id = aws_internet_gateway.gw.id +} + +resource "aws_route_table_association" "public6" { + count = local.ipv6_support ? 1 : 0 + + subnet_id = aws_subnet.public6[0].id + route_table_id = aws_route_table.public6[0].id +} \ No newline at end of file diff --git a/main.tf b/main.tf index 5e37621..3ab4f23 100644 --- a/main.tf +++ b/main.tf @@ -19,11 +19,12 @@ resource "aws_security_group" "main" { vpc_id = data.aws_vpc.main.id ingress { - description = "Unrestricted ingress from within VPC" - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = data.aws_vpc.main.cidr_block_associations[*].cidr_block + description = "Unrestricted ingress from within VPC" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = data.aws_vpc.main.cidr_block_associations[*].cidr_block + ipv6_cidr_blocks = var.use_nat64 ? ["${data.aws_vpc.main.ipv6_cidr_block}"] : null } egress { @@ -41,10 +42,11 @@ resource "aws_security_group" "main" { } resource "aws_network_interface" "main" { - description = "${var.name} static private ENI" - subnet_id = var.subnet_id - security_groups = [aws_security_group.main.id] - source_dest_check = false + description = "${var.name} static private ENI" + subnet_id = var.subnet_id + security_groups = [aws_security_group.main.id] + source_dest_check = false + ipv6_address_count = var.use_nat64 ? 1 : null tags = merge(var.tags, { Name = var.name @@ -59,6 +61,14 @@ resource "aws_route" "main" { network_interface_id = aws_network_interface.main.id } +resource "aws_route" "main_ipv6" { + for_each = (var.update_route_tables || var.update_route_table) && var.use_nat64 ? var.route_tables6_ids : {} + + route_table_id = each.value + destination_ipv6_cidr_block = "64:ff9b::/96" + network_interface_id = aws_network_interface.main.id +} + resource "aws_ssm_parameter" "cloudwatch_agent_config" { count = var.use_cloudwatch_agent && var.cloudwatch_agent_configuration_param_arn == null ? 1 : 0 diff --git a/variables.tf b/variables.tf index 7038ac8..d32e733 100644 --- a/variables.tf +++ b/variables.tf @@ -37,6 +37,12 @@ variable "route_tables_ids" { default = {} } +variable "route_tables6_ids" { + description = "Route tables to update for IPv6. Only valid if update_route_tables and use_nat64 are true" + type = map(string) + default = {} +} + variable "encryption" { description = "Whether or not to encrypt the EBS volume" type = bool @@ -129,6 +135,12 @@ variable "additional_security_group_ids" { default = [] } +variable "use_nat64" { + description = "Whether or not to enable NAT64 on the NAT instance. Your VPC and at least the public subnet this NAT instance is deployed into must support IPv6" + type = bool + default = false +} + variable "tags" { description = "Tags to apply to resources created within the module" type = map(string)