diff --git a/.spacelift/config.yml b/.spacelift/config.yml index 4aae5459a..bc464466c 100644 --- a/.spacelift/config.yml +++ b/.spacelift/config.yml @@ -1,2 +1,2 @@ version: 1 -module_version: 5.1.1 +module_version: 0.1.0 diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 579a47395..ccfcb4490 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -25,7 +25,7 @@ locals { module "vpc" { source = "../../" - name = local.name + name_prefix = local.name cidr = local.vpc_cidr azs = local.azs diff --git a/examples/ipam/main.tf b/examples/ipam/main.tf index d43851202..b38186d02 100644 --- a/examples/ipam/main.tf +++ b/examples/ipam/main.tf @@ -26,7 +26,7 @@ locals { module "vpc_ipam_set_netmask" { source = "../.." - name = "${local.name}-set-netmask" + name_prefix = "${local.name}-set-netmask" use_ipam_pool = true ipv4_ipam_pool_id = aws_vpc_ipam_pool.this.id @@ -46,7 +46,7 @@ module "vpc_ipam_set_netmask" { module "vpc_ipam_set_cidr" { source = "../.." - name = "${local.name}-set-cidr" + name_prefix = "${local.name}-set-cidr" use_ipam_pool = true ipv4_ipam_pool_id = aws_vpc_ipam_pool.this.id diff --git a/examples/ipv6-dualstack/main.tf b/examples/ipv6-dualstack/main.tf index d71f8fe35..b514ff83f 100644 --- a/examples/ipv6-dualstack/main.tf +++ b/examples/ipv6-dualstack/main.tf @@ -25,7 +25,7 @@ locals { module "vpc" { source = "../.." - name = local.name + name_prefix = local.name cidr = local.vpc_cidr azs = local.azs diff --git a/examples/ipv6-only/main.tf b/examples/ipv6-only/main.tf index ba737316d..250d0092c 100644 --- a/examples/ipv6-only/main.tf +++ b/examples/ipv6-only/main.tf @@ -22,7 +22,7 @@ locals { module "vpc" { source = "../.." - name = local.name + name_prefix = local.name azs = slice(data.aws_availability_zones.available.names, 0, 3) enable_ipv6 = true diff --git a/examples/issues/main.tf b/examples/issues/main.tf index 9e23b806f..f3272e36f 100644 --- a/examples/issues/main.tf +++ b/examples/issues/main.tf @@ -24,7 +24,7 @@ locals { module "vpc_issue_44" { source = "../../" - name = "asymmetrical" + name_prefix = "asymmetrical" cidr = "10.0.0.0/16" azs = local.azs @@ -48,7 +48,7 @@ module "vpc_issue_44" { module "vpc_issue_46" { source = "../../" - name = "no-private-subnets" + name_prefix = "no-private-subnets" cidr = "10.0.0.0/16" azs = local.azs @@ -74,7 +74,7 @@ module "vpc_issue_46" { module "vpc_issue_108" { source = "../../" - name = "route-already-exists" + name_prefix = "route-already-exists" cidr = "10.0.0.0/16" azs = local.azs diff --git a/examples/network-acls/main.tf b/examples/network-acls/main.tf index 35c3a2211..fc2cc8243 100644 --- a/examples/network-acls/main.tf +++ b/examples/network-acls/main.tf @@ -174,7 +174,7 @@ locals { module "vpc" { source = "../../" - name = local.name + name_prefix = local.name cidr = local.vpc_cidr azs = local.azs diff --git a/examples/outpost/main.tf b/examples/outpost/main.tf index b65e8d75a..adf3c6df8 100644 --- a/examples/outpost/main.tf +++ b/examples/outpost/main.tf @@ -124,7 +124,7 @@ locals { module "vpc" { source = "../../" - name = local.name + name_prefix = local.name cidr = local.vpc_cidr azs = local.azs diff --git a/examples/secondary-cidr-blocks/main.tf b/examples/secondary-cidr-blocks/main.tf index 5c963bb94..e4485ffc6 100644 --- a/examples/secondary-cidr-blocks/main.tf +++ b/examples/secondary-cidr-blocks/main.tf @@ -26,7 +26,7 @@ locals { module "vpc" { source = "../../" - name = local.name + name_prefix = local.name cidr = local.vpc_cidr secondary_cidr_blocks = local.secondary_cidr_blocks # can add up to 5 total CIDR blocks diff --git a/examples/separate-route-tables/main.tf b/examples/separate-route-tables/main.tf index 99cf9828f..2d661b6b5 100644 --- a/examples/separate-route-tables/main.tf +++ b/examples/separate-route-tables/main.tf @@ -25,7 +25,7 @@ locals { module "vpc" { source = "../../" - name = local.name + name_prefix = local.name cidr = local.vpc_cidr azs = local.azs diff --git a/examples/simple/main.tf b/examples/simple/main.tf index 324977173..e4c5a847d 100644 --- a/examples/simple/main.tf +++ b/examples/simple/main.tf @@ -25,7 +25,7 @@ locals { module "vpc" { source = "../../" - name = local.name + name_prefix = local.name cidr = local.vpc_cidr azs = local.azs diff --git a/examples/vpc-flow-logs/main.tf b/examples/vpc-flow-logs/main.tf index 7cd35d34f..4121dfdae 100644 --- a/examples/vpc-flow-logs/main.tf +++ b/examples/vpc-flow-logs/main.tf @@ -27,7 +27,7 @@ locals { module "vpc_with_flow_logs_s3_bucket" { source = "../../" - name = local.name + name_prefix = local.name cidr = local.vpc_cidr azs = local.azs @@ -44,7 +44,7 @@ module "vpc_with_flow_logs_s3_bucket" { module "vpc_with_flow_logs_s3_bucket_parquet" { source = "../../" - name = "${local.name}-parquet" + name_prefix = "${local.name}-parquet" cidr = local.vpc_cidr azs = local.azs @@ -63,7 +63,7 @@ module "vpc_with_flow_logs_s3_bucket_parquet" { module "vpc_with_flow_logs_cloudwatch_logs_default" { source = "../../" - name = "${local.name}-cloudwatch-logs-default" + name_prefix = "${local.name}-cloudwatch-logs-default" cidr = local.vpc_cidr azs = local.azs @@ -87,7 +87,7 @@ module "vpc_with_flow_logs_cloudwatch_logs_default" { module "vpc_with_flow_logs_cloudwatch_logs_prefix" { source = "../../" - name = "${local.name}-cloudwatch-logs-prefix" + name_prefix = "${local.name}-cloudwatch-logs-prefix" cidr = local.vpc_cidr azs = local.azs @@ -116,7 +116,7 @@ module "vpc_with_flow_logs_cloudwatch_logs_prefix" { module "vpc_with_flow_logs_cloudwatch_logs" { source = "../../" - name = "${local.name}-cloudwatch-logs" + name_prefix = "${local.name}-cloudwatch-logs" cidr = local.vpc_cidr azs = local.azs diff --git a/main.tf b/main.tf index 05b4f5e22..106b96cf0 100644 --- a/main.tf +++ b/main.tf @@ -13,6 +13,7 @@ locals { local.len_elasticache_subnets, local.len_database_subnets, local.len_redshift_subnets, + local.len_tgw_subnets ) # Use `local.vpc_id` to give a hint to Terraform that subnets should be deleted before secondary CIDR blocks can be free! @@ -44,7 +45,7 @@ resource "aws_vpc" "this" { enable_network_address_usage_metrics = var.enable_network_address_usage_metrics tags = merge( - { "Name" = var.name }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-vpc-${var.vpc_name_suffix}" }, var.tags, var.vpc_tags, ) @@ -74,7 +75,7 @@ resource "aws_vpc_dhcp_options" "this" { ipv6_address_preferred_lease_time = var.dhcp_options_ipv6_address_preferred_lease_time tags = merge( - { "Name" = var.name }, + { "Name" = var.name_prefix }, var.tags, var.dhcp_options_tags, ) @@ -115,7 +116,11 @@ resource "aws_subnet" "public" { { Name = try( var.public_subnet_names[count.index], - format("${var.name}-${var.public_subnet_suffix}-%s", element(var.azs, count.index)) + format("%s-%s%s-%s-sub-%s", var.name_prefix, var.short_aws_region, + substr(element(var.azs, count.index), -1, 1), + lookup(var.az_name_to_az_id, element(var.azs, count.index), ""), + var.public_subnet_suffix + ) ) }, var.tags, @@ -136,9 +141,10 @@ resource "aws_route_table" "public" { tags = merge( { "Name" = var.create_multiple_public_route_tables ? format( - "${var.name}-${var.public_subnet_suffix}-%s", - element(var.azs, count.index), - ) : "${var.name}-${var.public_subnet_suffix}" + "%s-%s%s-rtb-%s", var.name_prefix, var.short_aws_region, + substr(element(var.azs, count.index), -1, 1), + var.public_subnet_suffix + ) : "${var.name_prefix}-${var.short_aws_region}-rtb-${var.public_subnet_suffix}" }, var.tags, var.public_route_table_tags, @@ -183,7 +189,7 @@ resource "aws_network_acl" "public" { subnet_ids = aws_subnet.public[*].id tags = merge( - { "Name" = "${var.name}-${var.public_subnet_suffix}" }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-nacl-${var.public_subnet_suffix}" }, var.tags, var.public_acl_tags, ) @@ -246,11 +252,17 @@ resource "aws_subnet" "private" { private_dns_hostname_type_on_launch = var.private_subnet_private_dns_hostname_type_on_launch vpc_id = local.vpc_id + # ${var.name_prefix}-${var.region_short}--sub-${var.private_subnet_suffix} + # app1-test-euc1a-az2-sub-db tags = merge( { Name = try( var.private_subnet_names[count.index], - format("${var.name}-${var.private_subnet_suffix}-%s", element(var.azs, count.index)) + format("%s-%s%s-%s-sub-%s", var.name_prefix, var.short_aws_region, + substr(element(var.azs, count.index), -1, 1), + lookup(var.az_name_to_az_id, element(var.azs, count.index), ""), + var.private_subnet_suffix + ) ) }, var.tags, @@ -267,9 +279,11 @@ resource "aws_route_table" "private" { tags = merge( { - "Name" = var.single_nat_gateway ? "${var.name}-${var.private_subnet_suffix}" : format( - "${var.name}-${var.private_subnet_suffix}-%s", - element(var.azs, count.index), + "Name" = (var.single_nat_gateway ? "${var.name_prefix}-${var.short_aws_region}-rtb-${var.private_subnet_suffix}" : + format("%s-%s%s-rtb-%s", var.name_prefix, var.short_aws_region, + substr(element(var.azs, count.index), -1, 1), + var.public_subnet_suffix + ) ) }, var.tags, @@ -302,7 +316,7 @@ resource "aws_network_acl" "private" { subnet_ids = aws_subnet.private[*].id tags = merge( - { "Name" = "${var.name}-${var.private_subnet_suffix}" }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-nacl-${var.private_subnet_suffix}" }, var.tags, var.private_acl_tags, ) @@ -370,7 +384,12 @@ resource "aws_subnet" "database" { { Name = try( var.database_subnet_names[count.index], - format("${var.name}-${var.database_subnet_suffix}-%s", element(var.azs, count.index), ) + format( + "%s-%s%s-%s-sub-%s", var.name_prefix, var.short_aws_region, + substr(element(var.azs, count.index), -1, 1), + lookup(var.az_name_to_az_id, element(var.azs, count.index), ""), + var.database_subnet_suffix + ) ) }, var.tags, @@ -381,13 +400,13 @@ resource "aws_subnet" "database" { resource "aws_db_subnet_group" "database" { count = local.create_database_subnets && var.create_database_subnet_group ? 1 : 0 - name = lower(coalesce(var.database_subnet_group_name, var.name)) - description = "Database subnet group for ${var.name}" + name = lower(coalesce(var.database_subnet_group_name, var.name_prefix)) + description = "Database subnet group for ${var.name_prefix}" subnet_ids = aws_subnet.database[*].id tags = merge( { - "Name" = lower(coalesce(var.database_subnet_group_name, var.name)) + "Name" = lower(coalesce(var.database_subnet_group_name, var.name_prefix)) }, var.tags, var.database_subnet_group_tags, @@ -401,9 +420,13 @@ resource "aws_route_table" "database" { tags = merge( { - "Name" = var.single_nat_gateway || var.create_database_internet_gateway_route ? "${var.name}-${var.database_subnet_suffix}" : format( - "${var.name}-${var.database_subnet_suffix}-%s", - element(var.azs, count.index), + "Name" = ( + var.single_nat_gateway || var.create_database_internet_gateway_route ? + "${var.name_prefix}-${var.short_aws_region}-rtb-${var.database_subnet_suffix}" + : format( + "${var.name_prefix}-${var.short_aws_region}%s-rtb-${var.database_subnet_suffix}", + substr(element(var.azs, count.index), -1, 1), + ) ) }, var.tags, @@ -484,7 +507,7 @@ resource "aws_network_acl" "database" { subnet_ids = aws_subnet.database[*].id tags = merge( - { "Name" = "${var.name}-${var.database_subnet_suffix}" }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-nacl-${var.database_subnet_suffix}" }, var.tags, var.database_acl_tags, ) @@ -552,7 +575,10 @@ resource "aws_subnet" "redshift" { { Name = try( var.redshift_subnet_names[count.index], - format("${var.name}-${var.redshift_subnet_suffix}-%s", element(var.azs, count.index)) + format("${var.name_prefix}-${var.short_aws_region}%s-%s-sub-${var.redshift_subnet_suffix}", + substr(element(var.azs, count.index), -1, 1), + lookup(var.az_name_to_az_id, element(var.azs, count.index), "") + ) ) }, var.tags, @@ -563,12 +589,12 @@ resource "aws_subnet" "redshift" { resource "aws_redshift_subnet_group" "redshift" { count = local.create_redshift_subnets && var.create_redshift_subnet_group ? 1 : 0 - name = lower(coalesce(var.redshift_subnet_group_name, var.name)) - description = "Redshift subnet group for ${var.name}" + name = lower(coalesce(var.redshift_subnet_group_name, var.name_prefix)) + description = "Redshift subnet group for ${var.name_prefix}" subnet_ids = aws_subnet.redshift[*].id tags = merge( - { "Name" = coalesce(var.redshift_subnet_group_name, var.name) }, + { "Name" = coalesce(var.redshift_subnet_group_name, var.name_prefix) }, var.tags, var.redshift_subnet_group_tags, ) @@ -580,7 +606,7 @@ resource "aws_route_table" "redshift" { vpc_id = local.vpc_id tags = merge( - { "Name" = "${var.name}-${var.redshift_subnet_suffix}" }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-rtb-${var.redshift_subnet_suffix}" }, var.tags, var.redshift_route_table_tags, ) @@ -621,7 +647,7 @@ resource "aws_network_acl" "redshift" { subnet_ids = aws_subnet.redshift[*].id tags = merge( - { "Name" = "${var.name}-${var.redshift_subnet_suffix}" }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-nacl-${var.redshift_subnet_suffix}" }, var.tags, var.redshift_acl_tags, ) @@ -689,7 +715,11 @@ resource "aws_subnet" "elasticache" { { Name = try( var.elasticache_subnet_names[count.index], - format("${var.name}-${var.elasticache_subnet_suffix}-%s", element(var.azs, count.index)) + format("%s-%s%s-%s-sub-%s", var.name_prefix, var.short_aws_region, + substr(element(var.azs, count.index), -1, 1), + lookup(var.az_name_to_az_id, element(var.azs, count.index), ""), + var.elasticache_subnet_suffix + ) ) }, var.tags, @@ -700,12 +730,12 @@ resource "aws_subnet" "elasticache" { resource "aws_elasticache_subnet_group" "elasticache" { count = local.create_elasticache_subnets && var.create_elasticache_subnet_group ? 1 : 0 - name = coalesce(var.elasticache_subnet_group_name, var.name) - description = "ElastiCache subnet group for ${var.name}" + name = coalesce(var.elasticache_subnet_group_name, var.name_prefix) + description = "ElastiCache subnet group for ${var.name_prefix}" subnet_ids = aws_subnet.elasticache[*].id tags = merge( - { "Name" = coalesce(var.elasticache_subnet_group_name, var.name) }, + { "Name" = coalesce(var.elasticache_subnet_group_name, var.name_prefix) }, var.tags, var.elasticache_subnet_group_tags, ) @@ -717,7 +747,7 @@ resource "aws_route_table" "elasticache" { vpc_id = local.vpc_id tags = merge( - { "Name" = "${var.name}-${var.elasticache_subnet_suffix}" }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-rtb-${var.elasticache_subnet_suffix}" }, var.tags, var.elasticache_route_table_tags, ) @@ -751,7 +781,7 @@ resource "aws_network_acl" "elasticache" { subnet_ids = aws_subnet.elasticache[*].id tags = merge( - { "Name" = "${var.name}-${var.elasticache_subnet_suffix}" }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-nacl-${var.elasticache_subnet_suffix}" }, var.tags, var.elasticache_acl_tags, ) @@ -818,7 +848,11 @@ resource "aws_subnet" "intra" { { Name = try( var.intra_subnet_names[count.index], - format("${var.name}-${var.intra_subnet_suffix}-%s", element(var.azs, count.index)) + format("%s-%s%s-%s-sub-%s", var.name_prefix, var.short_aws_region, + substr(element(var.azs, count.index), -1, 1), + lookup(var.az_name_to_az_id, element(var.azs, count.index), ""), + var.intra_subnet_suffix + ) ) }, var.tags, @@ -838,9 +872,9 @@ resource "aws_route_table" "intra" { tags = merge( { "Name" = var.create_multiple_intra_route_tables ? format( - "${var.name}-${var.intra_subnet_suffix}-%s", - element(var.azs, count.index), - ) : "${var.name}-${var.intra_subnet_suffix}" + "${var.name_prefix}%s-${var.intra_subnet_suffix}-%s", + substr(element(var.azs, count.index), -1, 1), + ) : "${var.name_prefix}-rtb-${var.intra_subnet_suffix}" }, var.tags, var.intra_route_table_tags, @@ -869,7 +903,7 @@ resource "aws_network_acl" "intra" { subnet_ids = aws_subnet.intra[*].id tags = merge( - { "Name" = "${var.name}-${var.intra_subnet_suffix}" }, + { "Name" = "${var.name_prefix}-nacl-${var.intra_subnet_suffix}" }, var.tags, var.intra_acl_tags, ) @@ -938,7 +972,7 @@ resource "aws_subnet" "outpost" { { Name = try( var.outpost_subnet_names[count.index], - format("${var.name}-${var.outpost_subnet_suffix}-%s", var.outpost_az) + format("${var.name_prefix}-%s-sub-${var.outpost_subnet_suffix}", var.outpost_az) ) }, var.tags, @@ -971,7 +1005,7 @@ resource "aws_network_acl" "outpost" { subnet_ids = aws_subnet.outpost[*].id tags = merge( - { "Name" = "${var.name}-${var.outpost_subnet_suffix}" }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-nacl-${var.outpost_subnet_suffix}" }, var.tags, var.outpost_acl_tags, ) @@ -1021,7 +1055,7 @@ resource "aws_internet_gateway" "this" { vpc_id = local.vpc_id tags = merge( - { "Name" = var.name }, + { "Name" = "${var.name_prefix}-igw" }, var.tags, var.igw_tags, ) @@ -1033,7 +1067,7 @@ resource "aws_egress_only_internet_gateway" "this" { vpc_id = local.vpc_id tags = merge( - { "Name" = var.name }, + { "Name" = "${var.name_prefix}-eigw" }, var.tags, var.igw_tags, ) @@ -1064,8 +1098,10 @@ resource "aws_eip" "nat" { tags = merge( { "Name" = format( - "${var.name}-%s", - element(var.azs, var.single_nat_gateway ? 0 : count.index), + "${var.name_prefix}-${var.short_aws_region}%s-eip", + substr(element(var.azs, var.single_nat_gateway ? 0 : count.index), + length(element(var.azs, var.single_nat_gateway ? 0 : count.index)) - 1, 1 + ) ) }, var.tags, @@ -1090,8 +1126,10 @@ resource "aws_nat_gateway" "this" { tags = merge( { "Name" = format( - "${var.name}-%s", - element(var.azs, var.single_nat_gateway ? 0 : count.index), + "${var.name_prefix}-${var.short_aws_region}%s-natgw", + substr(element(var.azs, var.single_nat_gateway ? 0 : count.index), + length(element(var.azs, var.single_nat_gateway ? 0 : count.index)) - 1, 1 + ) ) }, var.tags, @@ -1138,7 +1176,7 @@ resource "aws_customer_gateway" "this" { type = "ipsec.1" tags = merge( - { Name = "${var.name}-${each.key}" }, + { Name = "${var.name_prefix}-${each.key}" }, var.tags, var.customer_gateway_tags, ) @@ -1160,7 +1198,7 @@ resource "aws_vpn_gateway" "this" { availability_zone = var.vpn_gateway_az tags = merge( - { "Name" = var.name }, + { "Name" = "${var.name_prefix}-${var.short_aws_region}-vpngw" }, var.tags, var.vpn_gateway_tags, ) @@ -1265,7 +1303,7 @@ resource "aws_default_security_group" "this" { } tags = merge( - { "Name" = coalesce(var.default_security_group_name, "${var.name}-default") }, + { "Name" = coalesce(var.default_security_group_name, "${var.name_prefix}-${var.short_aws_region}-sg-default") }, var.tags, var.default_security_group_tags, ) @@ -1314,7 +1352,7 @@ resource "aws_default_network_acl" "this" { } tags = merge( - { "Name" = coalesce(var.default_network_acl_name, "${var.name}-default") }, + { "Name" = coalesce(var.default_network_acl_name, "${var.name_prefix}-${var.short_aws_region}-nacl-default") }, var.tags, var.default_network_acl_tags, ) @@ -1359,7 +1397,7 @@ resource "aws_default_route_table" "default" { } tags = merge( - { "Name" = coalesce(var.default_route_table_name, "${var.name}-default") }, + { "Name" = coalesce(var.default_route_table_name, "${var.name_prefix}-${var.short_aws_region}-rtb-default") }, var.tags, var.default_route_table_tags, ) diff --git a/outputs.tf b/outputs.tf index a98c65c98..301a64f30 100644 --- a/outputs.tf +++ b/outputs.tf @@ -2,6 +2,7 @@ locals { redshift_route_table_ids = aws_route_table.redshift[*].id public_route_table_ids = aws_route_table.public[*].id private_route_table_ids = aws_route_table.private[*].id + tgw_route_table_ids = aws_route_table.tgw[*].id } ################################################################################ @@ -625,11 +626,11 @@ output "azs" { output "name" { description = "The name of the VPC specified as argument to this module" - value = var.name + value = var.name_prefix } ################################################################################ -# Our own outputs +# AS added outputs ################################################################################ output "private_subnets_az_names" { description = "List of AZ names of private subnets" @@ -660,3 +661,57 @@ output "database_subnets_az_ids" { description = "List of AZ IDs of database subnets" value = aws_subnet.database[*].availability_zone_id } + +################################################################################ +# TGW Subnets +################################################################################ + +output "tgw_subnets" { + description = "List of IDs of tgw subnets" + value = aws_subnet.tgw[*].id +} + +output "tgw_subnet_arns" { + description = "List of ARNs of tgw subnets" + value = aws_subnet.tgw[*].arn +} + +output "tgw_subnets_cidr_blocks" { + description = "List of cidr_blocks of tgw subnets" + value = compact(aws_subnet.tgw[*].cidr_block) +} + +output "tgw_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of tgw subnets in an IPv6 enabled VPC" + value = compact(aws_subnet.tgw[*].ipv6_cidr_block) +} + +output "tgw_route_table_ids" { + description = "List of IDs of tgw route tables" + value = local.tgw_route_table_ids +} + +output "tgw_route_table_association_ids" { + description = "List of IDs of the tgw route table association" + value = aws_route_table_association.tgw[*].id +} + +output "tgw_network_acl_id" { + description = "ID of the tgw network ACL" + value = try(aws_network_acl.tgw[0].id, null) +} + +output "tgw_network_acl_arn" { + description = "ARN of the tgw network ACL" + value = try(aws_network_acl.tgw[0].arn, null) +} + +output "aws_ec2_transit_gateway_vpc_attachment_id" { + description = "ID of the TGW attachment" + value = try(aws_ec2_transit_gateway_vpc_attachment.tgw[0].id, null) +} + +output "tgw_att_name" { + description = "Name of the TGW attachment" + value = try(aws_ec2_transit_gateway_vpc_attachment.tgw[0].tags["Name"], "") +} diff --git a/tgw.tf b/tgw.tf new file mode 100644 index 000000000..e8b6a76a4 --- /dev/null +++ b/tgw.tf @@ -0,0 +1,229 @@ +################################################################################ +# TGW Subnets +################################################################################ + +locals { + len_tgw_subnets = max(length(var.tgw_subnets), length(var.tgw_subnet_ipv6_prefixes)) + create_tgw_subnets = local.create_vpc && local.len_tgw_subnets > 0 + + # support variables for transit_gateway_routes + subnets_tgw_routed = keys(var.transit_gateway_routes) +} + +resource "aws_subnet" "tgw" { + count = local.create_tgw_subnets ? local.len_tgw_subnets : 0 # TODO: Maybe add condition to have at least as many as AZs + + assign_ipv6_address_on_creation = var.enable_ipv6 && var.tgw_subnet_ipv6_native ? true : var.tgw_subnet_assign_ipv6_address_on_creation + availability_zone = length(regexall("^[a-z]{2}-", element(var.azs, count.index))) > 0 ? element(var.azs, count.index) : null + availability_zone_id = length(regexall("^[a-z]{2}-", element(var.azs, count.index))) == 0 ? element(var.azs, count.index) : null + cidr_block = var.tgw_subnet_ipv6_native ? null : element(concat(var.tgw_subnets, [""]), count.index) + enable_dns64 = var.enable_ipv6 && var.tgw_subnet_enable_dns64 + enable_resource_name_dns_aaaa_record_on_launch = var.enable_ipv6 && var.tgw_subnet_enable_resource_name_dns_aaaa_record_on_launch + enable_resource_name_dns_a_record_on_launch = !var.tgw_subnet_ipv6_native && var.tgw_subnet_enable_resource_name_dns_a_record_on_launch + ipv6_cidr_block = var.enable_ipv6 && length(var.tgw_subnet_ipv6_prefixes) > 0 ? cidrsubnet(aws_vpc.this[0].ipv6_cidr_block, 8, var.tgw_subnet_ipv6_prefixes[count.index]) : null + ipv6_native = var.enable_ipv6 && var.tgw_subnet_ipv6_native + private_dns_hostname_type_on_launch = var.tgw_subnet_private_dns_hostname_type_on_launch + vpc_id = local.vpc_id + + tags = merge( + { + Name = try( + var.tgw_subnet_names[count.index], + format( + "%s-%s%s-%s-sub-%s", + var.name_prefix, + var.short_aws_region, + substr(element(var.azs, count.index), -1, 1), # Get last letter of az code + lookup(var.az_name_to_az_id, element(var.azs, count.index), ""), # Lookup az-id based on name + var.tgw_subnet_suffix + ) + ) + }, + var.tags, + var.tgw_subnet_tags, + lookup(var.tgw_subnet_tags_per_az, element(var.azs, count.index), {}) + ) +} + +locals { + num_tgw_route_tables = var.create_multiple_tgw_route_tables ? local.len_tgw_subnets : 1 +} + +resource "aws_route_table" "tgw" { + count = local.create_tgw_subnets ? local.num_tgw_route_tables : 0 + + vpc_id = local.vpc_id + tags = merge( + { + "Name" = var.create_multiple_tgw_route_tables ? format( + "%s-%s%s-rtb-%s", + var.name_prefix, + var.short_aws_region, + substr(element(var.azs, count.index), -1, 1), + var.tgw_subnet_suffix + ) : format( + "%s-%s-rtb-%s", + var.name_prefix, + var.short_aws_region, + var.tgw_subnet_suffix + ) + }, + var.tags, + var.tgw_route_table_tags + ) +} + +resource "aws_route_table_association" "tgw" { + count = local.create_tgw_subnets ? local.len_tgw_subnets : 0 + + subnet_id = element(aws_subnet.tgw[*].id, count.index) + route_table_id = element( + aws_route_table.tgw[*].id, + var.create_multiple_tgw_route_tables ? count.index : 0 + ) +} + +################################################################################ +# TGW Network ACLs +################################################################################ + +locals { + tgw_network_acl = local.create_tgw_subnets && var.tgw_dedicated_network_acl +} + +resource "aws_network_acl" "tgw" { + count = local.tgw_network_acl ? 1 : 0 + + vpc_id = local.vpc_id + subnet_ids = aws_subnet.tgw[*].id + + tags = merge( + { + "Name" = format("%s-%s-nacl-%s", var.name_prefix, var.short_aws_region, var.tgw_subnet_suffix) + }, + var.tags, + var.tgw_acl_tags, + ) +} + +resource "aws_network_acl_rule" "tgw_inbound" { + count = local.tgw_network_acl ? length(var.tgw_inbound_acl_rules) : 0 + + network_acl_id = aws_network_acl.tgw[0].id # TODO: Fixed + + egress = false + rule_number = var.tgw_inbound_acl_rules[count.index]["rule_number"] + rule_action = var.tgw_inbound_acl_rules[count.index]["rule_action"] + from_port = lookup(var.tgw_inbound_acl_rules[count.index], "from_port", null) + to_port = lookup(var.tgw_inbound_acl_rules[count.index], "to_port", null) + icmp_code = lookup(var.tgw_inbound_acl_rules[count.index], "icmp_code", null) + icmp_type = lookup(var.tgw_inbound_acl_rules[count.index], "icmp_type", null) + protocol = var.tgw_inbound_acl_rules[count.index]["protocol"] + cidr_block = lookup(var.tgw_inbound_acl_rules[count.index], "cidr_block", null) + ipv6_cidr_block = lookup(var.tgw_inbound_acl_rules[count.index], "ipv6_cidr_block", null) +} + +resource "aws_network_acl_rule" "tgw_outbound" { + count = local.tgw_network_acl ? length(var.tgw_outbound_acl_rules) : 0 + + network_acl_id = aws_network_acl.tgw[0].id + + egress = true + rule_number = var.tgw_outbound_acl_rules[count.index]["rule_number"] + rule_action = var.tgw_outbound_acl_rules[count.index]["rule_action"] + from_port = lookup(var.tgw_outbound_acl_rules[count.index], "from_port", null) + to_port = lookup(var.tgw_outbound_acl_rules[count.index], "to_port", null) + icmp_code = lookup(var.tgw_outbound_acl_rules[count.index], "icmp_code", null) + icmp_type = lookup(var.tgw_outbound_acl_rules[count.index], "icmp_type", null) + protocol = var.tgw_outbound_acl_rules[count.index]["protocol"] + cidr_block = lookup(var.tgw_outbound_acl_rules[count.index], "cidr_block", null) + ipv6_cidr_block = lookup(var.tgw_outbound_acl_rules[count.index], "ipv6_cidr_block", null) +} + +# Transit Gateway VPC attachment +resource "aws_ec2_transit_gateway_vpc_attachment" "tgw" { + count = var.enable_tgw_attachment ? 1 : 0 + + subnet_ids = aws_subnet.tgw[*].id + transit_gateway_id = var.transit_gateway_id + vpc_id = local.vpc_id + + tags = merge( + { Name = "${var.name_prefix}-${var.short_aws_region}-tgw-att" } + ) +} + +resource "aws_route" "tgw_nat_gateway" { + count = local.create_vpc && var.enable_tgw_nat_gateway ? local.nat_gateway_count : 0 + + route_table_id = element(aws_route_table.tgw[*].id, count.index) + destination_cidr_block = var.nat_gateway_destination_cidr_block + nat_gateway_id = element(aws_nat_gateway.this[*].id, count.index) + + timeouts { + create = "5m" + } + depends_on = [aws_ec2_transit_gateway_vpc_attachment.tgw] +} + +resource "aws_route" "tgw_dns64_nat_gateway" { + count = local.create_vpc && var.enable_tgw_nat_gateway && var.enable_ipv6 && var.tgw_subnet_enable_dns64 ? local.nat_gateway_count : 0 + + route_table_id = element(aws_route_table.tgw[*].id, count.index) + destination_ipv6_cidr_block = "64:ff9b::/96" + nat_gateway_id = element(aws_nat_gateway.this[*].id, count.index) + + timeouts { + create = "5m" + } + depends_on = [aws_ec2_transit_gateway_vpc_attachment.tgw] +} + +locals { + create_public_to_tgw = (local.create_public_subnets && contains(local.subnets_tgw_routed, "public")) + public_to_tgw_cidr_pairs = local.create_public_to_tgw ? flatten([ + for public_rtb in aws_route_table.public : [ + for cidr in var.transit_gateway_routes["public"]: { + rtb_id = public_rtb.id + cidr = cidr + } + ] + ]) : [] +} + +resource "aws_route" "public_to_tgw" { + for_each = local.create_public_to_tgw ? {for i, v in local.public_to_tgw_cidr_pairs : "${i}-${v.cidr}" => v} : {} + + destination_cidr_block = can(regex("^pl-", each.value.cidr)) ? null : each.value.cidr + destination_prefix_list_id = can(regex("^pl-", each.value.cidr)) ? each.value.cidr : null + + transit_gateway_id = var.transit_gateway_id + route_table_id = each.value.rtb_id + + depends_on = [aws_ec2_transit_gateway_vpc_attachment.tgw] +} + +# Route: IPv4 routes from private subnets to the Transit Gateway (if configured in var.transit_gateway_routes) +locals { + create_private_to_tgw = (local.create_private_subnets && contains(local.subnets_tgw_routed, "private")) + private_to_tgw_cidr_pairs = local.create_private_to_tgw ? flatten([ + for private_rtb in aws_route_table.private : [ + for cidr in var.transit_gateway_routes["private"]: { + rtb_id = private_rtb.id + cidr = cidr + } + ] + ]) : [] +} + +resource "aws_route" "private_to_tgw" { + for_each = local.create_private_to_tgw ? {for i, v in local.private_to_tgw_cidr_pairs : "${i}-${v.cidr}" => v} : {} + + destination_cidr_block = can(regex("^pl-", each.value.cidr)) ? null : each.value.cidr + destination_prefix_list_id = can(regex("^pl-", each.value.cidr)) ? each.value.cidr : null + + transit_gateway_id = var.transit_gateway_id + route_table_id = each.value.rtb_id + + depends_on = [aws_ec2_transit_gateway_vpc_attachment.tgw] +} diff --git a/variables.tf b/variables.tf index 8bfae5164..bfd56e37d 100644 --- a/variables.tf +++ b/variables.tf @@ -14,6 +14,23 @@ variable "name" { default = "" } +variable "name_prefix" { + description = "Name to be used on all the resources as identifier" + type = string + default = "" +} + +variable "short_aws_region" { + type = string + description = "The AWS region code where the VPC will be created" +} + +variable "vpc_name_suffix" { + description = "Name suffix for more detailed resource description" + type = string + default = "main" +} + variable "cidr" { description = "(Optional) The IPv4 CIDR block for the VPC. CIDR can be explicitly set or it can be derived from IPAM using `ipv4_netmask_length` & `ipv4_ipam_pool_id`" type = string @@ -38,6 +55,12 @@ variable "azs" { default = [] } +variable "az_name_to_az_id" { + description = "A map of availability zones names to ids in the account" + type = map(string) + default = {} +} + variable "enable_dns_hostnames" { description = "Should be true to enable DNS hostnames in the VPC" type = bool @@ -1240,6 +1263,12 @@ variable "nat_eip_tags" { default = {} } +variable "enable_tgw_nat_gateway" { + description = "Should be true if you want to provision NAT Gateways for each of your TGW networks" + type = bool + default = false +} + ################################################################################ # Customer Gateways ################################################################################ @@ -1638,3 +1667,171 @@ variable "putin_khuylo" { type = bool default = true } + +################################################################################ +# Transit Gateway +################################################################################ + +variable "transit_gateway_id" { + type = string + description = "Transit gateway id to attach the VPC to. Required when `transit_gateway` subnet is defined." + default = null +} + +variable "transit_gateway_routes" { + description = <<-EOF + Configuration of route(s) to transit gateway. + For each `public` and/or `private` subnets named in the `subnets` variable, + Optionally create routes from the subnet to transit gateway. Specify the CIDR range or a + prefix-list-id that you want routed to the transit gateway. + Example: + ``` + transit_gateway_routes = { + public = ["10.0.0.0/8"] + private = ["pl-123"] + } + ``` +EOF + type = any + default = {} +} + +################################################################################ +# TGW Subnets +################################################################################ + +variable "enable_tgw_attachment" { + description = "Enable Transit Gateway Attachment" + type = bool + default = false +} + +variable "tgw_subnets" { + description = "A list of tgw subnets inside the VPC" + type = list(string) + default = [] +} + +variable "tgw_subnet_assign_ipv6_address_on_creation" { + description = "Specify true to indicate that network interfaces created in the specified subnet should be assigned an IPv6 address. Default is `false`" + type = bool + default = false +} + +variable "tgw_subnet_enable_dns64" { + description = "Indicates whether DNS queries made to the Amazon-provided DNS Resolver in this subnet should return synthetic IPv6 addresses for IPv4-only destinations. Default: `true`" + type = bool + default = true +} + +variable "tgw_subnet_enable_resource_name_dns_aaaa_record_on_launch" { + description = "Indicates whether to respond to DNS queries for instance hostnames with DNS AAAA records. Default: `true`" + type = bool + default = true +} + +variable "tgw_subnet_enable_resource_name_dns_a_record_on_launch" { + description = "Indicates whether to respond to DNS queries for instance hostnames with DNS A records. Default: `false`" + type = bool + default = false +} + +variable "tgw_subnet_ipv6_prefixes" { + description = "Assigns IPv6 tgw subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list" + type = list(string) + default = [] +} + +variable "tgw_subnet_ipv6_native" { + description = "Indicates whether to create an IPv6-only subnet. Default: `false`" + type = bool + default = false +} + +variable "tgw_subnet_private_dns_hostname_type_on_launch" { + description = "The type of hostnames to assign to instances in the subnet at launch. For IPv6-only subnets, an instance DNS name must be based on the instance ID. For dual-stack and IPv4-only subnets, you can specify whether DNS names use the instance IPv4 address or the instance ID. Valid values: `ip-name`, `resource-name`" + type = string + default = null +} + +variable "tgw_subnet_names" { + description = "Explicit values to use in the Name tag on tgw subnets. If empty, Name tags are generated" + type = list(string) + default = [] +} + +variable "tgw_subnet_suffix" { + description = "Suffix to append to tgw subnets name" + type = string + default = "tgw" +} + +variable "tgw_subnet_tags" { + description = "Additional tags for the tgw subnets" + type = map(string) + default = {} +} + +variable "tgw_subnet_tags_per_az" { + description = "Additional tags for the tgw subnets where the primary key is the AZ" + type = map(map(string)) + default = {} +} + +variable "tgw_route_table_tags" { + description = "Additional tags for the tgw route tables" + type = map(string) + default = {} +} + +variable "create_multiple_tgw_route_tables" { + description = "Indicates whether to create a separate route table for each TGW subnet. Default: `false`" + type = bool + default = true +} + +################################################################################ +# TGW Network ACLs +################################################################################ + +variable "tgw_dedicated_network_acl" { + description = "Whether to use dedicated network ACL (not default) and custom rules for tgw subnets" + type = bool + default = false +} + +variable "tgw_inbound_acl_rules" { + description = "TGW subnets inbound network ACLs" + type = list(map(string)) + default = [ + { + rule_number = 100 + rule_action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + ] +} + +variable "tgw_outbound_acl_rules" { + description = "TGW subnets outbound network ACLs" + type = list(map(string)) + default = [ + { + rule_number = 100 + rule_action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + ] +} + +variable "tgw_acl_tags" { + description = "Additional tags for the tgw subnets network ACL" + type = map(string) + default = {} +}