From c78c640b232f0f8f2fb8e1a1992f17f08438531b Mon Sep 17 00:00:00 2001 From: Roman Eremeev Date: Wed, 16 Jul 2025 19:15:54 +0200 Subject: [PATCH 1/7] chore: pre-commit autoupdate --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 837f45982..626bd79c5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.99.0 + rev: v1.99.5 hooks: - id: terraform_fmt - id: terraform_docs From ef24f75c213c75597323386118205399a0422dee Mon Sep 17 00:00:00 2001 From: Roman Eremeev Date: Wed, 16 Jul 2025 20:03:47 +0200 Subject: [PATCH 2/7] feat: add support for region (Enhanced Region Support) - added `region` input variable - updated docs --- README.md | 1 + main.tf | 148 +++++++++++++++++++++++++++++++++++++++++++++++ variables.tf | 6 ++ vpc-flow-logs.tf | 6 ++ 4 files changed, 161 insertions(+) diff --git a/README.md b/README.md index da2482379..11d939520 100644 --- a/README.md +++ b/README.md @@ -579,6 +579,7 @@ No modules. | [redshift\_subnet\_suffix](#input\_redshift\_subnet\_suffix) | Suffix to append to redshift subnets name | `string` | `"redshift"` | no | | [redshift\_subnet\_tags](#input\_redshift\_subnet\_tags) | Additional tags for the redshift subnets | `map(string)` | `{}` | no | | [redshift\_subnets](#input\_redshift\_subnets) | A list of redshift subnets inside the VPC | `list(string)` | `[]` | no | +| [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the region set in the provider configuration | `string` | `null` | no | | [reuse\_nat\_ips](#input\_reuse\_nat\_ips) | Should be true if you don't want EIPs to be created for your NAT Gateways and will instead pass them in via the 'external\_nat\_ip\_ids' variable | `bool` | `false` | no | | [secondary\_cidr\_blocks](#input\_secondary\_cidr\_blocks) | List of secondary CIDR blocks to associate with the VPC to extend the IP Address pool | `list(string)` | `[]` | no | | [single\_nat\_gateway](#input\_single\_nat\_gateway) | Should be true if you want to provision a single shared NAT Gateway across all of your private networks | `bool` | `false` | no | diff --git a/main.tf b/main.tf index 618aa2c10..83b32c1a9 100644 --- a/main.tf +++ b/main.tf @@ -28,6 +28,8 @@ locals { resource "aws_vpc" "this" { count = local.create_vpc ? 1 : 0 + region = var.region + cidr_block = var.use_ipam_pool ? null : var.cidr ipv4_ipam_pool_id = var.ipv4_ipam_pool_id ipv4_netmask_length = var.ipv4_netmask_length @@ -53,6 +55,8 @@ resource "aws_vpc" "this" { resource "aws_vpc_ipv4_cidr_block_association" "this" { count = local.create_vpc && length(var.secondary_cidr_blocks) > 0 ? length(var.secondary_cidr_blocks) : 0 + region = var.region + # Do not turn this into `local.vpc_id` vpc_id = aws_vpc.this[0].id @@ -62,12 +66,16 @@ resource "aws_vpc_ipv4_cidr_block_association" "this" { resource "aws_vpc_block_public_access_options" "this" { count = local.create_vpc && length(keys(var.vpc_block_public_access_options)) > 0 ? 1 : 0 + region = var.region + internet_gateway_block_mode = try(var.vpc_block_public_access_options["internet_gateway_block_mode"], null) } resource "aws_vpc_block_public_access_exclusion" "this" { for_each = { for k, v in var.vpc_block_public_access_exclusions : k => v if local.create_vpc } + region = var.region + vpc_id = try(each.value.exclude_vpc, false) ? local.vpc_id : null subnet_id = try(each.value.exclude_subnet, false) ? lookup( @@ -99,6 +107,8 @@ resource "aws_vpc_block_public_access_exclusion" "this" { resource "aws_vpc_dhcp_options" "this" { count = local.create_vpc && var.enable_dhcp_options ? 1 : 0 + region = var.region + domain_name = var.dhcp_options_domain_name domain_name_servers = var.dhcp_options_domain_name_servers ntp_servers = var.dhcp_options_ntp_servers @@ -116,6 +126,8 @@ resource "aws_vpc_dhcp_options" "this" { resource "aws_vpc_dhcp_options_association" "this" { count = local.create_vpc && var.enable_dhcp_options ? 1 : 0 + region = var.region + vpc_id = local.vpc_id dhcp_options_id = aws_vpc_dhcp_options.this[0].id } @@ -131,6 +143,8 @@ locals { resource "aws_subnet" "public" { count = local.create_public_subnets && (!var.one_nat_gateway_per_az || local.len_public_subnets >= length(var.azs)) ? local.len_public_subnets : 0 + region = var.region + assign_ipv6_address_on_creation = var.enable_ipv6 && var.public_subnet_ipv6_native ? true : var.public_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 @@ -164,6 +178,8 @@ locals { resource "aws_route_table" "public" { count = local.create_public_subnets ? local.num_public_route_tables : 0 + region = var.region + vpc_id = local.vpc_id tags = merge( @@ -181,6 +197,8 @@ resource "aws_route_table" "public" { resource "aws_route_table_association" "public" { count = local.create_public_subnets ? local.len_public_subnets : 0 + region = var.region + subnet_id = element(aws_subnet.public[*].id, count.index) route_table_id = element(aws_route_table.public[*].id, var.create_multiple_public_route_tables ? count.index : 0) } @@ -188,6 +206,8 @@ resource "aws_route_table_association" "public" { resource "aws_route" "public_internet_gateway" { count = local.create_public_subnets && var.create_igw ? local.num_public_route_tables : 0 + region = var.region + route_table_id = aws_route_table.public[count.index].id destination_cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.this[0].id @@ -200,6 +220,8 @@ resource "aws_route" "public_internet_gateway" { resource "aws_route" "public_internet_gateway_ipv6" { count = local.create_public_subnets && var.create_igw && var.enable_ipv6 ? local.num_public_route_tables : 0 + region = var.region + route_table_id = aws_route_table.public[count.index].id destination_ipv6_cidr_block = "::/0" gateway_id = aws_internet_gateway.this[0].id @@ -212,6 +234,8 @@ resource "aws_route" "public_internet_gateway_ipv6" { resource "aws_network_acl" "public" { count = local.create_public_subnets && var.public_dedicated_network_acl ? 1 : 0 + region = var.region + vpc_id = local.vpc_id subnet_ids = aws_subnet.public[*].id @@ -225,6 +249,8 @@ resource "aws_network_acl" "public" { resource "aws_network_acl_rule" "public_inbound" { count = local.create_public_subnets && var.public_dedicated_network_acl ? length(var.public_inbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.public[0].id egress = false @@ -242,6 +268,8 @@ resource "aws_network_acl_rule" "public_inbound" { resource "aws_network_acl_rule" "public_outbound" { count = local.create_public_subnets && var.public_dedicated_network_acl ? length(var.public_outbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.public[0].id egress = true @@ -267,6 +295,8 @@ locals { resource "aws_subnet" "private" { count = local.create_private_subnets ? local.len_private_subnets : 0 + region = var.region + assign_ipv6_address_on_creation = var.enable_ipv6 && var.private_subnet_ipv6_native ? true : var.private_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 @@ -296,6 +326,8 @@ resource "aws_subnet" "private" { resource "aws_route_table" "private" { count = local.create_private_subnets && local.max_subnet_length > 0 ? local.nat_gateway_count : 0 + region = var.region + vpc_id = local.vpc_id tags = merge( @@ -313,6 +345,8 @@ resource "aws_route_table" "private" { resource "aws_route_table_association" "private" { count = local.create_private_subnets ? local.len_private_subnets : 0 + region = var.region + subnet_id = element(aws_subnet.private[*].id, count.index) route_table_id = element( aws_route_table.private[*].id, @@ -331,6 +365,8 @@ locals { resource "aws_network_acl" "private" { count = local.create_private_network_acl ? 1 : 0 + region = var.region + vpc_id = local.vpc_id subnet_ids = aws_subnet.private[*].id @@ -344,6 +380,8 @@ resource "aws_network_acl" "private" { resource "aws_network_acl_rule" "private_inbound" { count = local.create_private_network_acl ? length(var.private_inbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.private[0].id egress = false @@ -361,6 +399,8 @@ resource "aws_network_acl_rule" "private_inbound" { resource "aws_network_acl_rule" "private_outbound" { count = local.create_private_network_acl ? length(var.private_outbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.private[0].id egress = true @@ -387,6 +427,8 @@ locals { resource "aws_subnet" "database" { count = local.create_database_subnets ? local.len_database_subnets : 0 + region = var.region + assign_ipv6_address_on_creation = var.enable_ipv6 && var.database_subnet_ipv6_native ? true : var.database_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 @@ -414,6 +456,8 @@ resource "aws_subnet" "database" { resource "aws_db_subnet_group" "database" { count = local.create_database_subnets && var.create_database_subnet_group ? 1 : 0 + region = var.region + name = lower(coalesce(var.database_subnet_group_name, var.name)) description = "Database subnet group for ${var.name}" subnet_ids = aws_subnet.database[*].id @@ -430,6 +474,8 @@ resource "aws_db_subnet_group" "database" { resource "aws_route_table" "database" { count = local.create_database_route_table ? var.single_nat_gateway || var.create_database_internet_gateway_route ? 1 : local.len_database_subnets : 0 + region = var.region + vpc_id = local.vpc_id tags = merge( @@ -447,6 +493,8 @@ resource "aws_route_table" "database" { resource "aws_route_table_association" "database" { count = local.create_database_subnets ? local.len_database_subnets : 0 + region = var.region + subnet_id = element(aws_subnet.database[*].id, count.index) route_table_id = element( coalescelist(aws_route_table.database[*].id, aws_route_table.private[*].id), @@ -457,6 +505,8 @@ resource "aws_route_table_association" "database" { resource "aws_route" "database_internet_gateway" { count = local.create_database_route_table && var.create_igw && var.create_database_internet_gateway_route && !var.create_database_nat_gateway_route ? 1 : 0 + region = var.region + route_table_id = aws_route_table.database[0].id destination_cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.this[0].id @@ -469,6 +519,8 @@ resource "aws_route" "database_internet_gateway" { resource "aws_route" "database_nat_gateway" { count = local.create_database_route_table && !var.create_database_internet_gateway_route && var.create_database_nat_gateway_route && var.enable_nat_gateway ? var.single_nat_gateway ? 1 : local.len_database_subnets : 0 + region = var.region + route_table_id = element(aws_route_table.database[*].id, count.index) destination_cidr_block = "0.0.0.0/0" nat_gateway_id = element(aws_nat_gateway.this[*].id, count.index) @@ -481,6 +533,8 @@ resource "aws_route" "database_nat_gateway" { resource "aws_route" "database_dns64_nat_gateway" { count = local.create_database_route_table && !var.create_database_internet_gateway_route && var.create_database_nat_gateway_route && var.enable_nat_gateway && var.enable_ipv6 && var.private_subnet_enable_dns64 ? var.single_nat_gateway ? 1 : local.len_database_subnets : 0 + region = var.region + route_table_id = element(aws_route_table.database[*].id, count.index) destination_ipv6_cidr_block = "64:ff9b::/96" nat_gateway_id = element(aws_nat_gateway.this[*].id, count.index) @@ -493,6 +547,8 @@ resource "aws_route" "database_dns64_nat_gateway" { resource "aws_route" "database_ipv6_egress" { count = local.create_database_route_table && var.create_egress_only_igw && var.enable_ipv6 && var.create_database_internet_gateway_route ? 1 : 0 + region = var.region + route_table_id = aws_route_table.database[0].id destination_ipv6_cidr_block = "::/0" egress_only_gateway_id = aws_egress_only_internet_gateway.this[0].id @@ -513,6 +569,8 @@ locals { resource "aws_network_acl" "database" { count = local.create_database_network_acl ? 1 : 0 + region = var.region + vpc_id = local.vpc_id subnet_ids = aws_subnet.database[*].id @@ -526,6 +584,8 @@ resource "aws_network_acl" "database" { resource "aws_network_acl_rule" "database_inbound" { count = local.create_database_network_acl ? length(var.database_inbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.database[0].id egress = false @@ -543,6 +603,8 @@ resource "aws_network_acl_rule" "database_inbound" { resource "aws_network_acl_rule" "database_outbound" { count = local.create_database_network_acl ? length(var.database_outbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.database[0].id egress = true @@ -569,6 +631,8 @@ locals { resource "aws_subnet" "redshift" { count = local.create_redshift_subnets ? local.len_redshift_subnets : 0 + region = var.region + assign_ipv6_address_on_creation = var.enable_ipv6 && var.redshift_subnet_ipv6_native ? true : var.redshift_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 @@ -596,6 +660,8 @@ resource "aws_subnet" "redshift" { resource "aws_redshift_subnet_group" "redshift" { count = local.create_redshift_subnets && var.create_redshift_subnet_group ? 1 : 0 + region = var.region + name = lower(coalesce(var.redshift_subnet_group_name, var.name)) description = "Redshift subnet group for ${var.name}" subnet_ids = aws_subnet.redshift[*].id @@ -610,6 +676,8 @@ resource "aws_redshift_subnet_group" "redshift" { resource "aws_route_table" "redshift" { count = local.create_redshift_route_table ? 1 : 0 + region = var.region + vpc_id = local.vpc_id tags = merge( @@ -622,6 +690,8 @@ resource "aws_route_table" "redshift" { resource "aws_route_table_association" "redshift" { count = local.create_redshift_subnets && !var.enable_public_redshift ? local.len_redshift_subnets : 0 + region = var.region + subnet_id = element(aws_subnet.redshift[*].id, count.index) route_table_id = element( coalescelist(aws_route_table.redshift[*].id, aws_route_table.private[*].id), @@ -632,6 +702,8 @@ resource "aws_route_table_association" "redshift" { resource "aws_route_table_association" "redshift_public" { count = local.create_redshift_subnets && var.enable_public_redshift ? local.len_redshift_subnets : 0 + region = var.region + subnet_id = element(aws_subnet.redshift[*].id, count.index) route_table_id = element( coalescelist(aws_route_table.redshift[*].id, aws_route_table.public[*].id), @@ -650,6 +722,8 @@ locals { resource "aws_network_acl" "redshift" { count = local.create_redshift_network_acl ? 1 : 0 + region = var.region + vpc_id = local.vpc_id subnet_ids = aws_subnet.redshift[*].id @@ -663,6 +737,8 @@ resource "aws_network_acl" "redshift" { resource "aws_network_acl_rule" "redshift_inbound" { count = local.create_redshift_network_acl ? length(var.redshift_inbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.redshift[0].id egress = false @@ -680,6 +756,8 @@ resource "aws_network_acl_rule" "redshift_inbound" { resource "aws_network_acl_rule" "redshift_outbound" { count = local.create_redshift_network_acl ? length(var.redshift_outbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.redshift[0].id egress = true @@ -706,6 +784,8 @@ locals { resource "aws_subnet" "elasticache" { count = local.create_elasticache_subnets ? local.len_elasticache_subnets : 0 + region = var.region + assign_ipv6_address_on_creation = var.enable_ipv6 && var.elasticache_subnet_ipv6_native ? true : var.elasticache_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 @@ -733,6 +813,8 @@ resource "aws_subnet" "elasticache" { resource "aws_elasticache_subnet_group" "elasticache" { count = local.create_elasticache_subnets && var.create_elasticache_subnet_group ? 1 : 0 + region = var.region + name = coalesce(var.elasticache_subnet_group_name, var.name) description = "ElastiCache subnet group for ${var.name}" subnet_ids = aws_subnet.elasticache[*].id @@ -747,6 +829,8 @@ resource "aws_elasticache_subnet_group" "elasticache" { resource "aws_route_table" "elasticache" { count = local.create_elasticache_route_table ? 1 : 0 + region = var.region + vpc_id = local.vpc_id tags = merge( @@ -759,6 +843,8 @@ resource "aws_route_table" "elasticache" { resource "aws_route_table_association" "elasticache" { count = local.create_elasticache_subnets ? local.len_elasticache_subnets : 0 + region = var.region + subnet_id = element(aws_subnet.elasticache[*].id, count.index) route_table_id = element( coalescelist( @@ -780,6 +866,8 @@ locals { resource "aws_network_acl" "elasticache" { count = local.create_elasticache_network_acl ? 1 : 0 + region = var.region + vpc_id = local.vpc_id subnet_ids = aws_subnet.elasticache[*].id @@ -793,6 +881,8 @@ resource "aws_network_acl" "elasticache" { resource "aws_network_acl_rule" "elasticache_inbound" { count = local.create_elasticache_network_acl ? length(var.elasticache_inbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.elasticache[0].id egress = false @@ -810,6 +900,8 @@ resource "aws_network_acl_rule" "elasticache_inbound" { resource "aws_network_acl_rule" "elasticache_outbound" { count = local.create_elasticache_network_acl ? length(var.elasticache_outbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.elasticache[0].id egress = true @@ -835,6 +927,8 @@ locals { resource "aws_subnet" "intra" { count = local.create_intra_subnets ? local.len_intra_subnets : 0 + region = var.region + assign_ipv6_address_on_creation = var.enable_ipv6 && var.intra_subnet_ipv6_native ? true : var.intra_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 @@ -866,6 +960,8 @@ locals { resource "aws_route_table" "intra" { count = local.create_intra_subnets ? local.num_intra_route_tables : 0 + region = var.region + vpc_id = local.vpc_id tags = merge( @@ -883,6 +979,8 @@ resource "aws_route_table" "intra" { resource "aws_route_table_association" "intra" { count = local.create_intra_subnets ? local.len_intra_subnets : 0 + region = var.region + subnet_id = element(aws_subnet.intra[*].id, count.index) route_table_id = element(aws_route_table.intra[*].id, var.create_multiple_intra_route_tables ? count.index : 0) } @@ -898,6 +996,8 @@ locals { resource "aws_network_acl" "intra" { count = local.create_intra_network_acl ? 1 : 0 + region = var.region + vpc_id = local.vpc_id subnet_ids = aws_subnet.intra[*].id @@ -911,6 +1011,8 @@ resource "aws_network_acl" "intra" { resource "aws_network_acl_rule" "intra_inbound" { count = local.create_intra_network_acl ? length(var.intra_inbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.intra[0].id egress = false @@ -928,6 +1030,8 @@ resource "aws_network_acl_rule" "intra_inbound" { resource "aws_network_acl_rule" "intra_outbound" { count = local.create_intra_network_acl ? length(var.intra_outbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.intra[0].id egress = true @@ -953,6 +1057,8 @@ locals { resource "aws_subnet" "outpost" { count = local.create_outpost_subnets ? local.len_outpost_subnets : 0 + region = var.region + assign_ipv6_address_on_creation = var.enable_ipv6 && var.outpost_subnet_ipv6_native ? true : var.outpost_subnet_assign_ipv6_address_on_creation availability_zone = var.outpost_az cidr_block = var.outpost_subnet_ipv6_native ? null : element(concat(var.outpost_subnets, [""]), count.index) @@ -982,6 +1088,8 @@ resource "aws_subnet" "outpost" { resource "aws_route_table_association" "outpost" { count = local.create_outpost_subnets ? local.len_outpost_subnets : 0 + region = var.region + subnet_id = element(aws_subnet.outpost[*].id, count.index) route_table_id = element( aws_route_table.private[*].id, @@ -1000,6 +1108,8 @@ locals { resource "aws_network_acl" "outpost" { count = local.create_outpost_network_acl ? 1 : 0 + region = var.region + vpc_id = local.vpc_id subnet_ids = aws_subnet.outpost[*].id @@ -1013,6 +1123,8 @@ resource "aws_network_acl" "outpost" { resource "aws_network_acl_rule" "outpost_inbound" { count = local.create_outpost_network_acl ? length(var.outpost_inbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.outpost[0].id egress = false @@ -1030,6 +1142,8 @@ resource "aws_network_acl_rule" "outpost_inbound" { resource "aws_network_acl_rule" "outpost_outbound" { count = local.create_outpost_network_acl ? length(var.outpost_outbound_acl_rules) : 0 + region = var.region + network_acl_id = aws_network_acl.outpost[0].id egress = true @@ -1051,6 +1165,8 @@ resource "aws_network_acl_rule" "outpost_outbound" { resource "aws_internet_gateway" "this" { count = local.create_public_subnets && var.create_igw ? 1 : 0 + region = var.region + vpc_id = local.vpc_id tags = merge( @@ -1063,6 +1179,8 @@ resource "aws_internet_gateway" "this" { resource "aws_egress_only_internet_gateway" "this" { count = local.create_vpc && var.create_egress_only_igw && var.enable_ipv6 && local.max_subnet_length > 0 ? 1 : 0 + region = var.region + vpc_id = local.vpc_id tags = merge( @@ -1075,6 +1193,8 @@ resource "aws_egress_only_internet_gateway" "this" { resource "aws_route" "private_ipv6_egress" { count = local.create_vpc && var.create_egress_only_igw && var.enable_ipv6 && local.len_private_subnets > 0 ? local.nat_gateway_count : 0 + region = var.region + route_table_id = element(aws_route_table.private[*].id, count.index) destination_ipv6_cidr_block = "::/0" egress_only_gateway_id = element(aws_egress_only_internet_gateway.this[*].id, 0) @@ -1092,6 +1212,8 @@ locals { resource "aws_eip" "nat" { count = local.create_vpc && var.enable_nat_gateway && !var.reuse_nat_ips ? local.nat_gateway_count : 0 + region = var.region + domain = "vpc" tags = merge( @@ -1111,6 +1233,8 @@ resource "aws_eip" "nat" { resource "aws_nat_gateway" "this" { count = local.create_vpc && var.enable_nat_gateway ? local.nat_gateway_count : 0 + region = var.region + allocation_id = element( local.nat_gateway_ips, var.single_nat_gateway ? 0 : count.index, @@ -1137,6 +1261,8 @@ resource "aws_nat_gateway" "this" { resource "aws_route" "private_nat_gateway" { count = local.create_vpc && var.enable_nat_gateway && var.create_private_nat_gateway_route ? local.nat_gateway_count : 0 + region = var.region + route_table_id = element(aws_route_table.private[*].id, count.index) destination_cidr_block = var.nat_gateway_destination_cidr_block nat_gateway_id = element(aws_nat_gateway.this[*].id, count.index) @@ -1149,6 +1275,8 @@ resource "aws_route" "private_nat_gateway" { resource "aws_route" "private_dns64_nat_gateway" { count = local.create_vpc && var.enable_nat_gateway && var.enable_ipv6 && var.private_subnet_enable_dns64 ? local.nat_gateway_count : 0 + region = var.region + route_table_id = element(aws_route_table.private[*].id, count.index) destination_ipv6_cidr_block = "64:ff9b::/96" nat_gateway_id = element(aws_nat_gateway.this[*].id, count.index) @@ -1165,6 +1293,8 @@ resource "aws_route" "private_dns64_nat_gateway" { resource "aws_customer_gateway" "this" { for_each = var.customer_gateways + region = var.region + bgp_asn = each.value["bgp_asn"] ip_address = each.value["ip_address"] device_name = lookup(each.value, "device_name", null) @@ -1188,6 +1318,8 @@ resource "aws_customer_gateway" "this" { resource "aws_vpn_gateway" "this" { count = local.create_vpc && var.enable_vpn_gateway ? 1 : 0 + region = var.region + vpc_id = local.vpc_id amazon_side_asn = var.amazon_side_asn availability_zone = var.vpn_gateway_az @@ -1202,6 +1334,8 @@ resource "aws_vpn_gateway" "this" { resource "aws_vpn_gateway_attachment" "this" { count = var.vpn_gateway_id != "" ? 1 : 0 + region = var.region + vpc_id = local.vpc_id vpn_gateway_id = var.vpn_gateway_id } @@ -1209,6 +1343,8 @@ resource "aws_vpn_gateway_attachment" "this" { resource "aws_vpn_gateway_route_propagation" "public" { count = local.create_vpc && var.propagate_public_route_tables_vgw && (var.enable_vpn_gateway || var.vpn_gateway_id != "") ? 1 : 0 + region = var.region + route_table_id = element(aws_route_table.public[*].id, count.index) vpn_gateway_id = element( concat( @@ -1222,6 +1358,8 @@ resource "aws_vpn_gateway_route_propagation" "public" { resource "aws_vpn_gateway_route_propagation" "private" { count = local.create_vpc && var.propagate_private_route_tables_vgw && (var.enable_vpn_gateway || var.vpn_gateway_id != "") ? local.len_private_subnets : 0 + region = var.region + route_table_id = element(aws_route_table.private[*].id, count.index) vpn_gateway_id = element( concat( @@ -1235,6 +1373,8 @@ resource "aws_vpn_gateway_route_propagation" "private" { resource "aws_vpn_gateway_route_propagation" "intra" { count = local.create_vpc && var.propagate_intra_route_tables_vgw && (var.enable_vpn_gateway || var.vpn_gateway_id != "") ? local.len_intra_subnets : 0 + region = var.region + route_table_id = element(aws_route_table.intra[*].id, count.index) vpn_gateway_id = element( concat( @@ -1252,6 +1392,8 @@ resource "aws_vpn_gateway_route_propagation" "intra" { resource "aws_default_vpc" "this" { count = var.manage_default_vpc ? 1 : 0 + region = var.region + enable_dns_support = var.default_vpc_enable_dns_support enable_dns_hostnames = var.default_vpc_enable_dns_hostnames @@ -1265,6 +1407,8 @@ resource "aws_default_vpc" "this" { resource "aws_default_security_group" "this" { count = local.create_vpc && var.manage_default_security_group ? 1 : 0 + region = var.region + vpc_id = aws_vpc.this[0].id dynamic "ingress" { @@ -1311,6 +1455,8 @@ resource "aws_default_security_group" "this" { resource "aws_default_network_acl" "this" { count = local.create_vpc && var.manage_default_network_acl ? 1 : 0 + region = var.region + default_network_acl_id = aws_vpc.this[0].default_network_acl_id # subnet_ids is using lifecycle ignore_changes, so it is not necessary to list @@ -1364,6 +1510,8 @@ resource "aws_default_network_acl" "this" { resource "aws_default_route_table" "default" { count = local.create_vpc && var.manage_default_route_table ? 1 : 0 + region = var.region + default_route_table_id = aws_vpc.this[0].default_route_table_id propagating_vgws = var.default_route_table_propagating_vgws diff --git a/variables.tf b/variables.tf index d8338267a..4451d1500 100644 --- a/variables.tf +++ b/variables.tf @@ -8,6 +8,12 @@ variable "create_vpc" { default = true } +variable "region" { + description = "Region where the resource(s) will be managed. Defaults to the region set in the provider configuration" + type = string + default = null +} + variable "name" { description = "Name to be used on all the resources as identifier" type = string diff --git a/vpc-flow-logs.tf b/vpc-flow-logs.tf index fc7ba90be..355291646 100644 --- a/vpc-flow-logs.tf +++ b/vpc-flow-logs.tf @@ -1,6 +1,8 @@ data "aws_region" "current" { # Call this API only if create_vpc and enable_flow_log are true count = var.create_vpc && var.enable_flow_log ? 1 : 0 + + region = var.region } data "aws_caller_identity" "current" { @@ -36,6 +38,8 @@ locals { resource "aws_flow_log" "this" { count = local.enable_flow_log ? 1 : 0 + region = var.region + log_destination_type = var.flow_log_destination_type log_destination = local.flow_log_destination_arn log_format = var.flow_log_log_format @@ -65,6 +69,8 @@ resource "aws_flow_log" "this" { resource "aws_cloudwatch_log_group" "flow_log" { count = local.create_flow_log_cloudwatch_log_group ? 1 : 0 + region = var.region + name = "${var.flow_log_cloudwatch_log_group_name_prefix}${local.flow_log_cloudwatch_log_group_name_suffix}" retention_in_days = var.flow_log_cloudwatch_log_group_retention_in_days kms_key_id = var.flow_log_cloudwatch_log_group_kms_key_id From 9fb07307ce9bf3426bf9233833a58454d4f43109 Mon Sep 17 00:00:00 2001 From: Roman Eremeev Date: Wed, 16 Jul 2025 20:04:24 +0200 Subject: [PATCH 3/7] feat: add support for region in `vpc-endpoints` module --- modules/vpc-endpoints/README.md | 1 + modules/vpc-endpoints/main.tf | 6 ++++++ modules/vpc-endpoints/variables.tf | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/modules/vpc-endpoints/README.md b/modules/vpc-endpoints/README.md index 5b734876b..69e4a79d8 100644 --- a/modules/vpc-endpoints/README.md +++ b/modules/vpc-endpoints/README.md @@ -95,6 +95,7 @@ No modules. | [create](#input\_create) | Determines whether resources will be created | `bool` | `true` | no | | [create\_security\_group](#input\_create\_security\_group) | Determines if a security group is created | `bool` | `false` | no | | [endpoints](#input\_endpoints) | A map of interface and/or gateway endpoints containing their properties and configurations | `any` | `{}` | no | +| [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the region set in the provider configuration | `string` | `null` | no | | [security\_group\_description](#input\_security\_group\_description) | Description of the security group created | `string` | `null` | no | | [security\_group\_ids](#input\_security\_group\_ids) | Default security group IDs to associate with the VPC endpoints | `list(string)` | `[]` | no | | [security\_group\_name](#input\_security\_group\_name) | Name to use on security group created. Conflicts with `security_group_name_prefix` | `string` | `null` | no | diff --git a/modules/vpc-endpoints/main.tf b/modules/vpc-endpoints/main.tf index 5e2d105b0..64560578d 100644 --- a/modules/vpc-endpoints/main.tf +++ b/modules/vpc-endpoints/main.tf @@ -24,6 +24,8 @@ data "aws_vpc_endpoint_service" "this" { resource "aws_vpc_endpoint" "this" { for_each = local.endpoints + region = var.region + vpc_id = var.vpc_id service_name = try(each.value.service_endpoint, data.aws_vpc_endpoint_service.this[each.key].service_name) service_region = try(each.value.service_region, null) @@ -76,6 +78,8 @@ resource "aws_vpc_endpoint" "this" { resource "aws_security_group" "this" { count = var.create && var.create_security_group ? 1 : 0 + region = var.region + name = var.security_group_name name_prefix = var.security_group_name_prefix description = var.security_group_description @@ -95,6 +99,8 @@ resource "aws_security_group" "this" { resource "aws_security_group_rule" "this" { for_each = { for k, v in var.security_group_rules : k => v if var.create && var.create_security_group } + region = var.region + # Required security_group_id = aws_security_group.this[0].id protocol = try(each.value.protocol, "tcp") diff --git a/modules/vpc-endpoints/variables.tf b/modules/vpc-endpoints/variables.tf index 30a747abd..f893e5502 100644 --- a/modules/vpc-endpoints/variables.tf +++ b/modules/vpc-endpoints/variables.tf @@ -4,6 +4,12 @@ variable "create" { default = true } +variable "region" { + description = "Region where the resource(s) will be managed. Defaults to the region set in the provider configuration" + type = string + default = null +} + variable "vpc_id" { description = "The ID of the VPC in which the endpoint will be used" type = string From dc910322d81c4a0988c8915b9b8aa6e19dab407c Mon Sep 17 00:00:00 2001 From: Roman Eremeev Date: Mon, 21 Jul 2025 19:36:57 +0200 Subject: [PATCH 4/7] Use `region` variable in `aws_vpc_endpoint_service` data source --- modules/vpc-endpoints/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vpc-endpoints/main.tf b/modules/vpc-endpoints/main.tf index 64560578d..590a26c78 100644 --- a/modules/vpc-endpoints/main.tf +++ b/modules/vpc-endpoints/main.tf @@ -13,7 +13,7 @@ data "aws_vpc_endpoint_service" "this" { service = try(each.value.service, null) service_name = try(each.value.service_name, null) - service_regions = try(coalescelist(compact([each.value.service_region])), null) + service_regions = try(coalescelist(compact([each.value.service_region])), [var.region], null) filter { name = "service-type" From a77de686c247ba08e26b11b3bfb057dbbdb3051c Mon Sep 17 00:00:00 2001 From: Roman Eremeev Date: Tue, 22 Jul 2025 19:10:34 +0200 Subject: [PATCH 5/7] Workaround for service endpoint lookup in the wrong region --- modules/vpc-endpoints/README.md | 1 + modules/vpc-endpoints/main.tf | 6 +++--- modules/vpc-endpoints/variables.tf | 6 ++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/vpc-endpoints/README.md b/modules/vpc-endpoints/README.md index 69e4a79d8..6e4f8894c 100644 --- a/modules/vpc-endpoints/README.md +++ b/modules/vpc-endpoints/README.md @@ -94,6 +94,7 @@ No modules. |------|-------------|------|---------|:--------:| | [create](#input\_create) | Determines whether resources will be created | `bool` | `true` | no | | [create\_security\_group](#input\_create\_security\_group) | Determines if a security group is created | `bool` | `false` | no | +| [enable\_service\_endpoint\_lookup](#input\_enable\_service\_endpoint\_lookup) | Determines whether to look up the service endpoint in the AWS API. If set to false, the `service_endpoint` attribute (usually in the form of `com.amazonaws..`) must be provided in the `endpoints` map | `bool` | `true` | no | | [endpoints](#input\_endpoints) | A map of interface and/or gateway endpoints containing their properties and configurations | `any` | `{}` | no | | [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the region set in the provider configuration | `string` | `null` | no | | [security\_group\_description](#input\_security\_group\_description) | Description of the security group created | `string` | `null` | no | diff --git a/modules/vpc-endpoints/main.tf b/modules/vpc-endpoints/main.tf index 590a26c78..dd3c645dc 100644 --- a/modules/vpc-endpoints/main.tf +++ b/modules/vpc-endpoints/main.tf @@ -9,11 +9,11 @@ locals { } data "aws_vpc_endpoint_service" "this" { - for_each = local.endpoints + for_each = { for k, v in local.endpoints : k => v if var.enable_service_endpoint_lookup } service = try(each.value.service, null) service_name = try(each.value.service_name, null) - service_regions = try(coalescelist(compact([each.value.service_region])), [var.region], null) + service_regions = try(coalescelist(compact([each.value.service_region])), null) filter { name = "service-type" @@ -27,7 +27,7 @@ resource "aws_vpc_endpoint" "this" { region = var.region vpc_id = var.vpc_id - service_name = try(each.value.service_endpoint, data.aws_vpc_endpoint_service.this[each.key].service_name) + service_name = try(data.aws_vpc_endpoint_service.this[each.key].service_name, each.value.service_endpoint) service_region = try(each.value.service_region, null) vpc_endpoint_type = try(each.value.service_type, "Interface") auto_accept = try(each.value.auto_accept, null) diff --git a/modules/vpc-endpoints/variables.tf b/modules/vpc-endpoints/variables.tf index f893e5502..2e1668d5c 100644 --- a/modules/vpc-endpoints/variables.tf +++ b/modules/vpc-endpoints/variables.tf @@ -22,6 +22,12 @@ variable "endpoints" { default = {} } +variable "enable_service_endpoint_lookup" { + description = "Determines whether to look up the service endpoint in the AWS API. If set to false, the `service_endpoint` attribute (usually in the form of `com.amazonaws..`) must be provided in the `endpoints` map" + type = bool + default = true +} + variable "security_group_ids" { description = "Default security group IDs to associate with the VPC endpoints" type = list(string) From 28d67e2cf94c984b030c0960e246582323bd8e21 Mon Sep 17 00:00:00 2001 From: Roman Eremeev Date: Wed, 20 Aug 2025 14:12:12 +0200 Subject: [PATCH 6/7] Add `simple-regions` example --- examples/simple-regions/README.md | 156 ++++++ examples/simple-regions/main.tf | 54 ++ examples/simple-regions/outputs.tf | 749 +++++++++++++++++++++++++++ examples/simple-regions/variables.tf | 0 examples/simple-regions/versions.tf | 10 + 5 files changed, 969 insertions(+) create mode 100644 examples/simple-regions/README.md create mode 100644 examples/simple-regions/main.tf create mode 100644 examples/simple-regions/outputs.tf create mode 100644 examples/simple-regions/variables.tf create mode 100644 examples/simple-regions/versions.tf diff --git a/examples/simple-regions/README.md b/examples/simple-regions/README.md new file mode 100644 index 000000000..acd1c3ca8 --- /dev/null +++ b/examples/simple-regions/README.md @@ -0,0 +1,156 @@ +# Simple Regional VPCs + +This configuration is meant to demonstrate the usage of the new `region` parameter, [available in aws provider >= 6.0.0](https://registry.terraform.io/providers/hashicorp/aws/6.0.0/docs/guides/enhanced-region-support), to create a set of VPCs in multiple regions. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [aws](#requirement\_aws) | >= 6.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 6.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [vpc](#module\_vpc) | ../../ | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | + +## Inputs + +No inputs. + +## Outputs + +| Name | Description | +|------|-------------| +| [cgw\_arns](#output\_cgw\_arns) | List of ARNs of Customer Gateway | +| [cgw\_ids](#output\_cgw\_ids) | List of IDs of Customer Gateway | +| [database\_internet\_gateway\_route\_id](#output\_database\_internet\_gateway\_route\_id) | ID of the database internet gateway route | +| [database\_ipv6\_egress\_route\_id](#output\_database\_ipv6\_egress\_route\_id) | ID of the database IPv6 egress route | +| [database\_nat\_gateway\_route\_ids](#output\_database\_nat\_gateway\_route\_ids) | List of IDs of the database nat gateway route | +| [database\_network\_acl\_arn](#output\_database\_network\_acl\_arn) | ARN of the database network ACL | +| [database\_network\_acl\_id](#output\_database\_network\_acl\_id) | ID of the database network ACL | +| [database\_route\_table\_association\_ids](#output\_database\_route\_table\_association\_ids) | List of IDs of the database route table association | +| [database\_route\_table\_ids](#output\_database\_route\_table\_ids) | List of IDs of database route tables | +| [database\_subnet\_arns](#output\_database\_subnet\_arns) | List of ARNs of database subnets | +| [database\_subnet\_group](#output\_database\_subnet\_group) | ID of database subnet group | +| [database\_subnet\_group\_name](#output\_database\_subnet\_group\_name) | Name of database subnet group | +| [database\_subnets](#output\_database\_subnets) | List of IDs of database subnets | +| [database\_subnets\_cidr\_blocks](#output\_database\_subnets\_cidr\_blocks) | List of cidr\_blocks of database subnets | +| [database\_subnets\_ipv6\_cidr\_blocks](#output\_database\_subnets\_ipv6\_cidr\_blocks) | List of IPv6 cidr\_blocks of database subnets in an IPv6 enabled VPC | +| [default\_network\_acl\_id](#output\_default\_network\_acl\_id) | The ID of the default network ACL | +| [default\_route\_table\_id](#output\_default\_route\_table\_id) | The ID of the default route table | +| [default\_security\_group\_id](#output\_default\_security\_group\_id) | The ID of the security group created by default on VPC creation | +| [default\_vpc\_arn](#output\_default\_vpc\_arn) | The ARN of the Default VPC | +| [default\_vpc\_cidr\_block](#output\_default\_vpc\_cidr\_block) | The CIDR block of the Default VPC | +| [default\_vpc\_default\_network\_acl\_id](#output\_default\_vpc\_default\_network\_acl\_id) | The ID of the default network ACL of the Default VPC | +| [default\_vpc\_default\_route\_table\_id](#output\_default\_vpc\_default\_route\_table\_id) | The ID of the default route table of the Default VPC | +| [default\_vpc\_default\_security\_group\_id](#output\_default\_vpc\_default\_security\_group\_id) | The ID of the security group created by default on Default VPC creation | +| [default\_vpc\_enable\_dns\_hostnames](#output\_default\_vpc\_enable\_dns\_hostnames) | Whether or not the Default VPC has DNS hostname support | +| [default\_vpc\_enable\_dns\_support](#output\_default\_vpc\_enable\_dns\_support) | Whether or not the Default VPC has DNS support | +| [default\_vpc\_id](#output\_default\_vpc\_id) | The ID of the Default VPC | +| [default\_vpc\_instance\_tenancy](#output\_default\_vpc\_instance\_tenancy) | Tenancy of instances spin up within Default VPC | +| [default\_vpc\_main\_route\_table\_id](#output\_default\_vpc\_main\_route\_table\_id) | The ID of the main route table associated with the Default VPC | +| [dhcp\_options\_id](#output\_dhcp\_options\_id) | The ID of the DHCP options | +| [egress\_only\_internet\_gateway\_id](#output\_egress\_only\_internet\_gateway\_id) | The ID of the egress only Internet Gateway | +| [elasticache\_network\_acl\_arn](#output\_elasticache\_network\_acl\_arn) | ARN of the elasticache network ACL | +| [elasticache\_network\_acl\_id](#output\_elasticache\_network\_acl\_id) | ID of the elasticache network ACL | +| [elasticache\_route\_table\_association\_ids](#output\_elasticache\_route\_table\_association\_ids) | List of IDs of the elasticache route table association | +| [elasticache\_route\_table\_ids](#output\_elasticache\_route\_table\_ids) | List of IDs of elasticache route tables | +| [elasticache\_subnet\_arns](#output\_elasticache\_subnet\_arns) | List of ARNs of elasticache subnets | +| [elasticache\_subnet\_group](#output\_elasticache\_subnet\_group) | ID of elasticache subnet group | +| [elasticache\_subnet\_group\_name](#output\_elasticache\_subnet\_group\_name) | Name of elasticache subnet group | +| [elasticache\_subnets](#output\_elasticache\_subnets) | List of IDs of elasticache subnets | +| [elasticache\_subnets\_cidr\_blocks](#output\_elasticache\_subnets\_cidr\_blocks) | List of cidr\_blocks of elasticache subnets | +| [elasticache\_subnets\_ipv6\_cidr\_blocks](#output\_elasticache\_subnets\_ipv6\_cidr\_blocks) | List of IPv6 cidr\_blocks of elasticache subnets in an IPv6 enabled VPC | +| [igw\_arn](#output\_igw\_arn) | The ARN of the Internet Gateway | +| [igw\_id](#output\_igw\_id) | The ID of the Internet Gateway | +| [intra\_network\_acl\_arn](#output\_intra\_network\_acl\_arn) | ARN of the intra network ACL | +| [intra\_network\_acl\_id](#output\_intra\_network\_acl\_id) | ID of the intra network ACL | +| [intra\_route\_table\_association\_ids](#output\_intra\_route\_table\_association\_ids) | List of IDs of the intra route table association | +| [intra\_route\_table\_ids](#output\_intra\_route\_table\_ids) | List of IDs of intra route tables | +| [intra\_subnet\_arns](#output\_intra\_subnet\_arns) | List of ARNs of intra subnets | +| [intra\_subnets](#output\_intra\_subnets) | List of IDs of intra subnets | +| [intra\_subnets\_cidr\_blocks](#output\_intra\_subnets\_cidr\_blocks) | List of cidr\_blocks of intra subnets | +| [intra\_subnets\_ipv6\_cidr\_blocks](#output\_intra\_subnets\_ipv6\_cidr\_blocks) | List of IPv6 cidr\_blocks of intra subnets in an IPv6 enabled VPC | +| [nat\_ids](#output\_nat\_ids) | List of allocation ID of Elastic IPs created for AWS NAT Gateway | +| [nat\_public\_ips](#output\_nat\_public\_ips) | List of public Elastic IPs created for AWS NAT Gateway | +| [natgw\_ids](#output\_natgw\_ids) | List of NAT Gateway IDs | +| [outpost\_network\_acl\_arn](#output\_outpost\_network\_acl\_arn) | ARN of the outpost network ACL | +| [outpost\_network\_acl\_id](#output\_outpost\_network\_acl\_id) | ID of the outpost network ACL | +| [outpost\_subnet\_arns](#output\_outpost\_subnet\_arns) | List of ARNs of outpost subnets | +| [outpost\_subnets](#output\_outpost\_subnets) | List of IDs of outpost subnets | +| [outpost\_subnets\_cidr\_blocks](#output\_outpost\_subnets\_cidr\_blocks) | List of cidr\_blocks of outpost subnets | +| [outpost\_subnets\_ipv6\_cidr\_blocks](#output\_outpost\_subnets\_ipv6\_cidr\_blocks) | List of IPv6 cidr\_blocks of outpost subnets in an IPv6 enabled VPC | +| [private\_ipv6\_egress\_route\_ids](#output\_private\_ipv6\_egress\_route\_ids) | List of IDs of the ipv6 egress route | +| [private\_nat\_gateway\_route\_ids](#output\_private\_nat\_gateway\_route\_ids) | List of IDs of the private nat gateway route | +| [private\_network\_acl\_arn](#output\_private\_network\_acl\_arn) | ARN of the private network ACL | +| [private\_network\_acl\_id](#output\_private\_network\_acl\_id) | ID of the private network ACL | +| [private\_route\_table\_association\_ids](#output\_private\_route\_table\_association\_ids) | List of IDs of the private route table association | +| [private\_route\_table\_ids](#output\_private\_route\_table\_ids) | List of IDs of private route tables | +| [private\_subnet\_arns](#output\_private\_subnet\_arns) | List of ARNs of private subnets | +| [private\_subnets](#output\_private\_subnets) | List of IDs of private subnets | +| [private\_subnets\_cidr\_blocks](#output\_private\_subnets\_cidr\_blocks) | List of cidr\_blocks of private subnets | +| [private\_subnets\_ipv6\_cidr\_blocks](#output\_private\_subnets\_ipv6\_cidr\_blocks) | List of IPv6 cidr\_blocks of private subnets in an IPv6 enabled VPC | +| [public\_internet\_gateway\_ipv6\_route\_id](#output\_public\_internet\_gateway\_ipv6\_route\_id) | ID of the IPv6 internet gateway route | +| [public\_internet\_gateway\_route\_id](#output\_public\_internet\_gateway\_route\_id) | ID of the internet gateway route | +| [public\_network\_acl\_arn](#output\_public\_network\_acl\_arn) | ARN of the public network ACL | +| [public\_network\_acl\_id](#output\_public\_network\_acl\_id) | ID of the public network ACL | +| [public\_route\_table\_association\_ids](#output\_public\_route\_table\_association\_ids) | List of IDs of the public route table association | +| [public\_route\_table\_ids](#output\_public\_route\_table\_ids) | List of IDs of public route tables | +| [public\_subnet\_arns](#output\_public\_subnet\_arns) | List of ARNs of public subnets | +| [public\_subnets](#output\_public\_subnets) | List of IDs of public subnets | +| [public\_subnets\_cidr\_blocks](#output\_public\_subnets\_cidr\_blocks) | List of cidr\_blocks of public subnets | +| [public\_subnets\_ipv6\_cidr\_blocks](#output\_public\_subnets\_ipv6\_cidr\_blocks) | List of IPv6 cidr\_blocks of public subnets in an IPv6 enabled VPC | +| [redshift\_network\_acl\_arn](#output\_redshift\_network\_acl\_arn) | ARN of the redshift network ACL | +| [redshift\_network\_acl\_id](#output\_redshift\_network\_acl\_id) | ID of the redshift network ACL | +| [redshift\_public\_route\_table\_association\_ids](#output\_redshift\_public\_route\_table\_association\_ids) | List of IDs of the public redshift route table association | +| [redshift\_route\_table\_association\_ids](#output\_redshift\_route\_table\_association\_ids) | List of IDs of the redshift route table association | +| [redshift\_route\_table\_ids](#output\_redshift\_route\_table\_ids) | List of IDs of redshift route tables | +| [redshift\_subnet\_arns](#output\_redshift\_subnet\_arns) | List of ARNs of redshift subnets | +| [redshift\_subnet\_group](#output\_redshift\_subnet\_group) | ID of redshift subnet group | +| [redshift\_subnets](#output\_redshift\_subnets) | List of IDs of redshift subnets | +| [redshift\_subnets\_cidr\_blocks](#output\_redshift\_subnets\_cidr\_blocks) | List of cidr\_blocks of redshift subnets | +| [redshift\_subnets\_ipv6\_cidr\_blocks](#output\_redshift\_subnets\_ipv6\_cidr\_blocks) | List of IPv6 cidr\_blocks of redshift subnets in an IPv6 enabled VPC | +| [this\_customer\_gateway](#output\_this\_customer\_gateway) | Map of Customer Gateway attributes | +| [vgw\_arn](#output\_vgw\_arn) | The ARN of the VPN Gateway | +| [vgw\_id](#output\_vgw\_id) | The ID of the VPN Gateway | +| [vpc\_arn](#output\_vpc\_arn) | The ARN of the VPC | +| [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | +| [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | +| [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | +| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | +| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | +| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | +| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | +| [vpc\_id](#output\_vpc\_id) | The ID of the VPC | +| [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | +| [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | +| [vpc\_ipv6\_cidr\_block](#output\_vpc\_ipv6\_cidr\_block) | The IPv6 CIDR block | +| [vpc\_main\_route\_table\_id](#output\_vpc\_main\_route\_table\_id) | The ID of the main route table associated with this VPC | +| [vpc\_owner\_id](#output\_vpc\_owner\_id) | The ID of the AWS account that owns the VPC | +| [vpc\_secondary\_cidr\_blocks](#output\_vpc\_secondary\_cidr\_blocks) | List of secondary CIDR blocks of the VPC | + diff --git a/examples/simple-regions/main.tf b/examples/simple-regions/main.tf new file mode 100644 index 000000000..492920675 --- /dev/null +++ b/examples/simple-regions/main.tf @@ -0,0 +1,54 @@ +provider "aws" {} + +locals { + name = "ex-${basename(path.cwd)}" + + regions = toset([ + "us-east-1", + "eu-west-1", + "eu-central-1", + ]) + + vpc_cidrs = { + "us-east-1" = "10.0.0.0/16" + "eu-west-1" = "10.1.0.0/16" + "eu-central-1" = "10.2.0.0/16" + } + azs = { for k, v in local.vpc_cidrs : + k => slice(data.aws_availability_zones.available[k].names, 0, 3) + } + + tags = { + Example = local.name + GithubRepo = "terraform-aws-vpc" + GithubOrg = "terraform-aws-modules" + } +} + +data "aws_availability_zones" "available" { + for_each = local.regions + region = each.value + + state = "available" +} + +################################################################################ +# VPC Module +################################################################################ + +module "vpc" { + source = "../../" + + for_each = local.regions + region = each.value + + name = local.name + cidr = local.vpc_cidrs[each.value] + + azs = local.azs[each.value] + private_subnets = [for k, v in local.azs[each.value] : + cidrsubnet(local.vpc_cidrs[each.value], 4, k) + ] + + tags = local.tags +} diff --git a/examples/simple-regions/outputs.tf b/examples/simple-regions/outputs.tf new file mode 100644 index 000000000..7579a26b9 --- /dev/null +++ b/examples/simple-regions/outputs.tf @@ -0,0 +1,749 @@ +output "vpc_id" { + description = "The ID of the VPC" + value = { for region, v in module.vpc : + region => v.vpc_id + } +} + +output "vpc_arn" { + description = "The ARN of the VPC" + value = { for region, v in module.vpc : + region => v.vpc_arn + } +} + +output "vpc_cidr_block" { + description = "The CIDR block of the VPC" + value = { for region, v in module.vpc : + region => v.vpc_cidr_block + } +} + +output "default_security_group_id" { + description = "The ID of the security group created by default on VPC creation" + value = { for region, v in module.vpc : + region => v.default_security_group_id + } +} + +output "default_network_acl_id" { + description = "The ID of the default network ACL" + value = { for region, v in module.vpc : + region => v.default_network_acl_id + } +} + +output "default_route_table_id" { + description = "The ID of the default route table" + value = { for region, v in module.vpc : + region => v.default_route_table_id + } +} + +output "vpc_instance_tenancy" { + description = "Tenancy of instances spin up within VPC" + value = { for region, v in module.vpc : + region => v.vpc_instance_tenancy + } +} + +output "vpc_enable_dns_support" { + description = "Whether or not the VPC has DNS support" + value = { for region, v in module.vpc : + region => v.vpc_enable_dns_support + } +} + +output "vpc_enable_dns_hostnames" { + description = "Whether or not the VPC has DNS hostname support" + value = { for region, v in module.vpc : + region => v.vpc_enable_dns_hostnames + } +} + +output "vpc_main_route_table_id" { + description = "The ID of the main route table associated with this VPC" + value = { for region, v in module.vpc : + region => v.vpc_main_route_table_id + } +} + +output "vpc_ipv6_association_id" { + description = "The association ID for the IPv6 CIDR block" + value = { for region, v in module.vpc : + region => v.vpc_ipv6_association_id + } +} + +output "vpc_ipv6_cidr_block" { + description = "The IPv6 CIDR block" + value = { for region, v in module.vpc : + region => v.vpc_ipv6_cidr_block + } +} + +output "vpc_secondary_cidr_blocks" { + description = "List of secondary CIDR blocks of the VPC" + value = { for region, v in module.vpc : + region => v.vpc_secondary_cidr_blocks + } +} + +output "vpc_owner_id" { + description = "The ID of the AWS account that owns the VPC" + value = { for region, v in module.vpc : + region => v.vpc_owner_id + } +} + +output "private_subnets" { + description = "List of IDs of private subnets" + value = { for region, v in module.vpc : + region => v.private_subnets + } +} + +output "private_subnet_arns" { + description = "List of ARNs of private subnets" + value = { for region, v in module.vpc : + region => v.private_subnet_arns + } +} + +output "private_subnets_cidr_blocks" { + description = "List of cidr_blocks of private subnets" + value = { for region, v in module.vpc : + region => v.private_subnets_cidr_blocks + } +} + +output "private_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of private subnets in an IPv6 enabled VPC" + value = { for region, v in module.vpc : + region => v.private_subnets_ipv6_cidr_blocks + } +} + +output "public_subnets" { + description = "List of IDs of public subnets" + value = { for region, v in module.vpc : + region => v.public_subnets + } +} + +output "public_subnet_arns" { + description = "List of ARNs of public subnets" + value = { for region, v in module.vpc : + region => v.public_subnet_arns + } +} + +output "public_subnets_cidr_blocks" { + description = "List of cidr_blocks of public subnets" + value = { for region, v in module.vpc : + region => v.public_subnets_cidr_blocks + } +} + +output "public_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of public subnets in an IPv6 enabled VPC" + value = { for region, v in module.vpc : + region => v.public_subnets_ipv6_cidr_blocks + } +} + +output "outpost_subnets" { + description = "List of IDs of outpost subnets" + value = { for region, v in module.vpc : + region => v.outpost_subnets + } +} + +output "outpost_subnet_arns" { + description = "List of ARNs of outpost subnets" + value = { for region, v in module.vpc : + region => v.outpost_subnet_arns + } +} + +output "outpost_subnets_cidr_blocks" { + description = "List of cidr_blocks of outpost subnets" + value = { for region, v in module.vpc : + region => v.outpost_subnets_cidr_blocks + } +} + +output "outpost_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of outpost subnets in an IPv6 enabled VPC" + value = { for region, v in module.vpc : + region => v.outpost_subnets_ipv6_cidr_blocks + } +} + +output "database_subnets" { + description = "List of IDs of database subnets" + value = { for region, v in module.vpc : + region => v.database_subnets + } +} + +output "database_subnet_arns" { + description = "List of ARNs of database subnets" + value = { for region, v in module.vpc : + region => v.database_subnet_arns + } +} + +output "database_subnets_cidr_blocks" { + description = "List of cidr_blocks of database subnets" + value = { for region, v in module.vpc : + region => v.database_subnets_cidr_blocks + } +} + +output "database_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of database subnets in an IPv6 enabled VPC" + value = { for region, v in module.vpc : + region => v.database_subnets_ipv6_cidr_blocks + } +} + +output "database_subnet_group" { + description = "ID of database subnet group" + value = { for region, v in module.vpc : + region => v.database_subnet_group + } +} + +output "database_subnet_group_name" { + description = "Name of database subnet group" + value = { for region, v in module.vpc : + region => v.database_subnet_group_name + } +} + +output "redshift_subnets" { + description = "List of IDs of redshift subnets" + value = { for region, v in module.vpc : + region => v.redshift_subnets + } +} + +output "redshift_subnet_arns" { + description = "List of ARNs of redshift subnets" + value = { for region, v in module.vpc : + region => v.redshift_subnet_arns + } +} + +output "redshift_subnets_cidr_blocks" { + description = "List of cidr_blocks of redshift subnets" + value = { for region, v in module.vpc : + region => v.redshift_subnets_cidr_blocks + } +} + +output "redshift_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of redshift subnets in an IPv6 enabled VPC" + value = { for region, v in module.vpc : + region => v.redshift_subnets_ipv6_cidr_blocks + } +} + +output "redshift_subnet_group" { + description = "ID of redshift subnet group" + value = { for region, v in module.vpc : + region => v.redshift_subnet_group + } +} + +output "elasticache_subnets" { + description = "List of IDs of elasticache subnets" + value = { for region, v in module.vpc : + region => v.elasticache_subnets + } +} + +output "elasticache_subnet_arns" { + description = "List of ARNs of elasticache subnets" + value = { for region, v in module.vpc : + region => v.elasticache_subnet_arns + } +} + +output "elasticache_subnets_cidr_blocks" { + description = "List of cidr_blocks of elasticache subnets" + value = { for region, v in module.vpc : + region => v.elasticache_subnets_cidr_blocks + } +} + +output "elasticache_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of elasticache subnets in an IPv6 enabled VPC" + value = { for region, v in module.vpc : + region => v.elasticache_subnets_ipv6_cidr_blocks + } +} + +output "intra_subnets" { + description = "List of IDs of intra subnets" + value = { for region, v in module.vpc : + region => v.intra_subnets + } +} + +output "intra_subnet_arns" { + description = "List of ARNs of intra subnets" + value = { for region, v in module.vpc : + region => v.intra_subnet_arns + } +} + +output "intra_subnets_cidr_blocks" { + description = "List of cidr_blocks of intra subnets" + value = { for region, v in module.vpc : + region => v.intra_subnets_cidr_blocks + } +} + +output "intra_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of intra subnets in an IPv6 enabled VPC" + value = { for region, v in module.vpc : + region => v.intra_subnets_ipv6_cidr_blocks + } +} + +output "elasticache_subnet_group" { + description = "ID of elasticache subnet group" + value = { for region, v in module.vpc : + region => v.elasticache_subnet_group + } +} + +output "elasticache_subnet_group_name" { + description = "Name of elasticache subnet group" + value = { for region, v in module.vpc : + region => v.elasticache_subnet_group_name + } +} + +output "public_route_table_ids" { + description = "List of IDs of public route tables" + value = { for region, v in module.vpc : + region => v.public_route_table_ids + } +} + +output "private_route_table_ids" { + description = "List of IDs of private route tables" + value = { for region, v in module.vpc : + region => v.private_route_table_ids + } +} + +output "database_route_table_ids" { + description = "List of IDs of database route tables" + value = { for region, v in module.vpc : + region => v.database_route_table_ids + } +} + +output "redshift_route_table_ids" { + description = "List of IDs of redshift route tables" + value = { for region, v in module.vpc : + region => v.redshift_route_table_ids + } +} + +output "elasticache_route_table_ids" { + description = "List of IDs of elasticache route tables" + value = { for region, v in module.vpc : + region => v.elasticache_route_table_ids + } +} + +output "intra_route_table_ids" { + description = "List of IDs of intra route tables" + value = { for region, v in module.vpc : + region => v.intra_route_table_ids + } +} + +output "public_internet_gateway_route_id" { + description = "ID of the internet gateway route" + value = { for region, v in module.vpc : + region => v.public_internet_gateway_route_id + } +} + +output "public_internet_gateway_ipv6_route_id" { + description = "ID of the IPv6 internet gateway route" + value = { for region, v in module.vpc : + region => v.public_internet_gateway_ipv6_route_id + } +} + +output "database_internet_gateway_route_id" { + description = "ID of the database internet gateway route" + value = { for region, v in module.vpc : + region => v.database_internet_gateway_route_id + } +} + +output "database_nat_gateway_route_ids" { + description = "List of IDs of the database nat gateway route" + value = { for region, v in module.vpc : + region => v.database_nat_gateway_route_ids + } +} + +output "database_ipv6_egress_route_id" { + description = "ID of the database IPv6 egress route" + value = { for region, v in module.vpc : + region => v.database_ipv6_egress_route_id + } +} + +output "private_nat_gateway_route_ids" { + description = "List of IDs of the private nat gateway route" + value = { for region, v in module.vpc : + region => v.private_nat_gateway_route_ids + } +} + +output "private_ipv6_egress_route_ids" { + description = "List of IDs of the ipv6 egress route" + value = { for region, v in module.vpc : + region => v.private_ipv6_egress_route_ids + } +} + +output "private_route_table_association_ids" { + description = "List of IDs of the private route table association" + value = { for region, v in module.vpc : + region => v.private_route_table_association_ids + } +} + +output "database_route_table_association_ids" { + description = "List of IDs of the database route table association" + value = { for region, v in module.vpc : + region => v.database_route_table_association_ids + } +} + +output "redshift_route_table_association_ids" { + description = "List of IDs of the redshift route table association" + value = { for region, v in module.vpc : + region => v.redshift_route_table_association_ids + } +} + +output "redshift_public_route_table_association_ids" { + description = "List of IDs of the public redshift route table association" + value = { for region, v in module.vpc : + region => v.redshift_public_route_table_association_ids + } +} + +output "elasticache_route_table_association_ids" { + description = "List of IDs of the elasticache route table association" + value = { for region, v in module.vpc : + region => v.elasticache_route_table_association_ids + } +} + +output "intra_route_table_association_ids" { + description = "List of IDs of the intra route table association" + value = { for region, v in module.vpc : + region => v.intra_route_table_association_ids + } +} + +output "public_route_table_association_ids" { + description = "List of IDs of the public route table association" + value = { for region, v in module.vpc : + region => v.public_route_table_association_ids + } +} + +output "dhcp_options_id" { + description = "The ID of the DHCP options" + value = { for region, v in module.vpc : + region => v.dhcp_options_id + } +} + +output "nat_ids" { + description = "List of allocation ID of Elastic IPs created for AWS NAT Gateway" + value = { for region, v in module.vpc : + region => v.nat_ids + } +} + +output "nat_public_ips" { + description = "List of public Elastic IPs created for AWS NAT Gateway" + value = { for region, v in module.vpc : + region => v.nat_public_ips + } +} + +output "natgw_ids" { + description = "List of NAT Gateway IDs" + value = { for region, v in module.vpc : + region => v.natgw_ids + } +} + +output "igw_id" { + description = "The ID of the Internet Gateway" + value = { for region, v in module.vpc : + region => v.igw_id + } +} + +output "igw_arn" { + description = "The ARN of the Internet Gateway" + value = { for region, v in module.vpc : + region => v.igw_arn + } +} + +output "egress_only_internet_gateway_id" { + description = "The ID of the egress only Internet Gateway" + value = { for region, v in module.vpc : + region => v.egress_only_internet_gateway_id + } +} + +output "cgw_ids" { + description = "List of IDs of Customer Gateway" + value = { for region, v in module.vpc : + region => v.cgw_ids + } +} + +output "cgw_arns" { + description = "List of ARNs of Customer Gateway" + value = { for region, v in module.vpc : + region => v.cgw_arns + } +} + +output "this_customer_gateway" { + description = "Map of Customer Gateway attributes" + value = { for region, v in module.vpc : + region => v.this_customer_gateway + } +} + +output "vgw_id" { + description = "The ID of the VPN Gateway" + value = { for region, v in module.vpc : + region => v.vgw_id + } +} + +output "vgw_arn" { + description = "The ARN of the VPN Gateway" + value = { for region, v in module.vpc : + region => v.vgw_arn + } +} + +output "default_vpc_id" { + description = "The ID of the Default VPC" + value = { for region, v in module.vpc : + region => v.default_vpc_id + } +} + +output "default_vpc_arn" { + description = "The ARN of the Default VPC" + value = { for region, v in module.vpc : + region => v.default_vpc_arn + } +} + +output "default_vpc_cidr_block" { + description = "The CIDR block of the Default VPC" + value = { for region, v in module.vpc : + region => v.default_vpc_cidr_block + } +} + +output "default_vpc_default_security_group_id" { + description = "The ID of the security group created by default on Default VPC creation" + value = { for region, v in module.vpc : + region => v.default_vpc_default_security_group_id + } +} + +output "default_vpc_default_network_acl_id" { + description = "The ID of the default network ACL of the Default VPC" + value = { for region, v in module.vpc : + region => v.default_vpc_default_network_acl_id + } +} + +output "default_vpc_default_route_table_id" { + description = "The ID of the default route table of the Default VPC" + value = { for region, v in module.vpc : + region => v.default_vpc_default_route_table_id + } +} + +output "default_vpc_instance_tenancy" { + description = "Tenancy of instances spin up within Default VPC" + value = { for region, v in module.vpc : + region => v.default_vpc_instance_tenancy + } +} + +output "default_vpc_enable_dns_support" { + description = "Whether or not the Default VPC has DNS support" + value = { for region, v in module.vpc : + region => v.default_vpc_enable_dns_support + } +} + +output "default_vpc_enable_dns_hostnames" { + description = "Whether or not the Default VPC has DNS hostname support" + value = { for region, v in module.vpc : + region => v.default_vpc_enable_dns_hostnames + } +} + +output "default_vpc_main_route_table_id" { + description = "The ID of the main route table associated with the Default VPC" + value = { for region, v in module.vpc : + region => v.default_vpc_main_route_table_id + } +} + +output "public_network_acl_id" { + description = "ID of the public network ACL" + value = { for region, v in module.vpc : + region => v.public_network_acl_id + } +} + +output "public_network_acl_arn" { + description = "ARN of the public network ACL" + value = { for region, v in module.vpc : + region => v.public_network_acl_arn + } +} + +output "private_network_acl_id" { + description = "ID of the private network ACL" + value = { for region, v in module.vpc : + region => v.private_network_acl_id + } +} + +output "private_network_acl_arn" { + description = "ARN of the private network ACL" + value = { for region, v in module.vpc : + region => v.private_network_acl_arn + } +} + +output "outpost_network_acl_id" { + description = "ID of the outpost network ACL" + value = { for region, v in module.vpc : + region => v.outpost_network_acl_id + } +} + +output "outpost_network_acl_arn" { + description = "ARN of the outpost network ACL" + value = { for region, v in module.vpc : + region => v.outpost_network_acl_arn + } +} + +output "intra_network_acl_id" { + description = "ID of the intra network ACL" + value = { for region, v in module.vpc : + region => v.intra_network_acl_id + } +} + +output "intra_network_acl_arn" { + description = "ARN of the intra network ACL" + value = { for region, v in module.vpc : + region => v.intra_network_acl_arn + } +} + +output "database_network_acl_id" { + description = "ID of the database network ACL" + value = { for region, v in module.vpc : + region => v.database_network_acl_id + } +} + +output "database_network_acl_arn" { + description = "ARN of the database network ACL" + value = { for region, v in module.vpc : + region => v.database_network_acl_arn + } +} + +output "redshift_network_acl_id" { + description = "ID of the redshift network ACL" + value = { for region, v in module.vpc : + region => v.redshift_network_acl_id + } +} + +output "redshift_network_acl_arn" { + description = "ARN of the redshift network ACL" + value = { for region, v in module.vpc : + region => v.redshift_network_acl_arn + } +} + +output "elasticache_network_acl_id" { + description = "ID of the elasticache network ACL" + value = { for region, v in module.vpc : + region => v.elasticache_network_acl_id + } +} + +output "elasticache_network_acl_arn" { + description = "ARN of the elasticache network ACL" + value = { for region, v in module.vpc : + region => v.elasticache_network_acl_arn + } +} + +# VPC flow log +output "vpc_flow_log_id" { + description = "The ID of the Flow Log resource" + value = { for region, v in module.vpc : + region => v.vpc_flow_log_id + } +} + +output "vpc_flow_log_destination_arn" { + description = "The ARN of the destination for VPC Flow Logs" + value = { for region, v in module.vpc : + region => v.vpc_flow_log_destination_arn + } +} + +output "vpc_flow_log_destination_type" { + description = "The type of the destination for VPC Flow Logs" + value = { for region, v in module.vpc : + region => v.vpc_flow_log_destination_type + } +} + +output "vpc_flow_log_cloudwatch_iam_role_arn" { + description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" + value = { for region, v in module.vpc : + region => v.vpc_flow_log_cloudwatch_iam_role_arn + } +} diff --git a/examples/simple-regions/variables.tf b/examples/simple-regions/variables.tf new file mode 100644 index 000000000..e69de29bb diff --git a/examples/simple-regions/versions.tf b/examples/simple-regions/versions.tf new file mode 100644 index 000000000..aaf26b899 --- /dev/null +++ b/examples/simple-regions/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 6.0" + } + } +} From 103fa59dd463bec2fdca694a21ba8b1b7031cae9 Mon Sep 17 00:00:00 2001 From: Roman Eremeev Date: Wed, 20 Aug 2025 14:13:10 +0200 Subject: [PATCH 7/7] Explain region limitations in `vpc-endpoints` sub-module --- modules/vpc-endpoints/README.md | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/modules/vpc-endpoints/README.md b/modules/vpc-endpoints/README.md index 6e4f8894c..6a9f0d031 100644 --- a/modules/vpc-endpoints/README.md +++ b/modules/vpc-endpoints/README.md @@ -57,6 +57,79 @@ module "endpoints" { } ``` +### Region Support Limitation + +When using this sub-module with the [region parameter](https://registry.terraform.io/providers/hashicorp/aws/6.0.0/docs/guides/enhanced-region-support), it will still try to look up the service endpoint in the default region that's set in aws provider configuration. When you have this config: + +* aws provider region: us-east-1 +* module region: eu-central-1 + +It leads to an API error as shown: + +```plaintext +│ Error: creating EC2 VPC Endpoint (com.amazonaws.us-east-1.s3): operation error EC2: CreateVpcEndpoint, https response error StatusCode: 400, RequestID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, api error InvalidServiceName: The Vpc Endpoint Service 'com.amazonaws.us-east-1.s3' does not exist +│ +│ with module.vpc-endpoints-regions["eu-central-1"].aws_vpc_endpoint.this["s3"], +│ on .terraform/modules/vpc-endpoints-regions/modules/vpc-endpoints/main.tf line 24, in resource "aws_vpc_endpoint" "this": +│ 24: resource "aws_vpc_endpoint" "this" { +``` + +This happens because the [aws_vpc_endpoint_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc_endpoint_service) data source used in this sub-module does not support the [region parameter](https://registry.terraform.io/providers/hashicorp/aws/6.0.0/docs/guides/enhanced-region-support#non%E2%80%93region-aware-resources) yet. + +As a workaround, we have added the option `enable_service_endpoint_lookup = false` to disable the data source, but you will have to provide fully-qualified service endpoint instead of just the short service name, as shown in the example below. + +Before: + +```hcl +module "endpoints" { + source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" + + for_each = toset([ + "us-east-1", + "eu-west-1", + "eu-central-1", + ]) + region = each.value + + vpc_id = var.regional_vpc_ids[each.value] + security_group_ids = [var.regional_sg_ids[each.value]] + + endpoints = { + s3 = { + service = "s3" + # … + } + } +} +``` + +After: + +```hcl +module "endpoints" { + source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" + + for_each = toset([ + "us-east-1", + "eu-west-1", + "eu-central-1", + ]) + region = each.value + + vpc_id = var.regional_vpc_ids[each.value] + security_group_ids = [var.regional_sg_ids[each.value]] + + enable_service_endpoint_lookup = false # <-- THIS + endpoints = { + s3 = { + service_endpoint = "com.amazonaws.${each.value}.s3" # <-- THIS + service_region = each.value # <-- THIS + # … + } + } +} +``` + ## Examples - [Complete-VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/complete) with VPC Endpoints.