├── .gitignore ├── LICENSE ├── README.md ├── networking ├── dynamic_vpc │ ├── Readme.md │ ├── main.tf │ ├── variables.tf │ └── versions.tf ├── full_mesh_intra_vpc_security_group_rules │ ├── README.md │ ├── base.tf │ ├── main.tf │ ├── outputs.tf │ ├── preconditions.tf │ ├── variables.tf │ └── versions.tf ├── full_mesh_trio │ ├── README.md │ ├── base.tf │ ├── main.tf │ ├── one_associations.tf │ ├── one_base.tf │ ├── one_peering.tf │ ├── one_preconditions.tf │ ├── one_tgw_routes.tf │ ├── one_vpc_routes.tf │ ├── outputs.tf │ ├── three_associations.tf │ ├── three_base.tf │ ├── three_peering.tf │ ├── three_preconditions.tf │ ├── three_tgw_routes.tf │ ├── three_vpc_routes.tf │ ├── two_associations.tf │ ├── two_base.tf │ ├── two_peering.tf │ ├── two_preconditions.tf │ ├── two_tgw_routes.tf │ ├── two_vpc_routes.tf │ ├── variables.tf │ └── versions.tf ├── intra_vpc_security_group_rule_for_tiered_vpc_ng │ ├── README.md │ ├── base.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── ipv6_full_mesh_intra_vpc_security_group_rules │ ├── README.md │ ├── base.tf │ ├── main.tf │ ├── outputs.tf │ ├── preconditions.tf │ ├── variables.tf │ └── versions.tf ├── ipv6_intra_vpc_security_group_rule_for_tiered_vpc_ng │ ├── README.md │ ├── base.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── mega_mesh │ ├── README.md │ ├── base.tf │ ├── eight_associations.tf │ ├── eight_base.tf │ ├── eight_peering.tf │ ├── eight_preconditions.tf │ ├── eight_tgw_routes.tf │ ├── eight_vpc_routes.tf │ ├── five_associations.tf │ ├── five_base.tf │ ├── five_peering.tf │ ├── five_preconditions.tf │ ├── five_tgw_routes.tf │ ├── five_vpc_routes.tf │ ├── four_associations.tf │ ├── four_base.tf │ ├── four_peering.tf │ ├── four_preconditions.tf │ ├── four_tgw_routes.tf │ ├── four_vpc_routes.tf │ ├── main.tf │ ├── nine_associations.tf │ ├── nine_base.tf │ ├── nine_peering.tf │ ├── nine_preconditions.tf │ ├── nine_tgw_routes.tf │ ├── nine_vpc_routes.tf │ ├── one_associations.tf │ ├── one_base.tf │ ├── one_peering.tf │ ├── one_preconditions.tf │ ├── one_tgw_routes.tf │ ├── one_vpc_routes.tf │ ├── outputs.tf │ ├── seven_associations.tf │ ├── seven_base.tf │ ├── seven_peering.tf │ ├── seven_preconditions.tf │ ├── seven_tgw_routes.tf │ ├── seven_vpc_routes.tf │ ├── six_associations.tf │ ├── six_base.tf │ ├── six_peering.tf │ ├── six_preconditions.tf │ ├── six_tgw_routes.tf │ ├── six_vpc_routes.tf │ ├── ten_associations.tf │ ├── ten_base.tf │ ├── ten_peering.tf │ ├── ten_preconditions.tf │ ├── ten_tgw_routes.tf │ ├── ten_vpc_routes.tf │ ├── three_associations.tf │ ├── three_base.tf │ ├── three_peering.tf │ ├── three_preconditions.tf │ ├── three_tgw_routes.tf │ ├── three_vpc_routes.tf │ ├── two_associations.tf │ ├── two_base.tf │ ├── two_peering.tf │ ├── two_preconditions.tf │ ├── two_tgw_routes.tf │ ├── two_vpc_routes.tf │ ├── variables.tf │ └── versions.tf ├── super_intra_vpc_security_group_rules │ ├── README.md │ ├── base.tf │ ├── main.tf │ ├── outputs.tf │ ├── preconditions.tf │ ├── variables.tf │ └── versions.tf ├── tgw_super_router_for_tgw_centralized_router │ ├── README.md │ ├── base.tf │ ├── blackhole_routes.tf │ ├── main.tf │ ├── outputs.tf │ ├── peering.tf │ ├── preconditions.tf │ ├── routing.tf │ ├── variables.tf │ └── versions.tf ├── tiered_vpc │ ├── Readme.md │ ├── main.tf │ ├── outputs.tf │ ├── private.tf │ ├── public.tf │ ├── variables.tf │ └── versions.tf ├── tiered_vpc_ng │ ├── README.md │ ├── base.tf │ ├── isolated.tf │ ├── main.tf │ ├── outputs.tf │ ├── private.tf │ ├── public.tf │ ├── security_groups.tf │ ├── variables.tf │ └── versions.tf ├── transit_gateway_centralized_router_for_tiered_vpc_ng │ ├── README.md │ ├── base.tf │ ├── centralized_egress_routes.tf │ ├── main.tf │ ├── modules │ │ └── generate_routes_to_other_vpcs │ │ │ ├── .terraform-version │ │ │ ├── Readme.md │ │ │ ├── base.tf │ │ │ ├── main.tf │ │ │ ├── outputs.tf │ │ │ ├── tests │ │ │ ├── final │ │ │ │ └── main.tf │ │ │ ├── generate_routes.tftest.hcl │ │ │ └── setup │ │ │ │ └── main.tf │ │ │ ├── variables.tf │ │ │ └── versions.tf │ ├── outputs.tf │ ├── tgw_routes.tf │ ├── variables.tf │ ├── versions.tf │ ├── vpc_attachments.tf │ └── vpc_routes.tf └── vpc_peering_deluxe │ ├── README.md │ ├── base.tf │ ├── main.tf │ ├── outputs.tf │ ├── peering.tf │ ├── preconditions.tf │ ├── routing.tf │ ├── variables.tf │ └── versions.tf ├── opinions └── opinion_23 │ ├── README.md │ ├── list_of_objects │ ├── .terraform-version │ ├── main.tf │ └── versions.tf │ └── map_of_maps │ ├── .terraform-version │ ├── main.tf │ └── versions.tf └── utils ├── generate_routes_to_other_vpcs ├── .terraform-version ├── Readme.md ├── base.tf ├── main.tf ├── outputs.tf ├── tests │ └── defaults │ │ └── test_defaults.tf ├── variables.tf └── versions.tf └── tiered_subnet_calculator ├── .terraform-version ├── Readme.md ├── main.tf ├── tiers.auto.tfvars ├── variables.tf └── versions.tf /.gitignore: -------------------------------------------------------------------------------- 1 | .terraform 2 | *.tfstate* 3 | */files/secrets 4 | */personal.tfvars 5 | *.DS_Store 6 | */secrets/* 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jude Quintana 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform-modules 2 | A collection of ideas. 3 | 4 | Experimentation is the path to discovery. 5 | 6 | Create. Iterate. Combine. 7 | 8 | ~jq1 #StayUp 9 | -------------------------------------------------------------------------------- /networking/dynamic_vpc/Readme.md: -------------------------------------------------------------------------------- 1 | # This module is deprecated 2 | Please use [Tiered VPC-NG](https://github.com/JudeQuintana/terraform-modules/tree/master/networking/tiered_vpc_ng) instead! 3 | 4 | # Overview 5 | 6 | This is a Dynamic VPC Module that builds a redundant network 7 | architecture in AWS based on structured input using `for_each` and `for` 8 | constructs. It will build a VPC with private and public subnets per AZ with the 9 | proper routing and labeling. 10 | 11 | For a more details on the design go to the [Dynamic VPC Module Blog Post](https://jq1.io/posts/dynamic_vpc/) 12 | 13 | Here is the related VPC network diagram for visual reference. 14 | ![example_vpc](https://docs.aws.amazon.com/vpc/latest/userguide/images/nat-gateway-diagram.png) 15 | 16 | # Using the VPC module 17 | 18 | This configuration will create a VPC in the us-east-1 region with a NAT Gatway per AZ with 19 | routing for each private and public subnets. Every taggable resource 20 | will have proper naming including environment, region and AZ. Everything 21 | is in [main.tf](https://github.com/JudeQuintana/terraform-modules/blob/master/networking/dynamic_vpc/main.tf) and 22 | [variables.tf](https://github.com/JudeQuintana/terraform-modules/blob/master/networking/dynamic_vpc/variables.tf) 23 | because I wanted less focus on the directory structure. 24 | 25 | Also, I like being explicit about passing in an aliased `provider` into the module. It makes it 26 | easier to identify which region or account I'm applying module resources into. 27 | ``` 28 | terraform { 29 | required_version = "~> 0.12.6" 30 | required_providers { 31 | aws = "~> 2.70.0" 32 | } 33 | } 34 | 35 | # base provider 36 | provider "aws" { 37 | region = "us-east-1" 38 | } 39 | 40 | provider "aws" { 41 | region = "us-east-1" 42 | alias = "use1" 43 | } 44 | 45 | variable "region_az_short_names" { 46 | description = "Region and AZ names mapped to short naming conventions for labeling" 47 | type = map(string) 48 | 49 | default = { 50 | us-east-1 = "use1" 51 | us-east-1a = "use1a" 52 | us-east-1b = "use1b" 53 | us-east-1c = "use1c" 54 | us-west-2 = "usw2" 55 | us-west-2a = "usw2a" 56 | us-west-2b = "usw2b" 57 | us-west-2c = "usw2c" 58 | } 59 | } 60 | 61 | module "stage_use1_vpc" { 62 | source = "git@github.com:JudeQuintana/terraform-modules.git//networking/dynamic_vpc?ref=v1.0.4" 63 | 64 | providers = { 65 | aws = aws.use1 66 | } 67 | 68 | env_prefix = "stage" 69 | region_az_short_names = var.region_az_short_names 70 | cidr_block = "10.0.0.0/16" 71 | azs = { 72 | a = 1 73 | b = 2 74 | c = 3 75 | } 76 | } 77 | ``` 78 | 79 | Note: The third octet of the private subnets correspond to the values in the 80 | `var.azs` map. The third octect of the public subnets are n + 32. 81 | 82 | | az | resource | subnet cidr | routing 83 | | ----------- | ----------- | ----------- | ----------- | 84 | | a | private subnet| 10.0.1.0/24| traffic routes out nat gateway in AZ a 85 | | a | public subnet| 10.0.33.0/24| traffic routes out igw 86 | | | | | 87 | | b | private subnet| 10.0.2.0/24| traffic routes out nat gateway in AZ b 88 | | b | public subnet| 10.0.34.0/24| traffic routes out igw 89 | | | | | 90 | | c | private subnet| 10.0.3.0/24| traffic routes out nat gateway in AZ c 91 | | c | public subnet| 10.0.35.0/24| traffic routes out igw 92 | 93 | ## Caveats 94 | 95 | This VPC module more of a learning excersize and it does generate resources that cost money (ie NAT Gateways and EIPs). 96 | When it comes to scaling out networks via peer links it's best practice to segment your network tiers with their own subnets per AZ (ie 97 | private app subnet, public load balancer subnet, etc). Network segmentation makes it easier configure security groups across the VPC Peer links 98 | because you can't share security group IDs across VPCs, only subnets! 99 | -------------------------------------------------------------------------------- /networking/dynamic_vpc/variables.tf: -------------------------------------------------------------------------------- 1 | variable "env_prefix" { 2 | description = "prod, stage, etc" 3 | type = string 4 | } 5 | 6 | variable "region_az_short_names" { 7 | description = "Region and AZ names mapped to short naming conventions for labeling" 8 | type = map(string) 9 | } 10 | 11 | variable "cidr_block" { 12 | description = "Base VPC CIDR Block ie 10.0.0.0/16" 13 | type = string 14 | } 15 | 16 | variable "azs" { 17 | description = "AZ (letter) to Subnet (number for 3rd octet)" 18 | type = map(number) 19 | } 20 | 21 | variable "vpc_tenancy" { 22 | description = "Set VPC Tenancy" 23 | type = string 24 | default = "default" 25 | } 26 | 27 | -------------------------------------------------------------------------------- /networking/dynamic_vpc/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.12.6" 3 | } 4 | 5 | -------------------------------------------------------------------------------- /networking/full_mesh_intra_vpc_security_group_rules/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * # Full Mesh Intra VPC Secuity Group Rules Description 3 | * - This allowing inbound protocols across regions based on rules (ie ssh, icmp, etc) that 4 | * were used in each intra_vpc_security_group_rules modules for all vpcs in each region while in a TGW full mesh configuration. 5 | * - Rule sets for one, two and three Intra VPC Security Group Rules should be the same. also enforced by validation 6 | * - See it in action in [security_group_rules.tf](https://github.com/JudeQuintana/terraform-main/blob/main/full_mesh_trio_demo/security_group_rules.tf) in the [Full Mesh Trio Demo](https://github.com/JudeQuintana/terraform-main/tree/main/full_mesh_trio_demo). 7 | * 8 | * `v1.9.0`: 9 | * - ipv4 secondary cidrs 10 | * ``` 11 | * module "full_mesh_intra_vpc_security_groups_rules" { 12 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/full_mesh_intra_vpc_security_group_rules?ref=v1.9.0" 13 | * ... 14 | * ``` 15 | * 16 | * 17 | * `v1.7.5`: 18 | * - ipv4 network cidrs 19 | * ``` 20 | * module "full_mesh_intra_vpc_security_groups_rules" { 21 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/full_mesh_intra_vpc_security_group_rules?ref=v1.7.5" 22 | * 23 | * providers = { 24 | * aws.one = aws.use1 25 | * aws.two = aws.use2 26 | * aws.three = aws.usw2 27 | * } 28 | * 29 | * env_prefix = var.env_prefix 30 | * region_az_labels = var.region_az_labels 31 | * full_mesh_intra_vpc_security_group_rules = { 32 | * one = { 33 | * intra_vpc_security_group_rules = module.intra_vpc_security_group_rules_use1 34 | * } 35 | * two = { 36 | * intra_vpc_security_group_rules = module.intra_vpc_security_group_rules_use2 37 | * } 38 | * three = { 39 | * intra_vpc_security_group_rules = module.intra_vpc_security_group_rules_usw2 40 | * } 41 | * } 42 | * } 43 | * ``` 44 | * 45 | */ 46 | 47 | -------------------------------------------------------------------------------- /networking/full_mesh_intra_vpc_security_group_rules/outputs.tf: -------------------------------------------------------------------------------- 1 | output "one" { 2 | value = { 3 | account_id = local.one_account_id 4 | region = local.one_region_name 5 | rules = [for this in var.full_mesh_intra_vpc_security_group_rules.one.intra_vpc_security_group_rules : this.rule] 6 | } 7 | } 8 | 9 | output "two" { 10 | value = { 11 | account_id = local.two_account_id 12 | region = local.two_region_name 13 | rules = [for this in var.full_mesh_intra_vpc_security_group_rules.two.intra_vpc_security_group_rules : this.rule] 14 | } 15 | } 16 | 17 | output "three" { 18 | value = { 19 | account_id = local.three_account_id 20 | region = local.three_region_name 21 | rules = [for this in var.full_mesh_intra_vpc_security_group_rules.three.intra_vpc_security_group_rules : this.rule] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /networking/full_mesh_intra_vpc_security_group_rules/preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # used on all aws_security_group_rule resources to guarantee the intra vpc security group rules match their relative provider's region. 3 | one_provider_to_one_intra_vpc_security_group_rules_region_check = { 4 | condition = alltrue([ 5 | for this in var.full_mesh_intra_vpc_security_group_rules.one.intra_vpc_security_group_rules : 6 | contains([local.one_region_name], this.region) 7 | ]) 8 | error_message = "The Intra VPC Security Group Rule's regions for One must match the aws.one provider alias region for Full Mesh VPC Security Group Rules." 9 | } 10 | 11 | one_provider_to_one_intra_vpc_security_group_rules_account_id_check = { 12 | condition = alltrue([ 13 | for this in var.full_mesh_intra_vpc_security_group_rules.one.intra_vpc_security_group_rules : 14 | contains([local.one_account_id], this.account_id) 15 | ]) 16 | error_message = "The Intra VPC Security Group Rule's account ID for One must match the aws.one provider alias account ID for Full Mesh Intra VPC Security Group Rules." 17 | } 18 | 19 | two_provider_to_two_intra_vpc_security_group_rules_region_check = { 20 | condition = alltrue([ 21 | for this in var.full_mesh_intra_vpc_security_group_rules.two.intra_vpc_security_group_rules : 22 | contains([local.two_region_name], this.region) 23 | ]) 24 | error_message = "The Intra VPC Security Group Rule's regions for Two must match the aws.two provider alias region for Full Mesh VPC Security Group Rules." 25 | } 26 | 27 | two_provider_to_two_intra_vpc_security_group_rules_account_id_check = { 28 | condition = alltrue([ 29 | for this in var.full_mesh_intra_vpc_security_group_rules.two.intra_vpc_security_group_rules : 30 | contains([local.two_account_id], this.account_id) 31 | ]) 32 | error_message = "The Intra VPC Security Group Rule's account ID for Two must match the aws.two provider alias account ID for Full Mesh Intra VPC Security Group Rules." 33 | } 34 | 35 | three_provider_to_three_intra_vpc_security_group_rules_region_check = { 36 | condition = alltrue([ 37 | for this in var.full_mesh_intra_vpc_security_group_rules.three.intra_vpc_security_group_rules : 38 | contains([local.three_region_name], this.region) 39 | ]) 40 | error_message = "The Intra VPC Security Group Rule's regions for Three must match the aws.three provider alias region for Full Mesh VPC Security Group Rules." 41 | } 42 | 43 | three_provider_to_three_intra_vpc_security_group_rules_account_id_check = { 44 | condition = alltrue([ 45 | for this in var.full_mesh_intra_vpc_security_group_rules.three.intra_vpc_security_group_rules : 46 | contains([local.three_account_id], this.account_id) 47 | ]) 48 | error_message = "The Intra VPC Security Group Rule's account ID for Three must match the aws.three provider alias account ID for Full Mesh Intra VPC Security Group Rules." 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /networking/full_mesh_intra_vpc_security_group_rules/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=4.20" 7 | configuration_aliases = [aws.one, aws.two, aws.three] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/base.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | peering_name_format = "%s <-> %s" 3 | route_format = "%s|%s" 4 | upper_env_prefix = upper(var.env_prefix) 5 | default_tags = merge({ 6 | Environment = var.env_prefix 7 | }, var.tags) 8 | } 9 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * Full Mesh Trio module builds peering links (red) between existing hub spoke tgws (Centralized Routers) and adds proper routes to all TGWs and their attached VPCs, etc. 3 | * 4 | * The resulting architecture is a full mesh configurion between 3 hub spoke topologies. 5 | * See it in action in the [Full Mesh Trio Demo](https://github.com/JudeQuintana/terraform-main/tree/main/full_mesh_trio_demo) 6 | * 7 | * `v1.9.0`: 8 | * - reorganize files 9 | * - ipv4 VPC routes for ipv4 secondary cidrs 10 | * - ipv4 TGW routes for ipv4 secondary cidrs 11 | * - ipv6 VPC routes for ipv6 network cidrs 12 | * - ipv6 TGW routes for ipv6 network cidrs 13 | * - ipv6 VPC routes for ipv6 secondary cidrs 14 | * - ipv6 TGW routes for ipv6 secondary cidrs 15 | * - moar validation 16 | * ``` 17 | * module "full_mesh_trio" { 18 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/full_mesh_trio?ref=v1.9.0" 19 | * ... 20 | * ``` 21 | * 22 | * 23 | * `v1.7.5`: 24 | * - ipv4 VPC routes for ipv4 network cidrs 25 | * ``` 26 | * module "full_mesh_trio" { 27 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/full_mesh_trio?ref=v1.7.5" 28 | * 29 | * providers = { 30 | * aws.one = aws.use1 31 | * aws.two = aws.use2 32 | * aws.three = aws.usw2 33 | * } 34 | * 35 | * env_prefix = var.env_prefix 36 | * full_mesh_trio = { 37 | * one = { 38 | * centralized_router = module.centralized_router_use1 39 | * } 40 | * two = { 41 | * centralized_router = module.centralized_router_use2 42 | * } 43 | * three = { 44 | * centralized_router = module.centralized_router_usw2 45 | * } 46 | * } 47 | * } 48 | * 49 | * output "full_mesh_trio" { 50 | * value = module.full_mesh_trio 51 | * } 52 | * ``` 53 | */ 54 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/one_associations.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_two" { 2 | provider = aws.one 3 | 4 | transit_gateway_route_table_id = local.one_tgw.route_table_id 5 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 6 | } 7 | 8 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_three" { 9 | provider = aws.one 10 | 11 | transit_gateway_route_table_id = local.one_tgw.route_table_id 12 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 13 | } 14 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/one_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_one" { 2 | provider = aws.one 3 | } 4 | 5 | data "aws_region" "this_one" { 6 | provider = aws.one 7 | } 8 | 9 | locals { 10 | one_provider_account_id = data.aws_caller_identity.this_one.account_id 11 | one_provider_region_name = data.aws_region.this_one.name 12 | 13 | one_tgw = var.full_mesh_trio.one.centralized_router 14 | one_tgw_vpc_network_cidrs = toset(concat(local.one_tgw.vpc.network_cidrs, local.one_tgw.vpc.secondary_cidrs)) 15 | one_tgw_vpc_ipv6_network_cidrs = toset(concat(local.one_tgw.vpc.ipv6_network_cidrs, local.one_tgw.vpc.ipv6_secondary_cidrs)) 16 | one_tgw_vpc_route_table_ids = toset(concat(local.one_tgw.vpc.private_route_table_ids, local.one_tgw.vpc.public_route_table_ids)) 17 | } 18 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/one_peering.tf: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # Begin Full Mesh Trio One TGW to Two TGW 3 | ######################################################################################## 4 | 5 | resource "aws_ec2_transit_gateway_peering_attachment" "this_one_to_this_two" { 6 | provider = aws.one 7 | 8 | transit_gateway_id = local.one_tgw.id 9 | peer_account_id = local.two_tgw.account_id 10 | peer_region = local.two_tgw.region 11 | peer_transit_gateway_id = local.two_tgw.id 12 | tags = merge( 13 | local.default_tags, 14 | { 15 | Name = format(local.peering_name_format, local.one_tgw.full_name, local.two_tgw.full_name) 16 | Side = "One Creator" 17 | } 18 | ) 19 | 20 | lifecycle { 21 | # cant use dynamic block for lifecycle blocks 22 | # tgw region and account id preconditions are evaluated only on apply 23 | # see preconditions.tf 24 | precondition { 25 | condition = local.one_tgw_provider_region_check.condition 26 | error_message = local.one_tgw_provider_region_check.error_message 27 | } 28 | 29 | precondition { 30 | condition = local.one_tgw_provider_account_id_check.condition 31 | error_message = local.one_tgw_provider_account_id_check.error_message 32 | } 33 | 34 | precondition { 35 | condition = local.two_tgw_provider_region_check.condition 36 | error_message = local.two_tgw_provider_region_check.error_message 37 | } 38 | 39 | precondition { 40 | condition = local.two_tgw_provider_account_id_check.condition 41 | error_message = local.two_tgw_provider_account_id_check.error_message 42 | } 43 | 44 | precondition { 45 | condition = local.three_tgw_provider_region_check.condition 46 | error_message = local.three_tgw_provider_region_check.error_message 47 | } 48 | 49 | precondition { 50 | condition = local.three_tgw_provider_account_id_check.condition 51 | error_message = local.three_tgw_provider_account_id_check.error_message 52 | } 53 | } 54 | } 55 | 56 | resource "aws_ec2_transit_gateway_peering_attachment_accepter" "this_one_to_this_two" { 57 | provider = aws.two 58 | 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment.this_one_to_this_two.id 60 | tags = merge( 61 | local.default_tags, 62 | { 63 | Name = format(local.peering_name_format, local.two_tgw.full_name, local.one_tgw.full_name) 64 | Side = "Two Accepter" 65 | } 66 | ) 67 | } 68 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/one_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | one_tgw_provider_region_check = { 3 | condition = contains([local.one_provider_region_name], local.one_tgw.region) 4 | error_message = "Centralized Router One's region must match the aws.one provider alias region for Full Mesh Trio." 5 | } 6 | 7 | one_tgw_provider_account_id_check = { 8 | condition = contains([local.one_provider_account_id], local.one_tgw.account_id) 9 | error_message = "Centralized Router One's account ID must match the aws.one provider alias account ID for Full Mesh Trio." 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/one_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_two_tgw" { 2 | provider = aws.one 3 | 4 | for_each = local.two_tgw_vpc_network_cidrs 5 | 6 | transit_gateway_route_table_id = local.one_tgw.route_table_id 7 | destination_cidr_block = each.value 8 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 9 | } 10 | 11 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_three_tgw" { 12 | provider = aws.one 13 | 14 | for_each = local.three_tgw_vpc_network_cidrs 15 | 16 | transit_gateway_route_table_id = local.one_tgw.route_table_id 17 | destination_cidr_block = each.value 18 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 19 | } 20 | 21 | #ipv6 22 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_ipv6_routes_to_vpcs_in_two_tgw" { 23 | provider = aws.one 24 | 25 | for_each = local.two_tgw_vpc_ipv6_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.one_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_ipv6_routes_to_vpcs_in_three_tgw" { 33 | provider = aws.one 34 | 35 | for_each = local.three_tgw_vpc_ipv6_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.one_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 40 | } 41 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/outputs.tf: -------------------------------------------------------------------------------- 1 | output "peering" { 2 | value = { 3 | one = { 4 | attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 5 | from = local.one_tgw.full_name 6 | to = local.two_tgw.full_name 7 | } 8 | two = { 9 | attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 10 | from = local.two_tgw.full_name 11 | to = local.three_tgw.full_name 12 | } 13 | three = { 14 | attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 15 | from = local.three_tgw.full_name 16 | to = local.one_tgw.full_name 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/three_associations.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_one" { 2 | provider = aws.three 3 | 4 | transit_gateway_route_table_id = local.three_tgw.route_table_id 5 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 6 | } 7 | 8 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_two" { 9 | provider = aws.three 10 | 11 | transit_gateway_route_table_id = local.three_tgw.route_table_id 12 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 13 | } 14 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/three_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_three" { 2 | provider = aws.three 3 | } 4 | 5 | data "aws_region" "this_three" { 6 | provider = aws.three 7 | } 8 | 9 | locals { 10 | three_provider_account_id = data.aws_caller_identity.this_three.account_id 11 | three_provider_region_name = data.aws_region.this_three.name 12 | 13 | three_tgw = var.full_mesh_trio.three.centralized_router 14 | three_tgw_vpc_network_cidrs = toset(concat(local.three_tgw.vpc.network_cidrs, local.three_tgw.vpc.secondary_cidrs)) 15 | three_tgw_vpc_ipv6_network_cidrs = toset(concat(local.three_tgw.vpc.ipv6_network_cidrs, local.three_tgw.vpc.ipv6_secondary_cidrs)) 16 | three_tgw_vpc_route_table_ids = toset(concat(local.three_tgw.vpc.private_route_table_ids, local.three_tgw.vpc.public_route_table_ids)) 17 | } 18 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/three_peering.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ec2_transit_gateway_peering_attachment" "this_three_to_this_one" { 2 | provider = aws.three 3 | 4 | transit_gateway_id = local.three_tgw.id 5 | peer_account_id = local.one_tgw.account_id 6 | peer_region = local.one_tgw.region 7 | peer_transit_gateway_id = local.one_tgw.id 8 | tags = merge( 9 | local.default_tags, 10 | { 11 | Name = format(local.peering_name_format, local.three_tgw.full_name, local.one_tgw.full_name) 12 | Side = "Three Creator" 13 | } 14 | ) 15 | 16 | lifecycle { 17 | # cant use dynamic block for lifecycle blocks 18 | # tgw region and account id preconditions are evaluated only on apply 19 | # see preconditions.tf 20 | precondition { 21 | condition = local.one_tgw_provider_region_check.condition 22 | error_message = local.one_tgw_provider_region_check.error_message 23 | } 24 | 25 | precondition { 26 | condition = local.one_tgw_provider_account_id_check.condition 27 | error_message = local.one_tgw_provider_account_id_check.error_message 28 | } 29 | 30 | precondition { 31 | condition = local.two_tgw_provider_region_check.condition 32 | error_message = local.two_tgw_provider_region_check.error_message 33 | } 34 | 35 | precondition { 36 | condition = local.two_tgw_provider_account_id_check.condition 37 | error_message = local.two_tgw_provider_account_id_check.error_message 38 | } 39 | 40 | precondition { 41 | condition = local.three_tgw_provider_region_check.condition 42 | error_message = local.three_tgw_provider_region_check.error_message 43 | } 44 | 45 | precondition { 46 | condition = local.three_tgw_provider_account_id_check.condition 47 | error_message = local.three_tgw_provider_account_id_check.error_message 48 | } 49 | } 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_peering_attachment_accepter" "this_three_to_this_one" { 53 | provider = aws.one 54 | 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment.this_three_to_this_one.id 56 | tags = merge( 57 | local.default_tags, 58 | { 59 | Name = format(local.peering_name_format, local.one_tgw.full_name, local.three_tgw.full_name) 60 | Side = "One Accepter" 61 | } 62 | ) 63 | } 64 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/three_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | three_tgw_provider_region_check = { 3 | condition = contains([local.three_provider_region_name], local.three_tgw.region) 4 | error_message = "Centralized Router Three's region must match the aws.three provider alias region for Full Mesh Trio." 5 | } 6 | 7 | three_tgw_provider_account_id_check = { 8 | condition = contains([local.three_provider_account_id], local.three_tgw.account_id) 9 | error_message = "Centralized Router Three's account ID must match the aws.three provider alias account ID for Full Mesh Trio." 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/three_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_one_tgw" { 2 | provider = aws.three 3 | 4 | for_each = local.one_tgw_vpc_network_cidrs 5 | 6 | transit_gateway_route_table_id = local.three_tgw.route_table_id 7 | destination_cidr_block = each.value 8 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 9 | } 10 | 11 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_two_tgw" { 12 | provider = aws.three 13 | 14 | for_each = local.two_tgw_vpc_network_cidrs 15 | 16 | transit_gateway_route_table_id = local.three_tgw.route_table_id 17 | destination_cidr_block = each.value 18 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 19 | } 20 | 21 | #ipv6 22 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_ipv6_routes_to_vpcs_in_one_tgw" { 23 | provider = aws.three 24 | 25 | for_each = local.one_tgw_vpc_ipv6_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.three_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_ipv6_routes_to_vpcs_in_two_tgw" { 33 | provider = aws.three 34 | 35 | for_each = local.two_tgw_vpc_ipv6_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.three_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 40 | } 41 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/two_associations.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_one" { 2 | provider = aws.two 3 | 4 | transit_gateway_route_table_id = local.two_tgw.route_table_id 5 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 6 | } 7 | 8 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_three" { 9 | provider = aws.two 10 | 11 | transit_gateway_route_table_id = local.two_tgw.route_table_id 12 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 13 | } 14 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/two_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_two" { 2 | provider = aws.two 3 | } 4 | 5 | data "aws_region" "this_two" { 6 | provider = aws.two 7 | } 8 | 9 | locals { 10 | two_provider_account_id = data.aws_caller_identity.this_two.account_id 11 | two_provider_region_name = data.aws_region.this_two.name 12 | 13 | two_tgw = var.full_mesh_trio.two.centralized_router 14 | two_tgw_vpc_network_cidrs = toset(concat(local.two_tgw.vpc.network_cidrs, local.two_tgw.vpc.secondary_cidrs)) 15 | two_tgw_vpc_ipv6_network_cidrs = toset(concat(local.two_tgw.vpc.ipv6_network_cidrs, local.two_tgw.vpc.ipv6_secondary_cidrs)) 16 | two_tgw_vpc_route_table_ids = toset(concat(local.two_tgw.vpc.private_route_table_ids, local.two_tgw.vpc.public_route_table_ids)) 17 | } 18 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/two_peering.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ec2_transit_gateway_peering_attachment" "this_two_to_this_three" { 2 | provider = aws.two 3 | 4 | transit_gateway_id = local.two_tgw.id 5 | peer_account_id = local.three_tgw.account_id 6 | peer_region = local.three_tgw.region 7 | peer_transit_gateway_id = local.three_tgw.id 8 | tags = merge( 9 | local.default_tags, 10 | { 11 | Name = format(local.peering_name_format, local.two_tgw.full_name, local.three_tgw.full_name) 12 | Side = "Two Creator" 13 | } 14 | ) 15 | 16 | lifecycle { 17 | # cant use dynamic block for lifecycle blocks 18 | # tgw region and account id preconditions are evaluated only on apply 19 | # see preconditions.tf 20 | precondition { 21 | condition = local.one_tgw_provider_region_check.condition 22 | error_message = local.one_tgw_provider_region_check.error_message 23 | } 24 | 25 | precondition { 26 | condition = local.one_tgw_provider_account_id_check.condition 27 | error_message = local.one_tgw_provider_account_id_check.error_message 28 | } 29 | 30 | precondition { 31 | condition = local.two_tgw_provider_region_check.condition 32 | error_message = local.two_tgw_provider_region_check.error_message 33 | } 34 | 35 | precondition { 36 | condition = local.two_tgw_provider_account_id_check.condition 37 | error_message = local.two_tgw_provider_account_id_check.error_message 38 | } 39 | 40 | precondition { 41 | condition = local.three_tgw_provider_region_check.condition 42 | error_message = local.three_tgw_provider_region_check.error_message 43 | } 44 | 45 | precondition { 46 | condition = local.three_tgw_provider_account_id_check.condition 47 | error_message = local.three_tgw_provider_account_id_check.error_message 48 | } 49 | } 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_peering_attachment_accepter" "this_two_to_this_three" { 53 | provider = aws.three 54 | 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment.this_two_to_this_three.id 56 | tags = merge( 57 | local.default_tags, 58 | { 59 | Name = format(local.peering_name_format, local.three_tgw.full_name, local.two_tgw.full_name) 60 | Side = "Three Accepter" 61 | } 62 | ) 63 | } 64 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/two_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | two_tgw_provider_region_check = { 3 | condition = contains([local.two_provider_region_name], local.two_tgw.region) 4 | error_message = "Centralized Router Two's region must match the aws.two provider alias region for Full Mesh Trio." 5 | } 6 | 7 | two_tgw_provider_account_id_check = { 8 | condition = contains([local.two_provider_account_id], local.two_tgw.account_id) 9 | error_message = "Centralized Router Two's account ID must match the aws.two provider alias account ID for Full Mesh Trio." 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/two_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_one_tgw" { 2 | provider = aws.two 3 | 4 | for_each = local.one_tgw_vpc_network_cidrs 5 | 6 | transit_gateway_route_table_id = local.two_tgw.route_table_id 7 | destination_cidr_block = each.value 8 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 9 | } 10 | 11 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_three_tgw" { 12 | provider = aws.two 13 | 14 | for_each = local.three_tgw_vpc_network_cidrs 15 | 16 | transit_gateway_route_table_id = local.two_tgw.route_table_id 17 | destination_cidr_block = each.value 18 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 19 | } 20 | 21 | #ipv6 22 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_ipv6_routes_to_vpcs_in_one_tgw" { 23 | provider = aws.two 24 | 25 | for_each = local.one_tgw_vpc_ipv6_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.two_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_ipv6_routes_to_vpcs_in_three_tgw" { 33 | provider = aws.two 34 | 35 | for_each = local.three_tgw_vpc_ipv6_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.two_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 40 | } 41 | -------------------------------------------------------------------------------- /networking/full_mesh_trio/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=5.61" 7 | configuration_aliases = [aws.one, aws.two, aws.three] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /networking/intra_vpc_security_group_rule_for_tiered_vpc_ng/base.tf: -------------------------------------------------------------------------------- 1 | # Pull caller identity data from provider 2 | data "aws_caller_identity" "this" {} 3 | 4 | # Pull region data from provider 5 | data "aws_region" "this" {} 6 | 7 | locals { 8 | account_id = data.aws_caller_identity.this.account_id 9 | region_name = data.aws_region.this.name 10 | region_label = lookup(var.region_az_labels, local.region_name) 11 | 12 | # Each VPC id should have an inbound rule from all other VPC networks except itself. 13 | vpc_id_to_network_cidrs = { for this in var.intra_vpc_security_group_rule.vpcs : this.id => concat([this.network_cidr], this.secondary_cidrs) } 14 | 15 | # { vpc1-id = ["vpc2-network-cidr", "vpc3-network-cidr", ...], vpc2-id = ["vpc1-network-cidr", "vpc3-network-cidr", ...], vpc3-id = ["vpc1-network-cidr", "vpc2-network-cidr", ...] ... } 16 | vpc_id_to_inbound_network_cidrs = { 17 | for vpc_id_and_network_cidr in setproduct(keys(local.vpc_id_to_network_cidrs), flatten(values(local.vpc_id_to_network_cidrs))) : 18 | vpc_id_and_network_cidr[0] => vpc_id_and_network_cidr[1]... 19 | if !contains(lookup(local.vpc_id_to_network_cidrs, vpc_id_and_network_cidr[0]), vpc_id_and_network_cidr[1]) 20 | } 21 | 22 | # complete the security group rule object for each vpc 23 | vpc_id_to_intra_vpc_security_group_rule = { 24 | for this in var.intra_vpc_security_group_rule.vpcs : 25 | this.id => merge(var.intra_vpc_security_group_rule.rule, { 26 | intra_vpc_security_group_id = this.intra_vpc_security_group_id 27 | network_cidrs = lookup(local.vpc_id_to_inbound_network_cidrs, this.id) 28 | type = "ingress" 29 | }) } 30 | } 31 | 32 | resource "aws_security_group_rule" "this" { 33 | for_each = local.vpc_id_to_intra_vpc_security_group_rule 34 | 35 | security_group_id = each.value.intra_vpc_security_group_id 36 | cidr_blocks = each.value.network_cidrs 37 | type = each.value.type 38 | from_port = each.value.from_port 39 | to_port = each.value.to_port 40 | protocol = each.value.protocol 41 | description = format( 42 | "%s-%s: Allow %s inbound from other intra region VPCs in %s.", 43 | upper(var.env_prefix), 44 | local.region_label, 45 | each.value.label, 46 | local.region_label 47 | ) 48 | 49 | lifecycle { 50 | # preconditions are evaluated on apply only. 51 | precondition { 52 | condition = alltrue([for this in var.intra_vpc_security_group_rule.vpcs : contains([local.account_id], this.account_id)]) 53 | error_message = "All VPC account IDs must match the aws provider account ID for Intra VPC Security Group Rules." 54 | } 55 | 56 | precondition { 57 | condition = alltrue([for this in var.intra_vpc_security_group_rule.vpcs : contains([local.region_name], this.region)]) 58 | error_message = "All VPC regions must match the aws provider region for Intra VPC Security Group Rules." 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /networking/intra_vpc_security_group_rule_for_tiered_vpc_ng/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * # Intra VPC Security Group Rule Description 3 | * This Intra VPC Security Group Rule will create a SG Rule for each Tiered VPC allowing inbound-only ports from all other VPC networks (excluding itself). 4 | * 5 | * `v1.8.2` 6 | * - New [Dual Stack Networking Trifecta Demo](https://github.com/JudeQuintana/terraform-main/tree/main/dual_stack_networking_trifecta_demo) 7 | * - Same declaration as before but now supports VPC IPv4 Secondary CIDRs 8 | * 9 | * `v1.8.2` example: 10 | * ``` 11 | * module "intra_vpc_security_group_rules" { 12 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/intra_vpc_security_group_rule_for_tiered_vpc_ng?ref=v1.8.2" 13 | * 14 | * for_each = { for r in local.intra_vpc_security_group_rules : r.label => r } 15 | * 16 | * env_prefix = var.env_prefix 17 | * region_az_labels = var.region_az_labels 18 | * intra_vpc_security_group_rule = { 19 | * rule = each.value 20 | * vpcs = module.vpcs 21 | * } 22 | * } 23 | * ``` 24 | * 25 | * `v1.8.1`: 26 | * - Creates SG rules for IPv4 VPC network cidrs across VPCs 27 | * - Allowing SSH and ping communication across VPCs 28 | * 29 | * `v1.8.1` example: 30 | * ``` 31 | * # This will create a sg rule for each vpc allowing inbound-only ports from all other vpc networks (excluding itself). 32 | * # Basically allowing ssh and ping communication across all VPCs. 33 | * locals { 34 | * intra_vpc_security_group_rules = [ 35 | * { 36 | * label = "ssh" 37 | * protocol = "tcp" 38 | * from_port = 22 39 | * to_port = 22 40 | * }, 41 | * { 42 | * label = "ping" 43 | * protocol = "icmp" 44 | * from_port = 8 45 | * to_port = 0 46 | * } 47 | * ] 48 | * } 49 | * 50 | * module "intra_vpc_security_group_rules" { 51 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/intra_vpc_security_group_rule_for_tiered_vpc_ng?ref=v1.8.1" 52 | * 53 | * for_each = { for r in local.intra_vpc_security_group_rules : r.label => r } 54 | * 55 | * env_prefix = var.env_prefix 56 | * region_az_labels = var.region_az_labels 57 | * intra_vpc_security_group_rule = { 58 | * rule = each.value 59 | * vpcs = module.vpcs 60 | * } 61 | * } 62 | * ``` 63 | * 64 | * # Networking Trifecta Demo 65 | * Blog Post: 66 | * [Terraform Networking Trifecta ](https://jq1.io/posts/tnt/) 67 | * 68 | * Main: 69 | * - [Networking Trifecta Demo](https://github.com/JudeQuintana/terraform-main/tree/main/networking_trifecta_demo) 70 | * - See [Trifecta Demo Time](https://jq1.io/posts/tnt/#trifecta-demo-time) for instructions. 71 | * 72 | */ 73 | -------------------------------------------------------------------------------- /networking/intra_vpc_security_group_rule_for_tiered_vpc_ng/outputs.tf: -------------------------------------------------------------------------------- 1 | output "account_id" { 2 | value = local.account_id 3 | } 4 | 5 | output "region" { 6 | value = local.region_name 7 | } 8 | 9 | output "rule" { 10 | value = var.intra_vpc_security_group_rule.rule 11 | } 12 | 13 | output "vpcs" { 14 | value = var.intra_vpc_security_group_rule.vpcs 15 | } 16 | -------------------------------------------------------------------------------- /networking/intra_vpc_security_group_rule_for_tiered_vpc_ng/variables.tf: -------------------------------------------------------------------------------- 1 | variable "env_prefix" { 2 | description = "prod, stage, test" 3 | type = string 4 | } 5 | 6 | variable "region_az_labels" { 7 | description = "Region and AZ names mapped to short naming conventions for labeling" 8 | type = map(string) 9 | } 10 | 11 | variable "intra_vpc_security_group_rule" { 12 | description = "intra vpc security group rule configuration" 13 | type = object({ 14 | # security rule object to allow inbound across vpcs intra-vpc security group 15 | rule = object({ 16 | label = string 17 | protocol = string 18 | from_port = number 19 | to_port = number 20 | }) 21 | # map of tiered_vpc_ng objects 22 | vpcs = map(object({ 23 | id = string 24 | intra_vpc_security_group_id = string 25 | name = string 26 | network_cidr = string 27 | secondary_cidrs = optional(list(string), []) 28 | region = string 29 | account_id = string 30 | })) 31 | }) 32 | 33 | validation { 34 | condition = length(distinct([for this in var.intra_vpc_security_group_rule.vpcs : this.account_id])) <= 1 35 | error_message = "All VPCs must have the same account id as each other." 36 | } 37 | 38 | validation { 39 | condition = length(distinct([for this in var.intra_vpc_security_group_rule.vpcs : this.region])) <= 1 40 | error_message = "All VPCs must have the same region as each other." 41 | } 42 | 43 | validation { 44 | condition = length(distinct([ 45 | for this in var.intra_vpc_security_group_rule.vpcs : this.name 46 | ])) == length([ 47 | for this in var.intra_vpc_security_group_rule.vpcs : this.name 48 | ]) 49 | error_message = "All VPCs must have unique names." 50 | } 51 | 52 | validation { 53 | condition = length(distinct([ 54 | for this in var.intra_vpc_security_group_rule.vpcs : this.network_cidr 55 | ])) == length([ 56 | for this in var.intra_vpc_security_group_rule.vpcs : this.network_cidr 57 | ]) 58 | error_message = "All VPCs must have unique network CIDRs." 59 | } 60 | 61 | validation { 62 | condition = alltrue([ 63 | for this in var.intra_vpc_security_group_rule.vpcs : can(cidrnetmask(this.network_cidr)) 64 | ]) 65 | error_message = "Each VPC network CIDR must be valid IPv4 CIDR notation (ie x.x.x.x/xx -> 10.46.0.0/20). Check for typos." 66 | } 67 | 68 | validation { 69 | condition = alltrue(flatten([ 70 | for this in var.intra_vpc_security_group_rule.vpcs : [ 71 | for secondary_cidr in this.secondary_cidrs : 72 | can(cidrnetmask(secondary_cidr)) 73 | ]])) 74 | error_message = "Each Secondary VPC CIDR mush have valid IPv4 CIDR notation (ie x.x.x.x/xx -> 10.46.0.0/20). Check for typos." 75 | } 76 | 77 | validation { 78 | condition = length(var.intra_vpc_security_group_rule.vpcs) > 1 79 | error_message = "There must be at least 2 VPCs." 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /networking/intra_vpc_security_group_rule_for_tiered_vpc_ng/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=4.20" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /networking/ipv6_full_mesh_intra_vpc_security_group_rules/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * # Full Mesh Intra VPC Secuity Group Rules Description 3 | * - This allowing inbound protocols across regions based on rules (ie ssh, icmp, etc) that 4 | * were used in each intra_vpc_security_group_rules modules for all vpcs in each region while in a TGW full mesh configuration. 5 | * - Rule sets for one, two and three Intra VPC Security Group Rules should be the same. also enforced by validation 6 | * - ipv6 network cidrs 7 | * - ipv6 secondary cidrs 8 | * - See it in action in [security_group_rules.tf](https://github.com/JudeQuintana/terraform-main/blob/main/full_mesh_trio_demo/security_group_rules.tf) in the [Full Mesh Trio Demo](https://github.com/JudeQuintana/terraform-main/tree/main/full_mesh_trio_demo). 9 | * 10 | * ``` 11 | * module "ipv6_full_mesh_intra_vpc_security_group_rules" { 12 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/ipv6_full_mesh_intra_vpc_security_group_rules?ref=1.9.0 13 | * 14 | * providers = { 15 | * aws.one = aws.use1 16 | * aws.two = aws.use2 17 | * aws.three = aws.usw2 18 | * } 19 | * 20 | * env_prefix = var.env_prefix 21 | * region_az_labels = var.region_az_labels 22 | * ipv6_full_mesh_intra_vpc_security_group_rules = { 23 | * one = { 24 | * ipv6_intra_vpc_security_group_rules = module.ipv6_intra_vpc_security_group_rules_use1 25 | * } 26 | * two = { 27 | * ipv6_intra_vpc_security_group_rules = module.ipv6_intra_vpc_security_group_rules_use2 28 | * } 29 | * three = { 30 | * ipv6_intra_vpc_security_group_rules = module.ipv6_intra_vpc_security_group_rules_usw2 31 | * } 32 | * } 33 | * } 34 | * ``` 35 | * 36 | */ 37 | 38 | -------------------------------------------------------------------------------- /networking/ipv6_full_mesh_intra_vpc_security_group_rules/outputs.tf: -------------------------------------------------------------------------------- 1 | output "one" { 2 | value = { 3 | account_id = local.one_account_id 4 | region = local.one_region_name 5 | rules = [for this in var.ipv6_full_mesh_intra_vpc_security_group_rules.one.ipv6_intra_vpc_security_group_rules : this.rule] 6 | } 7 | } 8 | 9 | output "two" { 10 | value = { 11 | account_id = local.two_account_id 12 | region = local.two_region_name 13 | rules = [for this in var.ipv6_full_mesh_intra_vpc_security_group_rules.two.ipv6_intra_vpc_security_group_rules : this.rule] 14 | } 15 | } 16 | 17 | output "three" { 18 | value = { 19 | account_id = local.three_account_id 20 | region = local.three_region_name 21 | rules = [for this in var.ipv6_full_mesh_intra_vpc_security_group_rules.three.ipv6_intra_vpc_security_group_rules : this.rule] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /networking/ipv6_full_mesh_intra_vpc_security_group_rules/preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # used on all aws_security_group_rule resources to guarantee the intra vpc security group rules match their relative provider's region. 3 | one_provider_to_one_intra_vpc_security_group_rules_region_check = { 4 | condition = alltrue([ 5 | for this in var.ipv6_full_mesh_intra_vpc_security_group_rules.one.ipv6_intra_vpc_security_group_rules : 6 | contains([local.one_region_name], this.region) 7 | ]) 8 | error_message = "The IPv6 Intra VPC Security Group Rule's regions for One must match the aws.one provider alias region for IPv6 Full Mesh VPC Security Group Rules." 9 | } 10 | 11 | one_provider_to_one_intra_vpc_security_group_rules_account_id_check = { 12 | condition = alltrue([ 13 | for this in var.ipv6_full_mesh_intra_vpc_security_group_rules.one.ipv6_intra_vpc_security_group_rules : 14 | contains([local.one_account_id], this.account_id) 15 | ]) 16 | error_message = "The IPv6 Intra VPC Security Group Rule's account ID for One must match the aws.one provider alias account ID for IPv6 Full Mesh Intra VPC Security Group Rules." 17 | } 18 | 19 | two_provider_to_two_intra_vpc_security_group_rules_region_check = { 20 | condition = alltrue([ 21 | for this in var.ipv6_full_mesh_intra_vpc_security_group_rules.two.ipv6_intra_vpc_security_group_rules : 22 | contains([local.two_region_name], this.region) 23 | ]) 24 | error_message = "The IPv6 Intra VPC Security Group Rule's regions for Two must match the aws.two provider alias region for IPv6 Full Mesh VPC Security Group Rules." 25 | } 26 | 27 | two_provider_to_two_intra_vpc_security_group_rules_account_id_check = { 28 | condition = alltrue([ 29 | for this in var.ipv6_full_mesh_intra_vpc_security_group_rules.two.ipv6_intra_vpc_security_group_rules : 30 | contains([local.two_account_id], this.account_id) 31 | ]) 32 | error_message = "The IPv6 Intra VPC Security Group Rule's account ID for Two must match the aws.two provider alias account ID for IPv6 Full Mesh Intra VPC Security Group Rules." 33 | } 34 | 35 | three_provider_to_three_intra_vpc_security_group_rules_region_check = { 36 | condition = alltrue([ 37 | for this in var.ipv6_full_mesh_intra_vpc_security_group_rules.three.ipv6_intra_vpc_security_group_rules : 38 | contains([local.three_region_name], this.region) 39 | ]) 40 | error_message = "The IPv6 Intra VPC Security Group Rule's regions for Three must match the aws.three provider alias region for IPv6 Full Mesh VPC Security Group Rules." 41 | } 42 | 43 | three_provider_to_three_intra_vpc_security_group_rules_account_id_check = { 44 | condition = alltrue([ 45 | for this in var.ipv6_full_mesh_intra_vpc_security_group_rules.three.ipv6_intra_vpc_security_group_rules : 46 | contains([local.three_account_id], this.account_id) 47 | ]) 48 | error_message = "The IPv6 Intra VPC Security Group Rule's account ID for Three must match the aws.three provider alias account ID for IPv6 Full Mesh Intra VPC Security Group Rules." 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /networking/ipv6_full_mesh_intra_vpc_security_group_rules/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=5.61" 7 | configuration_aliases = [aws.one, aws.two, aws.three] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /networking/ipv6_intra_vpc_security_group_rule_for_tiered_vpc_ng/base.tf: -------------------------------------------------------------------------------- 1 | # Pull caller identity data from provider 2 | data "aws_caller_identity" "this" {} 3 | 4 | # Pull region data from provider 5 | data "aws_region" "this" {} 6 | 7 | locals { 8 | account_id = data.aws_caller_identity.this.account_id 9 | region_name = data.aws_region.this.name 10 | region_label = lookup(var.region_az_labels, local.region_name) 11 | rule_type = "ingress" 12 | } 13 | 14 | # Each VPC id should have an inbound rule from all other VPC networks except itself. 15 | # ipv6 16 | locals { 17 | vpc_id_to_ipv6_network_cidrs = { for this in var.ipv6_intra_vpc_security_group_rule.vpcs : this.id => concat([this.ipv6_network_cidr], this.ipv6_secondary_cidrs) } 18 | 19 | vpc_id_to_inbound_ipv6_network_cidrs = { 20 | for vpc_id_and_ipv6_network_cidr in setproduct(keys(local.vpc_id_to_ipv6_network_cidrs), flatten(values(local.vpc_id_to_ipv6_network_cidrs))) : 21 | vpc_id_and_ipv6_network_cidr[0] => vpc_id_and_ipv6_network_cidr[1]... 22 | if !contains(lookup(local.vpc_id_to_ipv6_network_cidrs, vpc_id_and_ipv6_network_cidr[0]), vpc_id_and_ipv6_network_cidr[1]) 23 | } 24 | 25 | vpc_id_to_intra_vpc_ipv6_security_group_rule = { 26 | for this in var.ipv6_intra_vpc_security_group_rule.vpcs : 27 | this.id => merge(var.ipv6_intra_vpc_security_group_rule.rule, { 28 | intra_vpc_security_group_id = this.intra_vpc_security_group_id 29 | ipv6_network_cidrs = lookup(local.vpc_id_to_inbound_ipv6_network_cidrs, this.id) 30 | type = local.rule_type 31 | }) } 32 | } 33 | 34 | resource "aws_security_group_rule" "this" { 35 | for_each = local.vpc_id_to_intra_vpc_ipv6_security_group_rule 36 | 37 | security_group_id = each.value.intra_vpc_security_group_id 38 | ipv6_cidr_blocks = each.value.ipv6_network_cidrs 39 | type = each.value.type 40 | from_port = each.value.from_port 41 | to_port = each.value.to_port 42 | protocol = each.value.protocol 43 | description = format( 44 | "%s-%s: Allow %s inbound from other intra region VPCs in %s.", 45 | upper(var.env_prefix), 46 | local.region_label, 47 | each.value.label, 48 | local.region_label 49 | ) 50 | 51 | lifecycle { 52 | # preconditions are evaluated on apply only. 53 | precondition { 54 | condition = alltrue([for this in var.ipv6_intra_vpc_security_group_rule.vpcs : contains([local.account_id], this.account_id)]) 55 | error_message = "All VPC account IDs must match the aws provider account ID for IPv6 Intra VPC Security Group Rules." 56 | } 57 | 58 | precondition { 59 | condition = alltrue([for this in var.ipv6_intra_vpc_security_group_rule.vpcs : contains([local.region_name], this.region)]) 60 | error_message = "All VPC regions must match the aws provider region for IPv6 Intra VPC Security Group Rules." 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /networking/ipv6_intra_vpc_security_group_rule_for_tiered_vpc_ng/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * # IPv6 Intra VPC Security Group Rule Description 3 | * This IPv6 Intra VPC Security Group Rule will create a SG Rule for each Tiered VPC allowing inbound-only ports from all other VPC networks (excluding itself). 4 | * 5 | * `v1.9.0` 6 | * - support for ipv6 secondary cidrs 7 | * - moar validation 8 | * ``` 9 | * module "ipv6_intra_vpc_security_group_rules" { 10 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/ipv6_intra_vpc_security_group_rule_for_tiered_vpc_ng?ref=1.9.0" 11 | * .. 12 | * ``` 13 | * 14 | * `v1.8.2` 15 | * - New [Dual Stack Networking Trifecta Demo](https://github.com/JudeQuintana/terraform-main/tree/main/dual_stack_networking_trifecta_demo) 16 | * - Similar declaration to Intra VPC Security Group Rules modules but this only supports IPv6 17 | * - important to keep IPv6 SG rules as a separate module from IPv4 18 | * 19 | * `v1.8.2` example: 20 | * ``` 21 | * 22 | * locals { 23 | * ipv6_intra_vpc_security_group_rules = [ 24 | * { 25 | * label = "ssh6" 26 | * protocol = "tcp" 27 | * from_port = 22 28 | * to_port = 22 29 | * }, 30 | * { 31 | * label = "ping6" 32 | * protocol = "icmpv6" 33 | * from_port = -1 34 | * to_port = -1 35 | * } 36 | * ] 37 | * } 38 | * 39 | * # Allowing IPv6 SSH and ping communication across all VPCs 40 | * module "ipv6_intra_vpc_security_group_rules" { 41 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/ipv6_intra_vpc_security_group_rule_for_tiered_vpc_ng?ref=1.8.2" 42 | * 43 | * for_each = { for r in local.ipv6_intra_vpc_security_group_rules : r.label => r } 44 | * 45 | * env_prefix = var.env_prefix 46 | * region_az_labels = var.region_az_labels 47 | * ipv6_intra_vpc_security_group_rule = { 48 | * rule = each.value 49 | * vpcs = module.vpcs 50 | * } 51 | * } 52 | * ``` 53 | * 54 | */ 55 | -------------------------------------------------------------------------------- /networking/ipv6_intra_vpc_security_group_rule_for_tiered_vpc_ng/outputs.tf: -------------------------------------------------------------------------------- 1 | output "account_id" { 2 | value = local.account_id 3 | } 4 | 5 | output "region" { 6 | value = local.region_name 7 | } 8 | 9 | output "rule" { 10 | value = var.ipv6_intra_vpc_security_group_rule.rule 11 | } 12 | 13 | output "vpcs" { 14 | value = var.ipv6_intra_vpc_security_group_rule.vpcs 15 | } 16 | -------------------------------------------------------------------------------- /networking/ipv6_intra_vpc_security_group_rule_for_tiered_vpc_ng/variables.tf: -------------------------------------------------------------------------------- 1 | variable "env_prefix" { 2 | description = "prod, stage, test" 3 | type = string 4 | } 5 | 6 | variable "region_az_labels" { 7 | description = "Region and AZ names mapped to short naming conventions for labeling" 8 | type = map(string) 9 | } 10 | 11 | variable "ipv6_intra_vpc_security_group_rule" { 12 | description = "intra vpc security group rule configuration" 13 | type = object({ 14 | # security rule object to allow inbound across vpcs intra-vpc security group 15 | rule = object({ 16 | label = string 17 | protocol = string 18 | from_port = number 19 | to_port = number 20 | }) 21 | # map of tiered_vpc_ng objects 22 | vpcs = map(object({ 23 | id = string 24 | intra_vpc_security_group_id = string 25 | name = string 26 | ipv6_network_cidr = string 27 | ipv6_secondary_cidrs = list(string) 28 | region = string 29 | account_id = string 30 | })) 31 | }) 32 | 33 | validation { 34 | condition = length(distinct([for this in var.ipv6_intra_vpc_security_group_rule.vpcs : this.account_id])) <= 1 35 | error_message = "All VPCs must have the same account id as each other." 36 | } 37 | 38 | validation { 39 | condition = length(distinct([for this in var.ipv6_intra_vpc_security_group_rule.vpcs : this.region])) <= 1 40 | error_message = "All VPCs must have the same region as each other." 41 | } 42 | 43 | validation { 44 | condition = length(distinct([ 45 | for this in var.ipv6_intra_vpc_security_group_rule.vpcs : this.name 46 | ])) == length([ 47 | for this in var.ipv6_intra_vpc_security_group_rule.vpcs : this.name 48 | ]) 49 | error_message = "All VPCs must have unique names." 50 | } 51 | 52 | validation { 53 | condition = length(distinct([ 54 | for this in var.ipv6_intra_vpc_security_group_rule.vpcs : this.ipv6_network_cidr 55 | ])) == length([ 56 | for this in var.ipv6_intra_vpc_security_group_rule.vpcs : this.ipv6_network_cidr 57 | ]) 58 | error_message = "All VPCs must have unique IPv6 network CIDRs." 59 | } 60 | 61 | validation { 62 | condition = length(var.ipv6_intra_vpc_security_group_rule.vpcs) > 1 63 | error_message = "There must be at least 2 VPCs." 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /networking/ipv6_intra_vpc_security_group_rule_for_tiered_vpc_ng/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=5.61" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /networking/mega_mesh/base.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | peering_name_format = "%s <-> %s" 3 | route_format = "%s|%s" 4 | upper_env_prefix = upper(var.env_prefix) 5 | default_tags = merge({ 6 | Environment = var.env_prefix 7 | }, var.tags) 8 | } 9 | 10 | -------------------------------------------------------------------------------- /networking/mega_mesh/eight_associations.tf: -------------------------------------------------------------------------------- 1 | # eight 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_eight_to_this_one" { 3 | provider = aws.eight 4 | 5 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_one.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_eight_to_this_two" { 10 | provider = aws.eight 11 | 12 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_two.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_eight_to_this_three" { 17 | provider = aws.eight 18 | 19 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_three.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_eight_to_this_four" { 24 | provider = aws.eight 25 | 26 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_four.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_eight_to_this_five" { 31 | provider = aws.eight 32 | 33 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_five.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_eight_to_this_six" { 38 | provider = aws.eight 39 | 40 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_six.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_eight_to_this_seven" { 45 | provider = aws.eight 46 | 47 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_seven.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_eight_to_this_nine" { 52 | provider = aws.eight 53 | 54 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_eight.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_eight_to_this_ten" { 59 | provider = aws.eight 60 | 61 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_eight.id 63 | } 64 | 65 | -------------------------------------------------------------------------------- /networking/mega_mesh/eight_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_eight" { 2 | provider = aws.eight 3 | } 4 | 5 | data "aws_region" "this_eight" { 6 | provider = aws.eight 7 | } 8 | 9 | locals { 10 | eight_provider_account_id = data.aws_caller_identity.this_eight.account_id 11 | eight_provider_region_name = data.aws_region.this_eight.name 12 | 13 | eight_tgw = var.mega_mesh.eight.centralized_router 14 | eight_tgw_vpc_network_cidrs = toset(local.eight_tgw.vpc.network_cidrs) 15 | eight_tgw_vpc_route_table_ids = toset(concat(local.eight_tgw.vpc.private_route_table_ids, local.eight_tgw.vpc.public_route_table_ids)) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /networking/mega_mesh/eight_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | eight_tgw_provider_region_check = { 4 | condition = contains([local.eight_provider_region_name], local.eight_tgw.region) 5 | error_message = "Centralized Router Eight's region must match the aws.eight provider alias region for Mega Mesh." 6 | } 7 | 8 | eight_tgw_provider_account_id_check = { 9 | condition = contains([local.eight_provider_account_id], local.eight_tgw.account_id) 10 | error_message = "Centralized Router Eight's account ID must match the aws.eight provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /networking/mega_mesh/eight_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # eight 2 | resource "aws_ec2_transit_gateway_route" "this_eight_tgw_routes_to_vpcs_in_one_tgw" { 3 | provider = aws.eight 4 | 5 | for_each = local.one_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_one.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_eight_tgw_routes_to_vpcs_in_two_tgw" { 13 | provider = aws.eight 14 | 15 | for_each = local.two_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_two.id 20 | } 21 | 22 | resource "aws_ec2_transit_gateway_route" "this_eight_tgw_routes_to_vpcs_in_three_tgw" { 23 | provider = aws.eight 24 | 25 | for_each = local.three_tgw_vpc_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_three.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_eight_tgw_routes_to_vpcs_in_four_tgw" { 33 | provider = aws.eight 34 | 35 | for_each = local.four_tgw_vpc_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_four.id 40 | } 41 | 42 | resource "aws_ec2_transit_gateway_route" "this_eight_tgw_routes_to_vpcs_in_five_tgw" { 43 | provider = aws.eight 44 | 45 | for_each = local.five_tgw_vpc_network_cidrs 46 | 47 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 48 | destination_cidr_block = each.value 49 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_five.id 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_eight_tgw_routes_to_vpcs_in_six_tgw" { 53 | provider = aws.eight 54 | 55 | for_each = local.six_tgw_vpc_network_cidrs 56 | 57 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 58 | destination_cidr_block = each.value 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_six.id 60 | } 61 | 62 | resource "aws_ec2_transit_gateway_route" "this_eight_tgw_routes_to_vpcs_in_seven_tgw" { 63 | provider = aws.eight 64 | 65 | for_each = local.seven_tgw_vpc_network_cidrs 66 | 67 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 68 | destination_cidr_block = each.value 69 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_seven.id 70 | } 71 | 72 | resource "aws_ec2_transit_gateway_route" "this_eight_tgw_routes_to_vpcs_in_nine_tgw" { 73 | provider = aws.eight 74 | 75 | for_each = local.nine_tgw_vpc_network_cidrs 76 | 77 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 78 | destination_cidr_block = each.value 79 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_eight.id 80 | } 81 | 82 | resource "aws_ec2_transit_gateway_route" "this_eight_tgw_routes_to_vpcs_in_ten_tgw" { 83 | provider = aws.eight 84 | 85 | for_each = local.ten_tgw_vpc_network_cidrs 86 | 87 | transit_gateway_route_table_id = local.eight_tgw.route_table_id 88 | destination_cidr_block = each.value 89 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_eight.id 90 | } 91 | 92 | -------------------------------------------------------------------------------- /networking/mega_mesh/five_associations.tf: -------------------------------------------------------------------------------- 1 | # five 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_five_to_this_one" { 3 | provider = aws.five 4 | 5 | transit_gateway_route_table_id = local.five_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_one.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_five_to_this_two" { 10 | provider = aws.five 11 | 12 | transit_gateway_route_table_id = local.five_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_two.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_five_to_this_three" { 17 | provider = aws.five 18 | 19 | transit_gateway_route_table_id = local.five_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_three.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_five_to_this_four" { 24 | provider = aws.five 25 | 26 | transit_gateway_route_table_id = local.five_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_four.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_five_to_this_six" { 31 | provider = aws.five 32 | 33 | transit_gateway_route_table_id = local.five_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_five.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_five_to_this_seven" { 38 | provider = aws.five 39 | 40 | transit_gateway_route_table_id = local.five_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_five.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_five_to_this_eight" { 45 | provider = aws.five 46 | 47 | transit_gateway_route_table_id = local.five_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_five.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_five_to_this_nine" { 52 | provider = aws.five 53 | 54 | transit_gateway_route_table_id = local.five_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_five.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_five_to_this_ten" { 59 | provider = aws.five 60 | 61 | transit_gateway_route_table_id = local.five_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_five.id 63 | } 64 | -------------------------------------------------------------------------------- /networking/mega_mesh/five_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_five" { 2 | provider = aws.five 3 | } 4 | 5 | data "aws_region" "this_five" { 6 | provider = aws.five 7 | } 8 | 9 | locals { 10 | five_provider_account_id = data.aws_caller_identity.this_five.account_id 11 | five_provider_region_name = data.aws_region.this_five.name 12 | 13 | five_tgw = var.mega_mesh.five.centralized_router 14 | five_tgw_vpc_network_cidrs = toset(local.five_tgw.vpc.network_cidrs) 15 | five_tgw_vpc_route_table_ids = toset(concat(local.five_tgw.vpc.private_route_table_ids, local.five_tgw.vpc.public_route_table_ids)) 16 | } 17 | -------------------------------------------------------------------------------- /networking/mega_mesh/five_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | five_tgw_provider_region_check = { 4 | condition = contains([local.five_provider_region_name], local.five_tgw.region) 5 | error_message = "Centralized Router Five's region must match the aws.five provider alias region for Mega Mesh." 6 | } 7 | 8 | five_tgw_provider_account_id_check = { 9 | condition = contains([local.five_provider_account_id], local.five_tgw.account_id) 10 | error_message = "Centralized Router Five's account ID must match the aws.five provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /networking/mega_mesh/five_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # five 2 | resource "aws_ec2_transit_gateway_route" "this_five_tgw_routes_to_vpcs_in_one_tgw" { 3 | provider = aws.five 4 | 5 | for_each = local.one_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.five_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_one.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_five_tgw_routes_to_vpcs_in_two_tgw" { 13 | provider = aws.five 14 | 15 | for_each = local.two_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.five_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_two.id 20 | } 21 | 22 | resource "aws_ec2_transit_gateway_route" "this_five_tgw_routes_to_vpcs_in_three_tgw" { 23 | provider = aws.five 24 | 25 | for_each = local.three_tgw_vpc_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.five_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_three.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_five_tgw_routes_to_vpcs_in_four_tgw" { 33 | provider = aws.five 34 | 35 | for_each = local.four_tgw_vpc_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.five_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_four.id 40 | } 41 | 42 | resource "aws_ec2_transit_gateway_route" "this_five_tgw_routes_to_vpcs_in_six_tgw" { 43 | provider = aws.five 44 | 45 | for_each = local.six_tgw_vpc_network_cidrs 46 | 47 | transit_gateway_route_table_id = local.five_tgw.route_table_id 48 | destination_cidr_block = each.value 49 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_five.id 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_five_tgw_routes_to_vpcs_in_seven_tgw" { 53 | provider = aws.five 54 | 55 | for_each = local.seven_tgw_vpc_network_cidrs 56 | 57 | transit_gateway_route_table_id = local.five_tgw.route_table_id 58 | destination_cidr_block = each.value 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_five.id 60 | } 61 | 62 | resource "aws_ec2_transit_gateway_route" "this_five_tgw_routes_to_vpcs_in_eight_tgw" { 63 | provider = aws.five 64 | 65 | for_each = local.eight_tgw_vpc_network_cidrs 66 | 67 | transit_gateway_route_table_id = local.five_tgw.route_table_id 68 | destination_cidr_block = each.value 69 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_five.id 70 | } 71 | 72 | resource "aws_ec2_transit_gateway_route" "this_five_tgw_routes_to_vpcs_in_nine_tgw" { 73 | provider = aws.five 74 | 75 | for_each = local.nine_tgw_vpc_network_cidrs 76 | 77 | transit_gateway_route_table_id = local.five_tgw.route_table_id 78 | destination_cidr_block = each.value 79 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_five.id 80 | } 81 | 82 | resource "aws_ec2_transit_gateway_route" "this_five_tgw_routes_to_vpcs_in_ten_tgw" { 83 | provider = aws.five 84 | 85 | for_each = local.ten_tgw_vpc_network_cidrs 86 | 87 | transit_gateway_route_table_id = local.five_tgw.route_table_id 88 | destination_cidr_block = each.value 89 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_five.id 90 | } 91 | -------------------------------------------------------------------------------- /networking/mega_mesh/four_associations.tf: -------------------------------------------------------------------------------- 1 | # four 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_four_to_this_one" { 3 | provider = aws.four 4 | 5 | transit_gateway_route_table_id = local.four_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_one.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_four_to_this_two" { 10 | provider = aws.four 11 | 12 | transit_gateway_route_table_id = local.four_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_two.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_four_to_this_three" { 17 | provider = aws.four 18 | 19 | transit_gateway_route_table_id = local.four_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_three.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_four_to_this_five" { 24 | provider = aws.four 25 | 26 | transit_gateway_route_table_id = local.four_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_four.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_four_to_this_six" { 31 | provider = aws.four 32 | 33 | transit_gateway_route_table_id = local.four_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_four.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_four_to_this_seven" { 38 | provider = aws.four 39 | 40 | transit_gateway_route_table_id = local.four_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_four.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_four_to_this_eight" { 45 | provider = aws.four 46 | 47 | transit_gateway_route_table_id = local.four_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_four.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_four_to_this_nine" { 52 | provider = aws.four 53 | 54 | transit_gateway_route_table_id = local.four_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_four.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_four_to_this_ten" { 59 | provider = aws.four 60 | 61 | transit_gateway_route_table_id = local.four_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_four.id 63 | } 64 | 65 | -------------------------------------------------------------------------------- /networking/mega_mesh/four_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_four" { 2 | provider = aws.four 3 | } 4 | 5 | data "aws_region" "this_four" { 6 | provider = aws.four 7 | } 8 | 9 | locals { 10 | four_provider_account_id = data.aws_caller_identity.this_four.account_id 11 | four_provider_region_name = data.aws_region.this_four.name 12 | 13 | four_tgw = var.mega_mesh.four.centralized_router 14 | four_tgw_vpc_network_cidrs = toset(local.four_tgw.vpc.network_cidrs) 15 | four_tgw_vpc_route_table_ids = toset(concat(local.four_tgw.vpc.private_route_table_ids, local.four_tgw.vpc.public_route_table_ids)) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /networking/mega_mesh/four_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | four_tgw_provider_region_check = { 4 | condition = contains([local.four_provider_region_name], local.four_tgw.region) 5 | error_message = "Centralized Router Four's region must match the aws.four provider alias region for Mega Mesh." 6 | } 7 | 8 | four_tgw_provider_account_id_check = { 9 | condition = contains([local.four_provider_account_id], local.four_tgw.account_id) 10 | error_message = "Centralized Router Four's account ID must match the aws.four provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /networking/mega_mesh/four_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # four 2 | resource "aws_ec2_transit_gateway_route" "this_four_tgw_routes_to_vpcs_in_one_tgw" { 3 | provider = aws.four 4 | 5 | for_each = local.one_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.four_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_one.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_four_tgw_routes_to_vpcs_in_two_tgw" { 13 | provider = aws.four 14 | 15 | for_each = local.two_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.four_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_two.id 20 | } 21 | 22 | resource "aws_ec2_transit_gateway_route" "this_four_tgw_routes_to_vpcs_in_three_tgw" { 23 | provider = aws.four 24 | 25 | for_each = local.three_tgw_vpc_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.four_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_three.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_four_tgw_routes_to_vpcs_in_five_tgw" { 33 | provider = aws.four 34 | 35 | for_each = local.five_tgw_vpc_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.four_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_four.id 40 | } 41 | 42 | resource "aws_ec2_transit_gateway_route" "this_four_tgw_routes_to_vpcs_in_six_tgw" { 43 | provider = aws.four 44 | 45 | for_each = local.six_tgw_vpc_network_cidrs 46 | 47 | transit_gateway_route_table_id = local.four_tgw.route_table_id 48 | destination_cidr_block = each.value 49 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_four.id 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_four_tgw_routes_to_vpcs_in_seven_tgw" { 53 | provider = aws.four 54 | 55 | for_each = local.seven_tgw_vpc_network_cidrs 56 | 57 | transit_gateway_route_table_id = local.four_tgw.route_table_id 58 | destination_cidr_block = each.value 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_four.id 60 | } 61 | 62 | resource "aws_ec2_transit_gateway_route" "this_four_tgw_routes_to_vpcs_in_eight_tgw" { 63 | provider = aws.four 64 | 65 | for_each = local.eight_tgw_vpc_network_cidrs 66 | 67 | transit_gateway_route_table_id = local.four_tgw.route_table_id 68 | destination_cidr_block = each.value 69 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_four.id 70 | } 71 | 72 | resource "aws_ec2_transit_gateway_route" "this_four_tgw_routes_to_vpcs_in_nine_tgw" { 73 | provider = aws.four 74 | 75 | for_each = local.nine_tgw_vpc_network_cidrs 76 | 77 | transit_gateway_route_table_id = local.four_tgw.route_table_id 78 | destination_cidr_block = each.value 79 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_four.id 80 | } 81 | 82 | resource "aws_ec2_transit_gateway_route" "this_four_tgw_routes_to_vpcs_in_ten_tgw" { 83 | provider = aws.four 84 | 85 | for_each = local.ten_tgw_vpc_network_cidrs 86 | 87 | transit_gateway_route_table_id = local.four_tgw.route_table_id 88 | destination_cidr_block = each.value 89 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_four.id 90 | } 91 | 92 | -------------------------------------------------------------------------------- /networking/mega_mesh/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * # Mega Mesh 3 | * Mega Mesh == (Full Mesh Trio)² + 1 4 | * Full Mesh Transit Gateway across 10 regions. 5 | * [Demo](https://github.com/JudeQuintana/terraform-main/tree/main/mega_mesh_demo) 6 | * 7 | * ![mega-mesh](https://jq1-io.s3.amazonaws.com/mega-mesh/ten-full-mesh-tgw.png) 8 | * 9 | * ``` 10 | * module "mega_mesh" { 11 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/mega_mesh?ref=v1.8.0" 12 | * 13 | * providers = { 14 | * aws.one = aws.use1 15 | * aws.two = aws.usw1 16 | * aws.three = aws.euc1 17 | * aws.four = aws.euw1 18 | * aws.five = aws.apne1 19 | * aws.six = aws.apse1 20 | * aws.seven = aws.cac1 21 | * aws.eight = aws.sae1 22 | * aws.nine = aws.use2 23 | * aws.ten = aws.usw2 24 | * } 25 | * 26 | * env_prefix = var.env_prefix 27 | * mega_mesh = { 28 | * one = { 29 | * centralized_router = module.centralized_router_use1 30 | * } 31 | * two = { 32 | * centralized_router = module.centralized_router_usw1 33 | * } 34 | * three = { 35 | * centralized_router = module.centralized_router_euc1 36 | * } 37 | * four = { 38 | * centralized_router = module.centralized_router_euw1 39 | * } 40 | * five = { 41 | * centralized_router = module.centralized_router_apne1 42 | * } 43 | * six = { 44 | * centralized_router = module.centralized_router_apse1 45 | * } 46 | * seven = { 47 | * centralized_router = module.centralized_router_cac1 48 | * } 49 | * eight = { 50 | * centralized_router = module.centralized_router_sae1 51 | * } 52 | * nine = { 53 | * centralized_router = module.centralized_router_use2 54 | * } 55 | * ten = { 56 | * centralized_router = module.centralized_router_usw2 57 | * } 58 | * } 59 | * } 60 | * 61 | * output "mega_mesh" { 62 | * value = module.mega_mesh 63 | * } 64 | * ``` 65 | */ 66 | -------------------------------------------------------------------------------- /networking/mega_mesh/nine_associations.tf: -------------------------------------------------------------------------------- 1 | # nine 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_nine_to_this_one" { 3 | provider = aws.nine 4 | 5 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_one.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_nine_to_this_two" { 10 | provider = aws.nine 11 | 12 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_two.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_nine_to_this_three" { 17 | provider = aws.nine 18 | 19 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_three.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_nine_to_this_four" { 24 | provider = aws.nine 25 | 26 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_four.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_nine_to_this_five" { 31 | provider = aws.nine 32 | 33 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_five.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_nine_to_this_six" { 38 | provider = aws.nine 39 | 40 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_six.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_nine_to_this_seven" { 45 | provider = aws.nine 46 | 47 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_seven.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_nine_to_this_eight" { 52 | provider = aws.nine 53 | 54 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_eight.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_nine_to_this_ten" { 59 | provider = aws.nine 60 | 61 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_nine.id 63 | } 64 | 65 | -------------------------------------------------------------------------------- /networking/mega_mesh/nine_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_nine" { 2 | provider = aws.nine 3 | } 4 | 5 | data "aws_region" "this_nine" { 6 | provider = aws.nine 7 | } 8 | 9 | locals { 10 | nine_provider_account_id = data.aws_caller_identity.this_nine.account_id 11 | nine_provider_region_name = data.aws_region.this_nine.name 12 | 13 | nine_tgw = var.mega_mesh.nine.centralized_router 14 | nine_tgw_vpc_network_cidrs = toset(local.nine_tgw.vpc.network_cidrs) 15 | nine_tgw_vpc_route_table_ids = toset(concat(local.nine_tgw.vpc.private_route_table_ids, local.nine_tgw.vpc.public_route_table_ids)) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /networking/mega_mesh/nine_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | nine_tgw_provider_region_check = { 4 | condition = contains([local.nine_provider_region_name], local.nine_tgw.region) 5 | error_message = "Centralized Router Nine's region must match the aws.nine provider alias region for Mega Mesh." 6 | } 7 | 8 | nine_tgw_provider_account_id_check = { 9 | condition = contains([local.nine_provider_account_id], local.nine_tgw.account_id) 10 | error_message = "Centralized Router Nine's account ID must match the aws.nine provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /networking/mega_mesh/nine_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # nine 2 | resource "aws_ec2_transit_gateway_route" "this_nine_tgw_routes_to_vpcs_in_one_tgw" { 3 | provider = aws.nine 4 | 5 | for_each = local.one_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_one.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_nine_tgw_routes_to_vpcs_in_two_tgw" { 13 | provider = aws.nine 14 | 15 | for_each = local.two_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_two.id 20 | } 21 | 22 | resource "aws_ec2_transit_gateway_route" "this_nine_tgw_routes_to_vpcs_in_three_tgw" { 23 | provider = aws.nine 24 | 25 | for_each = local.three_tgw_vpc_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_three.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_nine_tgw_routes_to_vpcs_in_four_tgw" { 33 | provider = aws.nine 34 | 35 | for_each = local.four_tgw_vpc_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_four.id 40 | } 41 | 42 | resource "aws_ec2_transit_gateway_route" "this_nine_tgw_routes_to_vpcs_in_five_tgw" { 43 | provider = aws.nine 44 | 45 | for_each = local.five_tgw_vpc_network_cidrs 46 | 47 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 48 | destination_cidr_block = each.value 49 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_five.id 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_nine_tgw_routes_to_vpcs_in_six_tgw" { 53 | provider = aws.nine 54 | 55 | for_each = local.six_tgw_vpc_network_cidrs 56 | 57 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 58 | destination_cidr_block = each.value 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_six.id 60 | } 61 | 62 | resource "aws_ec2_transit_gateway_route" "this_nine_tgw_routes_to_vpcs_in_seven_tgw" { 63 | provider = aws.nine 64 | 65 | for_each = local.seven_tgw_vpc_network_cidrs 66 | 67 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 68 | destination_cidr_block = each.value 69 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_seven.id 70 | } 71 | 72 | resource "aws_ec2_transit_gateway_route" "this_nine_tgw_routes_to_vpcs_in_eight_tgw" { 73 | provider = aws.nine 74 | 75 | for_each = local.eight_tgw_vpc_network_cidrs 76 | 77 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 78 | destination_cidr_block = each.value 79 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_eight.id 80 | } 81 | 82 | resource "aws_ec2_transit_gateway_route" "this_nine_tgw_routes_to_vpcs_in_ten_tgw" { 83 | provider = aws.nine 84 | 85 | for_each = local.ten_tgw_vpc_network_cidrs 86 | 87 | transit_gateway_route_table_id = local.nine_tgw.route_table_id 88 | destination_cidr_block = each.value 89 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_nine.id 90 | } 91 | 92 | -------------------------------------------------------------------------------- /networking/mega_mesh/one_associations.tf: -------------------------------------------------------------------------------- 1 | # one 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_two" { 3 | provider = aws.one 4 | 5 | transit_gateway_route_table_id = local.one_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_three" { 10 | provider = aws.one 11 | 12 | transit_gateway_route_table_id = local.one_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_four" { 17 | provider = aws.one 18 | 19 | transit_gateway_route_table_id = local.one_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_one.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_five" { 24 | provider = aws.one 25 | 26 | transit_gateway_route_table_id = local.one_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_one.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_six" { 31 | provider = aws.one 32 | 33 | transit_gateway_route_table_id = local.one_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_one.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_seven" { 38 | provider = aws.one 39 | 40 | transit_gateway_route_table_id = local.one_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_one.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_eight" { 45 | provider = aws.one 46 | 47 | transit_gateway_route_table_id = local.one_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_one.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_nine" { 52 | provider = aws.one 53 | 54 | transit_gateway_route_table_id = local.one_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_one.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_one_to_this_ten" { 59 | provider = aws.one 60 | 61 | transit_gateway_route_table_id = local.one_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_one.id 63 | } 64 | 65 | -------------------------------------------------------------------------------- /networking/mega_mesh/one_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_one" { 2 | provider = aws.one 3 | } 4 | 5 | data "aws_region" "this_one" { 6 | provider = aws.one 7 | } 8 | 9 | locals { 10 | one_provider_account_id = data.aws_caller_identity.this_one.account_id 11 | one_provider_region_name = data.aws_region.this_one.name 12 | 13 | one_tgw = var.mega_mesh.one.centralized_router 14 | one_tgw_vpc_network_cidrs = toset(local.one_tgw.vpc.network_cidrs) 15 | one_tgw_vpc_route_table_ids = toset(concat(local.one_tgw.vpc.private_route_table_ids, local.one_tgw.vpc.public_route_table_ids)) 16 | } 17 | -------------------------------------------------------------------------------- /networking/mega_mesh/one_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | one_tgw_provider_region_check = { 4 | condition = contains([local.one_provider_region_name], local.one_tgw.region) 5 | error_message = "Centralized Router One's region must match the aws.one provider alias region for Mega Mesh." 6 | } 7 | 8 | one_tgw_provider_account_id_check = { 9 | condition = contains([local.one_provider_account_id], local.one_tgw.account_id) 10 | error_message = "Centralized Router One's account ID must match the aws.one provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /networking/mega_mesh/one_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # one 2 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_two_tgw" { 3 | provider = aws.one 4 | 5 | for_each = local.two_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.one_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_three_tgw" { 13 | provider = aws.one 14 | 15 | for_each = local.three_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.one_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 20 | } 21 | 22 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_four_tgw" { 23 | provider = aws.one 24 | 25 | for_each = local.four_tgw_vpc_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.one_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_one.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_five_tgw" { 33 | provider = aws.one 34 | 35 | for_each = local.five_tgw_vpc_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.one_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_one.id 40 | } 41 | 42 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_six_tgw" { 43 | provider = aws.one 44 | 45 | for_each = local.six_tgw_vpc_network_cidrs 46 | 47 | transit_gateway_route_table_id = local.one_tgw.route_table_id 48 | destination_cidr_block = each.value 49 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_one.id 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_seven_tgw" { 53 | provider = aws.one 54 | 55 | for_each = local.seven_tgw_vpc_network_cidrs 56 | 57 | transit_gateway_route_table_id = local.one_tgw.route_table_id 58 | destination_cidr_block = each.value 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_one.id 60 | } 61 | 62 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_eight_tgw" { 63 | provider = aws.one 64 | 65 | for_each = local.eight_tgw_vpc_network_cidrs 66 | 67 | transit_gateway_route_table_id = local.one_tgw.route_table_id 68 | destination_cidr_block = each.value 69 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_one.id 70 | } 71 | 72 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_nine_tgw" { 73 | provider = aws.one 74 | 75 | for_each = local.nine_tgw_vpc_network_cidrs 76 | 77 | transit_gateway_route_table_id = local.one_tgw.route_table_id 78 | destination_cidr_block = each.value 79 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_one.id 80 | } 81 | 82 | resource "aws_ec2_transit_gateway_route" "this_one_tgw_routes_to_vpcs_in_ten_tgw" { 83 | provider = aws.one 84 | 85 | for_each = local.ten_tgw_vpc_network_cidrs 86 | 87 | transit_gateway_route_table_id = local.one_tgw.route_table_id 88 | destination_cidr_block = each.value 89 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_one.id 90 | } 91 | 92 | -------------------------------------------------------------------------------- /networking/mega_mesh/seven_associations.tf: -------------------------------------------------------------------------------- 1 | # seven 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_seven_to_this_one" { 3 | provider = aws.seven 4 | 5 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_one.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_seven_to_this_two" { 10 | provider = aws.seven 11 | 12 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_two.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_seven_to_this_three" { 17 | provider = aws.seven 18 | 19 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_three.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_seven_to_this_four" { 24 | provider = aws.seven 25 | 26 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_four.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_seven_to_this_five" { 31 | provider = aws.seven 32 | 33 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_five.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_seven_to_this_six" { 38 | provider = aws.seven 39 | 40 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_six.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_seven_to_this_eight" { 45 | provider = aws.seven 46 | 47 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_seven.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_seven_to_this_nine" { 52 | provider = aws.seven 53 | 54 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_seven.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_seven_to_this_ten" { 59 | provider = aws.seven 60 | 61 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_seven.id 63 | } 64 | 65 | -------------------------------------------------------------------------------- /networking/mega_mesh/seven_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_seven" { 2 | provider = aws.seven 3 | } 4 | 5 | data "aws_region" "this_seven" { 6 | provider = aws.seven 7 | } 8 | 9 | locals { 10 | seven_provider_account_id = data.aws_caller_identity.this_seven.account_id 11 | seven_provider_region_name = data.aws_region.this_seven.name 12 | 13 | seven_tgw = var.mega_mesh.seven.centralized_router 14 | seven_tgw_vpc_network_cidrs = toset(local.seven_tgw.vpc.network_cidrs) 15 | seven_tgw_vpc_route_table_ids = toset(concat(local.seven_tgw.vpc.private_route_table_ids, local.seven_tgw.vpc.public_route_table_ids)) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /networking/mega_mesh/seven_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | seven_tgw_provider_region_check = { 4 | condition = contains([local.seven_provider_region_name], local.seven_tgw.region) 5 | error_message = "Centralized Router Seven's region must match the aws.seven provider alias region for Mega Mesh." 6 | } 7 | 8 | seven_tgw_provider_account_id_check = { 9 | condition = contains([local.seven_provider_account_id], local.seven_tgw.account_id) 10 | error_message = "Centralized Router Seven's account ID must match the aws.seven provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /networking/mega_mesh/seven_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # seven 2 | resource "aws_ec2_transit_gateway_route" "this_seven_tgw_routes_to_vpcs_in_one_tgw" { 3 | provider = aws.seven 4 | 5 | for_each = local.one_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_one.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_seven_tgw_routes_to_vpcs_in_two_tgw" { 13 | provider = aws.seven 14 | 15 | for_each = local.two_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_two.id 20 | } 21 | 22 | resource "aws_ec2_transit_gateway_route" "this_seven_tgw_routes_to_vpcs_in_three_tgw" { 23 | provider = aws.seven 24 | 25 | for_each = local.three_tgw_vpc_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_three.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_seven_tgw_routes_to_vpcs_in_four_tgw" { 33 | provider = aws.seven 34 | 35 | for_each = local.four_tgw_vpc_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_four.id 40 | } 41 | 42 | resource "aws_ec2_transit_gateway_route" "this_seven_tgw_routes_to_vpcs_in_five_tgw" { 43 | provider = aws.seven 44 | 45 | for_each = local.five_tgw_vpc_network_cidrs 46 | 47 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 48 | destination_cidr_block = each.value 49 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_five.id 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_seven_tgw_routes_to_vpcs_in_six_tgw" { 53 | provider = aws.seven 54 | 55 | for_each = local.six_tgw_vpc_network_cidrs 56 | 57 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 58 | destination_cidr_block = each.value 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_six.id 60 | } 61 | 62 | resource "aws_ec2_transit_gateway_route" "this_seven_tgw_routes_to_vpcs_in_eight_tgw" { 63 | provider = aws.seven 64 | 65 | for_each = local.eight_tgw_vpc_network_cidrs 66 | 67 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 68 | destination_cidr_block = each.value 69 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_seven.id 70 | } 71 | 72 | resource "aws_ec2_transit_gateway_route" "this_seven_tgw_routes_to_vpcs_in_nine_tgw" { 73 | provider = aws.seven 74 | 75 | for_each = local.nine_tgw_vpc_network_cidrs 76 | 77 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 78 | destination_cidr_block = each.value 79 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_seven.id 80 | } 81 | 82 | resource "aws_ec2_transit_gateway_route" "this_seven_tgw_routes_to_vpcs_in_ten_tgw" { 83 | provider = aws.seven 84 | 85 | for_each = local.ten_tgw_vpc_network_cidrs 86 | 87 | transit_gateway_route_table_id = local.seven_tgw.route_table_id 88 | destination_cidr_block = each.value 89 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_seven.id 90 | } 91 | 92 | -------------------------------------------------------------------------------- /networking/mega_mesh/six_associations.tf: -------------------------------------------------------------------------------- 1 | # six 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_six_to_this_one" { 3 | provider = aws.six 4 | 5 | transit_gateway_route_table_id = local.six_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_one.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_six_to_this_two" { 10 | provider = aws.six 11 | 12 | transit_gateway_route_table_id = local.six_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_two.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_six_to_this_three" { 17 | provider = aws.six 18 | 19 | transit_gateway_route_table_id = local.six_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_three.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_six_to_this_four" { 24 | provider = aws.six 25 | 26 | transit_gateway_route_table_id = local.six_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_four.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_six_to_this_five" { 31 | provider = aws.six 32 | 33 | transit_gateway_route_table_id = local.six_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_five.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_six_to_this_seven" { 38 | provider = aws.six 39 | 40 | transit_gateway_route_table_id = local.six_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_six.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_six_to_this_eight" { 45 | provider = aws.six 46 | 47 | transit_gateway_route_table_id = local.six_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_six.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_six_to_this_nine" { 52 | provider = aws.six 53 | 54 | transit_gateway_route_table_id = local.six_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_six.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_six_to_this_ten" { 59 | provider = aws.six 60 | 61 | transit_gateway_route_table_id = local.six_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_six.id 63 | } 64 | -------------------------------------------------------------------------------- /networking/mega_mesh/six_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_six" { 2 | provider = aws.six 3 | } 4 | 5 | data "aws_region" "this_six" { 6 | provider = aws.six 7 | } 8 | 9 | locals { 10 | six_provider_account_id = data.aws_caller_identity.this_six.account_id 11 | six_provider_region_name = data.aws_region.this_six.name 12 | 13 | six_tgw = var.mega_mesh.six.centralized_router 14 | six_tgw_vpc_network_cidrs = toset(local.six_tgw.vpc.network_cidrs) 15 | six_tgw_vpc_route_table_ids = toset(concat(local.six_tgw.vpc.private_route_table_ids, local.six_tgw.vpc.public_route_table_ids)) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /networking/mega_mesh/six_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | six_tgw_provider_region_check = { 4 | condition = contains([local.six_provider_region_name], local.six_tgw.region) 5 | error_message = "Centralized Router Six's region must match the aws.six provider alias region for Mega Mesh." 6 | } 7 | 8 | six_tgw_provider_account_id_check = { 9 | condition = contains([local.six_provider_account_id], local.six_tgw.account_id) 10 | error_message = "Centralized Router Six's account ID must match the aws.six provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /networking/mega_mesh/six_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # six 2 | resource "aws_ec2_transit_gateway_route" "this_six_tgw_routes_to_vpcs_in_one_tgw" { 3 | provider = aws.six 4 | 5 | for_each = local.one_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.six_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_one.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_six_tgw_routes_to_vpcs_in_two_tgw" { 13 | provider = aws.six 14 | 15 | for_each = local.two_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.six_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_two.id 20 | } 21 | 22 | resource "aws_ec2_transit_gateway_route" "this_six_tgw_routes_to_vpcs_in_three_tgw" { 23 | provider = aws.six 24 | 25 | for_each = local.three_tgw_vpc_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.six_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_three.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_six_tgw_routes_to_vpcs_in_four_tgw" { 33 | provider = aws.six 34 | 35 | for_each = local.four_tgw_vpc_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.six_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_four.id 40 | } 41 | 42 | resource "aws_ec2_transit_gateway_route" "this_six_tgw_routes_to_vpcs_in_five_tgw" { 43 | provider = aws.six 44 | 45 | for_each = local.five_tgw_vpc_network_cidrs 46 | 47 | transit_gateway_route_table_id = local.six_tgw.route_table_id 48 | destination_cidr_block = each.value 49 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_five.id 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_six_tgw_routes_to_vpcs_in_seven_tgw" { 53 | provider = aws.six 54 | 55 | for_each = local.seven_tgw_vpc_network_cidrs 56 | 57 | transit_gateway_route_table_id = local.six_tgw.route_table_id 58 | destination_cidr_block = each.value 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_six.id 60 | } 61 | 62 | resource "aws_ec2_transit_gateway_route" "this_six_tgw_routes_to_vpcs_in_eight_tgw" { 63 | provider = aws.six 64 | 65 | for_each = local.eight_tgw_vpc_network_cidrs 66 | 67 | transit_gateway_route_table_id = local.six_tgw.route_table_id 68 | destination_cidr_block = each.value 69 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_six.id 70 | } 71 | 72 | resource "aws_ec2_transit_gateway_route" "this_six_tgw_routes_to_vpcs_in_nine_tgw" { 73 | provider = aws.six 74 | 75 | for_each = local.nine_tgw_vpc_network_cidrs 76 | 77 | transit_gateway_route_table_id = local.six_tgw.route_table_id 78 | destination_cidr_block = each.value 79 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_six.id 80 | } 81 | 82 | resource "aws_ec2_transit_gateway_route" "this_six_tgw_routes_to_vpcs_in_ten_tgw" { 83 | provider = aws.six 84 | 85 | for_each = local.ten_tgw_vpc_network_cidrs 86 | 87 | transit_gateway_route_table_id = local.six_tgw.route_table_id 88 | destination_cidr_block = each.value 89 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_six.id 90 | } 91 | 92 | -------------------------------------------------------------------------------- /networking/mega_mesh/ten_associations.tf: -------------------------------------------------------------------------------- 1 | # ten 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_ten_to_this_one" { 3 | provider = aws.ten 4 | 5 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_one.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_ten_to_this_two" { 10 | provider = aws.ten 11 | 12 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_two.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_ten_to_this_three" { 17 | provider = aws.ten 18 | 19 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_three.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_ten_to_this_four" { 24 | provider = aws.ten 25 | 26 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_four.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_ten_to_this_five" { 31 | provider = aws.ten 32 | 33 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_five.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_ten_to_this_six" { 38 | provider = aws.ten 39 | 40 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_six.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_ten_to_this_seven" { 45 | provider = aws.ten 46 | 47 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_seven.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_ten_to_this_eight" { 52 | provider = aws.ten 53 | 54 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_eight.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_ten_to_this_nine" { 59 | provider = aws.ten 60 | 61 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_nine.id 63 | } 64 | 65 | -------------------------------------------------------------------------------- /networking/mega_mesh/ten_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_ten" { 2 | provider = aws.ten 3 | } 4 | 5 | data "aws_region" "this_ten" { 6 | provider = aws.ten 7 | } 8 | 9 | locals { 10 | ten_provider_account_id = data.aws_caller_identity.this_ten.account_id 11 | ten_provider_region_name = data.aws_region.this_ten.name 12 | 13 | ten_tgw = var.mega_mesh.ten.centralized_router 14 | ten_tgw_vpc_network_cidrs = toset(local.ten_tgw.vpc.network_cidrs) 15 | ten_tgw_vpc_route_table_ids = toset(concat(local.ten_tgw.vpc.private_route_table_ids, local.ten_tgw.vpc.public_route_table_ids)) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /networking/mega_mesh/ten_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | ten_tgw_provider_region_check = { 4 | condition = contains([local.ten_provider_region_name], local.ten_tgw.region) 5 | error_message = "Centralized Router Ten's region must match the aws.ten provider alias region for Mega Mesh." 6 | } 7 | 8 | ten_tgw_provider_account_id_check = { 9 | condition = contains([local.ten_provider_account_id], local.ten_tgw.account_id) 10 | error_message = "Centralized Router Ten's account ID must match the aws.ten provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /networking/mega_mesh/ten_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # ten 2 | resource "aws_ec2_transit_gateway_route" "this_ten_tgw_routes_to_vpcs_in_one_tgw" { 3 | provider = aws.ten 4 | 5 | for_each = local.one_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_one.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_ten_tgw_routes_to_vpcs_in_two_tgw" { 13 | provider = aws.ten 14 | 15 | for_each = local.two_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_two.id 20 | } 21 | 22 | resource "aws_ec2_transit_gateway_route" "this_ten_tgw_routes_to_vpcs_in_three_tgw" { 23 | provider = aws.ten 24 | 25 | for_each = local.three_tgw_vpc_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_three.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_ten_tgw_routes_to_vpcs_in_four_tgw" { 33 | provider = aws.ten 34 | 35 | for_each = local.four_tgw_vpc_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_four.id 40 | } 41 | 42 | resource "aws_ec2_transit_gateway_route" "this_ten_tgw_routes_to_vpcs_in_five_tgw" { 43 | provider = aws.ten 44 | 45 | for_each = local.five_tgw_vpc_network_cidrs 46 | 47 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 48 | destination_cidr_block = each.value 49 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_five.id 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_ten_tgw_routes_to_vpcs_in_six_tgw" { 53 | provider = aws.ten 54 | 55 | for_each = local.six_tgw_vpc_network_cidrs 56 | 57 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 58 | destination_cidr_block = each.value 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_six.id 60 | } 61 | 62 | resource "aws_ec2_transit_gateway_route" "this_ten_tgw_routes_to_vpcs_in_seven_tgw" { 63 | provider = aws.ten 64 | 65 | for_each = local.seven_tgw_vpc_network_cidrs 66 | 67 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 68 | destination_cidr_block = each.value 69 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_seven.id 70 | } 71 | 72 | resource "aws_ec2_transit_gateway_route" "this_ten_tgw_routes_to_vpcs_in_eight_tgw" { 73 | provider = aws.ten 74 | 75 | for_each = local.eight_tgw_vpc_network_cidrs 76 | 77 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 78 | destination_cidr_block = each.value 79 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_eight.id 80 | } 81 | 82 | resource "aws_ec2_transit_gateway_route" "this_ten_tgw_routes_to_vpcs_in_nine_tgw" { 83 | provider = aws.ten 84 | 85 | for_each = local.nine_tgw_vpc_network_cidrs 86 | 87 | transit_gateway_route_table_id = local.ten_tgw.route_table_id 88 | destination_cidr_block = each.value 89 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_nine.id 90 | } 91 | 92 | -------------------------------------------------------------------------------- /networking/mega_mesh/three_associations.tf: -------------------------------------------------------------------------------- 1 | # three 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_one" { 3 | provider = aws.three 4 | 5 | transit_gateway_route_table_id = local.three_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_two" { 10 | provider = aws.three 11 | 12 | transit_gateway_route_table_id = local.three_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_four" { 17 | provider = aws.three 18 | 19 | transit_gateway_route_table_id = local.three_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_three.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_five" { 24 | provider = aws.three 25 | 26 | transit_gateway_route_table_id = local.three_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_three.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_six" { 31 | provider = aws.three 32 | 33 | transit_gateway_route_table_id = local.three_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_three.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_seven" { 38 | provider = aws.three 39 | 40 | transit_gateway_route_table_id = local.three_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_three.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_eight" { 45 | provider = aws.three 46 | 47 | transit_gateway_route_table_id = local.three_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_three.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_nine" { 52 | provider = aws.three 53 | 54 | transit_gateway_route_table_id = local.three_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_three.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_three_to_this_ten" { 59 | provider = aws.three 60 | 61 | transit_gateway_route_table_id = local.three_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_three.id 63 | } 64 | 65 | -------------------------------------------------------------------------------- /networking/mega_mesh/three_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_three" { 2 | provider = aws.three 3 | } 4 | 5 | data "aws_region" "this_three" { 6 | provider = aws.three 7 | } 8 | 9 | locals { 10 | three_provider_account_id = data.aws_caller_identity.this_three.account_id 11 | three_provider_region_name = data.aws_region.this_three.name 12 | 13 | three_tgw = var.mega_mesh.three.centralized_router 14 | three_tgw_vpc_network_cidrs = toset(local.three_tgw.vpc.network_cidrs) 15 | three_tgw_vpc_route_table_ids = toset(concat(local.three_tgw.vpc.private_route_table_ids, local.three_tgw.vpc.public_route_table_ids)) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /networking/mega_mesh/three_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | three_tgw_provider_region_check = { 4 | condition = contains([local.three_provider_region_name], local.three_tgw.region) 5 | error_message = "Centralized Router Three's region must match the aws.three provider alias region for Mega Mesh." 6 | } 7 | 8 | three_tgw_provider_account_id_check = { 9 | condition = contains([local.three_provider_account_id], local.three_tgw.account_id) 10 | error_message = "Centralized Router Three's account ID must match the aws.three provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /networking/mega_mesh/three_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # three 2 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_one_tgw" { 3 | provider = aws.three 4 | 5 | for_each = local.one_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.three_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_three_to_this_one.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_two_tgw" { 13 | provider = aws.three 14 | 15 | for_each = local.two_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.three_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 20 | } 21 | 22 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_four_tgw" { 23 | provider = aws.three 24 | 25 | for_each = local.four_tgw_vpc_network_cidrs 26 | 27 | transit_gateway_route_table_id = local.three_tgw.route_table_id 28 | destination_cidr_block = each.value 29 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_three.id 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_five_tgw" { 33 | provider = aws.three 34 | 35 | for_each = local.five_tgw_vpc_network_cidrs 36 | 37 | transit_gateway_route_table_id = local.three_tgw.route_table_id 38 | destination_cidr_block = each.value 39 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_three.id 40 | } 41 | 42 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_six_tgw" { 43 | provider = aws.three 44 | 45 | for_each = local.six_tgw_vpc_network_cidrs 46 | 47 | transit_gateway_route_table_id = local.three_tgw.route_table_id 48 | destination_cidr_block = each.value 49 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_three.id 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_seven_tgw" { 53 | provider = aws.three 54 | 55 | for_each = local.seven_tgw_vpc_network_cidrs 56 | 57 | transit_gateway_route_table_id = local.three_tgw.route_table_id 58 | destination_cidr_block = each.value 59 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_three.id 60 | } 61 | 62 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_eight_tgw" { 63 | provider = aws.three 64 | 65 | for_each = local.eight_tgw_vpc_network_cidrs 66 | 67 | transit_gateway_route_table_id = local.three_tgw.route_table_id 68 | destination_cidr_block = each.value 69 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_three.id 70 | } 71 | 72 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_nine_tgw" { 73 | provider = aws.three 74 | 75 | for_each = local.nine_tgw_vpc_network_cidrs 76 | 77 | transit_gateway_route_table_id = local.three_tgw.route_table_id 78 | destination_cidr_block = each.value 79 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_three.id 80 | } 81 | 82 | resource "aws_ec2_transit_gateway_route" "this_three_tgw_routes_to_vpcs_in_ten_tgw" { 83 | provider = aws.three 84 | 85 | for_each = local.ten_tgw_vpc_network_cidrs 86 | 87 | transit_gateway_route_table_id = local.three_tgw.route_table_id 88 | destination_cidr_block = each.value 89 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_three.id 90 | } 91 | 92 | -------------------------------------------------------------------------------- /networking/mega_mesh/two_associations.tf: -------------------------------------------------------------------------------- 1 | # two 2 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_one" { 3 | provider = aws.two 4 | 5 | transit_gateway_route_table_id = local.two_tgw.route_table_id 6 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 7 | } 8 | 9 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_three" { 10 | provider = aws.two 11 | 12 | transit_gateway_route_table_id = local.two_tgw.route_table_id 13 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 14 | } 15 | 16 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_four" { 17 | provider = aws.two 18 | 19 | transit_gateway_route_table_id = local.two_tgw.route_table_id 20 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_two.id 21 | } 22 | 23 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_five" { 24 | provider = aws.two 25 | 26 | transit_gateway_route_table_id = local.two_tgw.route_table_id 27 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_two.id 28 | } 29 | 30 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_six" { 31 | provider = aws.two 32 | 33 | transit_gateway_route_table_id = local.two_tgw.route_table_id 34 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_two.id 35 | } 36 | 37 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_seven" { 38 | provider = aws.two 39 | 40 | transit_gateway_route_table_id = local.two_tgw.route_table_id 41 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_two.id 42 | } 43 | 44 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_eight" { 45 | provider = aws.two 46 | 47 | transit_gateway_route_table_id = local.two_tgw.route_table_id 48 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_two.id 49 | } 50 | 51 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_nine" { 52 | provider = aws.two 53 | 54 | transit_gateway_route_table_id = local.two_tgw.route_table_id 55 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_two.id 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route_table_association" "this_two_to_this_ten" { 59 | provider = aws.two 60 | 61 | transit_gateway_route_table_id = local.two_tgw.route_table_id 62 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_two.id 63 | } 64 | 65 | -------------------------------------------------------------------------------- /networking/mega_mesh/two_base.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this_two" { 2 | provider = aws.two 3 | } 4 | 5 | data "aws_region" "this_two" { 6 | provider = aws.two 7 | } 8 | 9 | locals { 10 | two_provider_account_id = data.aws_caller_identity.this_two.account_id 11 | two_provider_region_name = data.aws_region.this_two.name 12 | 13 | two_tgw = var.mega_mesh.two.centralized_router 14 | two_tgw_vpc_network_cidrs = toset(local.two_tgw.vpc.network_cidrs) 15 | two_tgw_vpc_route_table_ids = toset(concat(local.two_tgw.vpc.private_route_table_ids, local.two_tgw.vpc.public_route_table_ids)) 16 | } 17 | -------------------------------------------------------------------------------- /networking/mega_mesh/two_preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the centralized routers match their relative provider's region and account id before created peering attachments 3 | two_tgw_provider_region_check = { 4 | condition = contains([local.two_provider_region_name], local.two_tgw.region) 5 | error_message = "Centralized Router Two's region must match the aws.two provider alias region for Mega Mesh." 6 | } 7 | 8 | two_tgw_provider_account_id_check = { 9 | condition = contains([local.two_provider_account_id], local.two_tgw.account_id) 10 | error_message = "Centralized Router Two's account ID must match the aws.two provider alias account ID for Mega Mesh." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /networking/mega_mesh/two_tgw_routes.tf: -------------------------------------------------------------------------------- 1 | # two 2 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_one_tgw" { 3 | provider = aws.two 4 | 5 | for_each = local.one_tgw_vpc_network_cidrs 6 | 7 | transit_gateway_route_table_id = local.two_tgw.route_table_id 8 | destination_cidr_block = each.value 9 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_one_to_this_two.id 10 | } 11 | 12 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_three_tgw" { 13 | provider = aws.two 14 | 15 | for_each = local.three_tgw_vpc_network_cidrs 16 | 17 | transit_gateway_route_table_id = local.two_tgw.route_table_id 18 | destination_cidr_block = each.value 19 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_two_to_this_three.id 20 | } 21 | 22 | 23 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_four_tgw" { 24 | provider = aws.two 25 | 26 | for_each = local.four_tgw_vpc_network_cidrs 27 | 28 | transit_gateway_route_table_id = local.two_tgw.route_table_id 29 | destination_cidr_block = each.value 30 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_four_to_this_two.id 31 | } 32 | 33 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_five_tgw" { 34 | provider = aws.two 35 | 36 | for_each = local.five_tgw_vpc_network_cidrs 37 | 38 | transit_gateway_route_table_id = local.two_tgw.route_table_id 39 | destination_cidr_block = each.value 40 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_five_to_this_two.id 41 | } 42 | 43 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_six_tgw" { 44 | provider = aws.two 45 | 46 | for_each = local.six_tgw_vpc_network_cidrs 47 | 48 | transit_gateway_route_table_id = local.two_tgw.route_table_id 49 | destination_cidr_block = each.value 50 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_six_to_this_two.id 51 | } 52 | 53 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_seven_tgw" { 54 | provider = aws.two 55 | 56 | for_each = local.seven_tgw_vpc_network_cidrs 57 | 58 | transit_gateway_route_table_id = local.two_tgw.route_table_id 59 | destination_cidr_block = each.value 60 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_seven_to_this_two.id 61 | } 62 | 63 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_eight_tgw" { 64 | provider = aws.two 65 | 66 | for_each = local.eight_tgw_vpc_network_cidrs 67 | 68 | transit_gateway_route_table_id = local.two_tgw.route_table_id 69 | destination_cidr_block = each.value 70 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_eight_to_this_two.id 71 | } 72 | 73 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_nine_tgw" { 74 | provider = aws.two 75 | 76 | for_each = local.nine_tgw_vpc_network_cidrs 77 | 78 | transit_gateway_route_table_id = local.two_tgw.route_table_id 79 | destination_cidr_block = each.value 80 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_nine_to_this_two.id 81 | } 82 | 83 | resource "aws_ec2_transit_gateway_route" "this_two_tgw_routes_to_vpcs_in_ten_tgw" { 84 | provider = aws.two 85 | 86 | for_each = local.ten_tgw_vpc_network_cidrs 87 | 88 | transit_gateway_route_table_id = local.two_tgw.route_table_id 89 | destination_cidr_block = each.value 90 | transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment_accepter.this_ten_to_this_two.id 91 | } 92 | 93 | -------------------------------------------------------------------------------- /networking/mega_mesh/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=4.20" 7 | configuration_aliases = [aws.one, aws.two, aws.three, aws.four, aws.five, aws.six, aws.seven, aws.eight, aws.nine, aws.ten] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /networking/super_intra_vpc_security_group_rules/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * # Super Intra VPC Secuity Group Rules Description 3 | * - This allowing inbound protocols across regions based on rules (ie ssh, icmp, etc) that 4 | * were used in each intra_vpc_security_group_rules modules for all vpcs in each region. 5 | * - Rule sets for local and peer should be the same. also enforce by validation 6 | * 7 | * - See [security_group_rules.tf](https://github.com/JudeQuintana/terraform-main/blob/main/super_router_demo/security_group_rules.tf) in the [Super Router Demo](https://github.com/JudeQuintana/terraform-main/tree/main/super_router_demo). 8 | * 9 | * Example: 10 | * ``` 11 | * module "super_intra_vpc_security_group_rules_usw2_to_use1" { 12 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/super_intra_vpc_security_group_rules?ref=v1.7.5" 13 | * 14 | * providers = { 15 | * aws.local = aws.usw2 16 | * aws.peer = aws.use1 17 | * } 18 | * 19 | * env_prefix = var.env_prefix 20 | * region_az_labels = var.region_az_labels 21 | * super_intra_vpc_security_group_rules = { 22 | * local = { 23 | * intra_vpc_security_group_rules = module.intra_vpc_security_group_rules_usw2 24 | * } 25 | * peer = { 26 | * intra_vpc_security_group_rules = module.intra_vpc_security_group_rules_use1 27 | * } 28 | * } 29 | * } 30 | * ``` 31 | * 32 | */ 33 | -------------------------------------------------------------------------------- /networking/super_intra_vpc_security_group_rules/outputs.tf: -------------------------------------------------------------------------------- 1 | output "local" { 2 | value = { 3 | account_id = local.local_account_id 4 | region = local.local_region_name 5 | rules = [for this in local.local_vpc_id_and_rule_to_peer_intra_vpc_security_group_rule : this] 6 | } 7 | } 8 | 9 | output "peer" { 10 | value = { 11 | account_id = local.peer_account_id 12 | region = local.peer_region_name 13 | rules = [for this in local.peer_vpc_id_and_rule_to_local_intra_vpc_security_group_rule : this] 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /networking/super_intra_vpc_security_group_rules/preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # used on both aws_security_group_rule.this_local and aws_security_group_rule.this_peer 3 | # guarantee the centralized routers match their relative provider's region. 4 | local_provider_to_local_intra_vpc_security_group_rules_region_check = { 5 | condition = alltrue([ 6 | for this in var.super_intra_vpc_security_group_rules.local.intra_vpc_security_group_rules : 7 | contains([local.local_region_name], this.region) 8 | ]) 9 | error_message = "All local Intra VPC Security Group Rule's regions must match the aws.local provider alias region for Super Intra VPC Security Group Rules." 10 | } 11 | 12 | local_provider_to_local_intra_vpc_security_group_rules_account_id_check = { 13 | condition = alltrue([ 14 | for this in var.super_intra_vpc_security_group_rules.local.intra_vpc_security_group_rules : 15 | contains([local.local_account_id], this.account_id) 16 | ]) 17 | error_message = "All local Intra VPC Security Group Rule's account ID must match the aws.local provider alias account ID for Super Intra VPC Security Group Rules." 18 | } 19 | 20 | peer_provider_to_peer_intra_vpc_security_group_rules_region_check = { 21 | condition = alltrue([ 22 | for this in var.super_intra_vpc_security_group_rules.peer.intra_vpc_security_group_rules : 23 | contains([local.peer_region_name], this.region) 24 | ]) 25 | error_message = "All peer Intra VPC Security Group Rule's regions must match the aws.peer provider alias region for Super Intra VPC Security Group Rules." 26 | } 27 | 28 | peer_provider_to_peer_intra_vpc_security_group_rules_account_id_check = { 29 | condition = alltrue([ 30 | for this in var.super_intra_vpc_security_group_rules.peer.intra_vpc_security_group_rules : 31 | contains([local.peer_account_id], this.account_id) 32 | ]) 33 | error_message = "All peer Intra VPC Security Group Rule's account ID must match the aws.peer provider alias account ID for Super Intra VPC Security Group Rules." 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /networking/super_intra_vpc_security_group_rules/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=4.20" 7 | configuration_aliases = [aws.local, aws.peer] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /networking/tgw_super_router_for_tgw_centralized_router/blackhole_routes.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | blackhole_cidrs = toset(var.super_router.blackhole_cidrs) 3 | } 4 | 5 | resource "aws_ec2_transit_gateway_route" "this_local_blackholes" { 6 | provider = aws.local 7 | 8 | for_each = local.blackhole_cidrs 9 | 10 | destination_cidr_block = each.value 11 | blackhole = true 12 | transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this_local.id 13 | } 14 | 15 | resource "aws_ec2_transit_gateway_route" "this_peer_blackholes" { 16 | provider = aws.peer 17 | 18 | for_each = local.blackhole_cidrs 19 | 20 | destination_cidr_block = each.value 21 | blackhole = true 22 | transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this_peer.id 23 | } 24 | -------------------------------------------------------------------------------- /networking/tgw_super_router_for_tgw_centralized_router/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * # Super Router Description 3 | * This is a follow up to the [generating routes post](https://jq1.io/posts/generating_routes/). 4 | * 5 | * Original Blog Post: [Super Powered, Super Sharp, Super Router!](https://jq1.io/posts/super_router/) 6 | * 7 | * Fresh new decentralized design in [$init super refactor](https://jq1.io/posts/init_super_refactor/). 8 | * 9 | * New features means new steez in [Slappin chrome on the WIP'](https://jq1.io/posts/slappin_chrome_on_the_wip/)! 10 | * 11 | * Super Router provides both intra-region and cross-region peering and routing for Centralized Routers and Tiered VPCs (same AWS account only, no cross account). 12 | * 13 | * Super Router is composed of two TGWs instead of one TGW (one for each region). 14 | * 15 | * Example: 16 | * ``` 17 | * module "super_router_usw2_to_use1" { 18 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/tgw_super_router_for_tgw_centralized_router?ref=v1.7.5" 19 | * 20 | * providers = { 21 | * aws.local = aws.usw2 # local super router tgw will be built in the aws.local provider region 22 | * aws.peer = aws.use1 # peer super router tgw will be built in the aws.peer provider region 23 | * } 24 | * 25 | * env_prefix = var.env_prefix 26 | * region_az_labels = var.region_az_labels 27 | * super_router = { 28 | * name = "professor-x" 29 | * local = { 30 | * amazon_side_asn = 64521 31 | * centralized_routers = module.centralized_routers_usw2 32 | * } 33 | * peer = { 34 | * amazon_side_asn = 64522 35 | * centralized_routers = module.centralized_routers_use1 36 | * } 37 | * } 38 | * } 39 | * ``` 40 | * 41 | * The resulting architecture is a decentralized hub spoke topology: 42 | * ![super-router-shokunin](https://jq1-io.s3.amazonaws.com/super-router/super-router-shokunin.png) 43 | */ 44 | -------------------------------------------------------------------------------- /networking/tgw_super_router_for_tgw_centralized_router/outputs.tf: -------------------------------------------------------------------------------- 1 | output "name" { 2 | value = var.super_router.name 3 | } 4 | 5 | output "blackhole_cidrs" { 6 | value = local.blackhole_cidrs 7 | } 8 | 9 | output "local" { 10 | value = { 11 | account_id = local.local_account_id 12 | amazon_side_asn = var.super_router.local.amazon_side_asn 13 | full_name = local.local_super_router_name 14 | id = aws_ec2_transit_gateway.this_local.id 15 | network_cidrs = local.local_tgws_all_vpc_network_cidrs 16 | region = local.local_region_name 17 | route_table_id = aws_ec2_transit_gateway_route_table.this_local.id 18 | } 19 | } 20 | 21 | output "peer" { 22 | value = { 23 | account_id = local.peer_account_id 24 | amazon_side_asn = var.super_router.peer.amazon_side_asn 25 | full_name = local.peer_super_router_name 26 | id = aws_ec2_transit_gateway.this_peer.id 27 | network_cidrs = local.peer_tgws_all_vpc_network_cidrs 28 | region = local.peer_region_name 29 | route_table_id = aws_ec2_transit_gateway_route_table.this_peer.id 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /networking/tgw_super_router_for_tgw_centralized_router/preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # used on both aws_ec2_transit_gateway.this_lcoal and aws_ec2_transit_gateway.this_peer 3 | # guarantee the centralized routers match their relative provider's region. 4 | local_provider_to_local_tgws_region_check = { 5 | condition = alltrue([for this in local.local_tgws[*].region : contains([local.local_region_name], this)]) 6 | error_message = "All local Centralized Router regions must match the aws.local provider alias region for Super Router." 7 | } 8 | 9 | local_provider_to_local_tgws_account_id_check = { 10 | condition = alltrue([for this in local.local_tgws[*].account_id : contains([local.local_account_id], this)]) 11 | error_message = "All local Centralized Router account IDs must match the aws.local provider alias account ID for Super Router." 12 | } 13 | 14 | peer_provider_to_peer_tgws_region_check = { 15 | condition = alltrue([for this in local.peer_tgws[*].region : contains([local.peer_region_name], this)]) 16 | error_message = "All peer Centralized Router regions must match the aws.peer provider alias region for Super Router." 17 | } 18 | 19 | peer_provider_to_peer_tgws_account_id_check = { 20 | condition = alltrue([for this in local.peer_tgws[*].account_id : contains([local.peer_account_id], this)]) 21 | error_message = "All peer Centralized Router account IDs must match the aws.peer provider alias account ID for Super Router." 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /networking/tgw_super_router_for_tgw_centralized_router/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=4.20" 7 | configuration_aliases = [aws.local, aws.peer] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /networking/tiered_vpc/Readme.md: -------------------------------------------------------------------------------- 1 | ## This module is deprecated 2 | Please use [Tiered VPC-NG](https://github.com/JudeQuintana/terraform-modules/tree/master/networking/tiered_vpc_ng) instead! 3 | 4 | ## Blog Post 5 | Please see the [Tiered VPC in Terraform 6 | 0.13](https://jq1.io/posts/tiered_vpc) blog post for more 7 | details. 8 | 9 | ## Description 10 | Create VPC tiers. 11 | 12 | Requires a minimum of at least one public subnet. 13 | 14 | Private subnets can be nulled out. 15 | 16 | Can add and remove subnets and AZs at any time. 17 | 18 | Routing and structured naming for resource tagging is automatic. 19 | 20 | NAT Gateways (with EIP) are created per AZ for private subnets. 21 | 22 | All public and private subnets will have randomly generated name to differentiate each subnet. 23 | 24 | ## Usage 25 | ``` 26 | terraform { 27 | required_version = ">= 0.13" 28 | 29 | required_providers { 30 | aws = { 31 | source = "hashicorp/aws" 32 | version = "~> 3.0" 33 | } 34 | } 35 | } 36 | 37 | # default provider 38 | provider "aws" { 39 | region = "us-east-1" 40 | } 41 | 42 | provider "aws" { 43 | region = "us-west-2" 44 | alias = "usw2" 45 | } 46 | 47 | variable "env_prefix" { 48 | default = "test" 49 | } 50 | 51 | variable "region_az_labels" { 52 | type = map(string) 53 | 54 | default = { 55 | us-east-1 = "use1" 56 | us-east-1a = "use1a" 57 | us-east-1b = "use1b" 58 | us-east-2c = "use1c" 59 | us-west-2 = "usw2" 60 | us-west-2a = "usw2a" 61 | us-west-2b = "usw2b" 62 | us-west-2c = "usw2c" 63 | } 64 | } 65 | 66 | locals { 67 | tiers = [ 68 | { 69 | azs = { 70 | a = { 71 | private = ["10.0.8.0/24", "10.0.9.0/24"] 72 | public = ["10.0.0.0/24", "10.0.1.0/24"] 73 | }, 74 | b = { 75 | private = ["10.0.11.0/24", "10.0.12.0/24"] 76 | public = ["10.0.3.0/24", "10.0.4.0/24"] 77 | }, 78 | } 79 | name = "app" 80 | network = "10.0.0.0/20" 81 | }, 82 | { 83 | azs = { 84 | a = { 85 | private = ["10.0.16.0/24", "10.0.17.0/24"] 86 | public = ["10.0.28.0/28"] # 10.0.28.0/24 chopped up into /28 87 | }, 88 | b = { 89 | private = ["10.0.20.0/24", "10.0.21.0/24"] 90 | public = ["10.0.28.16/28"] # 10.0.28.0/24 chopped up into /28 91 | }, 92 | } 93 | name = "db" 94 | network = "10.0.16.0/20" 95 | }, 96 | { 97 | azs = { 98 | a = { 99 | private = ["10.47.11.0/24", "10.47.12.0/24"] 100 | public = ["10.47.0.0/28", "10.47.0.16/28"] # 10.47.0.0/24 chopped up into /28 101 | }, 102 | c = { 103 | private = null 104 | public = ["10.47.6.0/24", "10.47.7.0/24"] 105 | }, 106 | } 107 | name = "general" 108 | network = "10.47.0.0/20" 109 | } 110 | ] 111 | } 112 | 113 | module "usw2_vpcs" { 114 | source = "git@github.com:JudeQuintana/terraform-modules.git//networking/tiered_vpc?ref=v1.1.1" 115 | 116 | for_each = { for t in local.tiers : t.name => t } 117 | 118 | providers = { 119 | aws = aws.usw2 120 | } 121 | 122 | tier = each.value 123 | env_prefix = var.env_prefix 124 | region_az_labels = var.region_az_labels 125 | } 126 | 127 | ``` 128 | -------------------------------------------------------------------------------- /networking/tiered_vpc/main.tf: -------------------------------------------------------------------------------- 1 | # Pull region data from provider 2 | data "aws_region" "current" {} 3 | 4 | locals { 5 | region_name = data.aws_region.current.name 6 | region_label = lookup(var.region_az_labels, local.region_name) 7 | route_any_cidr = "0.0.0.0/0" 8 | 9 | # Set Environment tag since we have have var.env_prefix 10 | # add or override with var.tags 11 | default_tags = merge({ 12 | Environment = lower(var.env_prefix) 13 | }, var.tags) 14 | 15 | vpc_igw_name_tag = { 16 | Name = format("%s-%s-%s", upper(var.env_prefix), local.region_label, var.tier.name) 17 | } 18 | } 19 | 20 | ###################################################### 21 | # 22 | # Base VPC Setup: 23 | # - VPC 24 | # - IGW 25 | # 26 | ###################################################### 27 | 28 | resource "aws_vpc" "this" { 29 | cidr_block = var.tier.network 30 | instance_tenancy = var.vpc_tenancy 31 | enable_dns_support = true 32 | enable_dns_hostnames = true 33 | tags = merge( 34 | local.default_tags, 35 | local.vpc_igw_name_tag 36 | ) 37 | } 38 | 39 | resource "aws_internet_gateway" "this" { 40 | vpc_id = aws_vpc.this.id 41 | tags = merge( 42 | local.default_tags, 43 | local.vpc_igw_name_tag 44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /networking/tiered_vpc/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc" { 2 | value = { 3 | id = aws_vpc.this.id 4 | cidr = aws_vpc.this.cidr_block 5 | default_sg_id = aws_vpc.this.default_security_group_id 6 | igw_id = aws_internet_gateway.this.id 7 | } 8 | } 9 | 10 | locals { 11 | private_subnet_to_subnet_ids = { for subnet, this in aws_subnet.private : subnet => this.id } 12 | private_subnet_ids_per_az = { for subnet, subnet_id in local.private_subnet_to_subnet_ids : lookup(local.private_subnet_to_azs, subnet) => subnet_id... } # group subnet_id by AZ of subnet 13 | private_route_table_ids_per_az = { for az, route_table in aws_route_table.private : az => route_table.id } 14 | 15 | public_subnet_to_subnet_ids = { for subnet, this in aws_subnet.public : subnet => this.id } 16 | public_subnet_ids_per_az = { for subnet, subnet_id in local.public_subnet_to_subnet_ids : lookup(local.public_subnet_to_azs, subnet) => subnet_id... } # group subnet_id by AZ of subnet 17 | public_route_table_ids_per_az = { for az, subnet_id in local.public_subnet_ids_per_az : az => aws_route_table.public.id } # Each public subnet shares the same route table 18 | } 19 | 20 | output "public_subnet_ids" { 21 | value = local.public_subnet_ids_per_az 22 | } 23 | 24 | output "public_route_table_ids" { 25 | value = local.public_route_table_ids_per_az 26 | } 27 | 28 | output "private_subnet_ids" { 29 | value = local.private_subnet_ids_per_az 30 | } 31 | 32 | output "private_route_table_ids" { 33 | value = local.private_route_table_ids_per_az 34 | } 35 | 36 | locals { 37 | tier_bundle = { 38 | for az, acl in var.tier.azs : az => { 39 | private = acl.private != null ? acl.private : [] 40 | private_ids = lookup(local.private_subnet_ids_per_az, az, []) 41 | private_route_table_id = lookup(local.private_route_table_ids_per_az, az, null) 42 | public = acl.public 43 | public_ids = lookup(local.public_subnet_ids_per_az, az) 44 | public_route_table_id = lookup(local.public_route_table_ids_per_az, az) # no default because there will always be a public route table 45 | } 46 | } 47 | } 48 | 49 | output "tier_bundle" { 50 | value = local.tier_bundle 51 | } 52 | 53 | locals { 54 | tier_structured = { 55 | for az, acl in var.tier.azs : az => { 56 | private = [for subnet, subnet_id in local.private_subnet_to_subnet_ids : 57 | { 58 | subnet = subnet 59 | id = subnet_id 60 | } 61 | if lookup(local.private_subnet_to_azs, subnet) == az] 62 | private_route_table_id = lookup(local.private_route_table_ids_per_az, az, null) 63 | 64 | public = [for subnet, subnet_id in local.public_subnet_to_subnet_ids : 65 | { 66 | subnet = subnet 67 | id = subnet_id 68 | } 69 | if lookup(local.public_subnet_to_azs, subnet) == az] 70 | public_route_table_id = lookup(local.public_route_table_ids_per_az, az) 71 | } 72 | } 73 | } 74 | 75 | output "tier" { 76 | value = local.tier_structured 77 | } 78 | -------------------------------------------------------------------------------- /networking/tiered_vpc/public.tf: -------------------------------------------------------------------------------- 1 | ############################################################################################################ 2 | # 3 | # Public Subnets: 4 | # - It's required to have at least 1 public subnet in a tier 5 | # - Public Route Table and Route for all subnets 6 | # - Route out IGW 7 | # 8 | # Note: 9 | # lookup(var.region_az_labels, format("%s%s", local.region_name, lookup(local.public_subnet_to_azs, each.value))) 10 | # is building the public AZ name on the fly by looking the up the AZ letter via subnet cidr then combining the AZ 11 | # with the region to build full AZ name (ie us-east-1b) then lookup the shortname for the full region name (ie use1b) 12 | # 13 | # - public_label for tags that are related to the public subnets 14 | # - public_az_to_subnets is map of azs to public subnets (cidrs) 15 | # - public_subnet_to_azs is a map of public subnets to azs used for subnet name tagging 16 | # - public_subnets is a set of all public subnets 17 | ############################################################################################################ 18 | 19 | locals { 20 | public_label = "public" 21 | public_az_to_subnets = { for az, acls in var.tier.azs : az => acls.public } 22 | public_subnet_to_azs = { for subnet, az in transpose(local.public_az_to_subnets) : subnet => element(az, 0) } 23 | public_subnets = toset(keys(local.public_subnet_to_azs)) 24 | } 25 | 26 | # generate single word random pet name for each public subnet's name tag 27 | resource "random_pet" "public" { 28 | for_each = local.public_subnets 29 | 30 | length = 1 31 | } 32 | 33 | resource "aws_subnet" "public" { 34 | for_each = local.public_subnets 35 | 36 | vpc_id = aws_vpc.this.id 37 | availability_zone = format("%s%s", local.region_name, lookup(local.public_subnet_to_azs, each.value)) 38 | cidr_block = each.value 39 | map_public_ip_on_launch = true 40 | tags = merge( 41 | local.default_tags, 42 | { 43 | Name = format( 44 | "%s-%s-%s-%s-%s", 45 | upper(var.env_prefix), 46 | lookup(var.region_az_labels, format("%s%s", local.region_name, lookup(local.public_subnet_to_azs, each.value))), 47 | var.tier.name, 48 | local.public_label, 49 | lookup(random_pet.public, each.value).id 50 | ) 51 | } 52 | ) 53 | 54 | lifecycle { 55 | # ignore tags because a lookup on random_pet.public is used 56 | ignore_changes = [tags] 57 | } 58 | } 59 | 60 | locals { 61 | public_route_table_name_tag = { 62 | Name = format( 63 | "%s-%s-%s-%s-%s", 64 | upper(var.env_prefix), 65 | local.region_label, 66 | var.tier.name, 67 | local.public_label, 68 | "all" 69 | ) 70 | } 71 | } 72 | 73 | # one public route table for all public subnets across azs 74 | resource "aws_route_table" "public" { 75 | vpc_id = aws_vpc.this.id 76 | tags = merge( 77 | local.default_tags, 78 | local.public_route_table_name_tag 79 | ) 80 | } 81 | 82 | # one public route out through IGW for all public subnets across azs 83 | resource "aws_route" "public_route_out" { 84 | destination_cidr_block = local.route_any_cidr 85 | route_table_id = aws_route_table.public.id 86 | gateway_id = aws_internet_gateway.this.id 87 | } 88 | 89 | # associate each public subnet to the shared route table 90 | resource "aws_route_table_association" "public" { 91 | for_each = local.public_subnets 92 | 93 | subnet_id = lookup(aws_subnet.public, each.key).id 94 | route_table_id = aws_route_table.public.id 95 | 96 | lifecycle { 97 | # route_table_id is not needed here because the value 98 | # is not a part of the for_each iteration and therefore 99 | # wont trigger forcing a new resource 100 | ignore_changes = [subnet_id] 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /networking/tiered_vpc/variables.tf: -------------------------------------------------------------------------------- 1 | variable "env_prefix" { 2 | description = "prod, stage, etc" 3 | type = string 4 | } 5 | 6 | variable "region_az_labels" { 7 | description = "Region and AZ names mapped to short naming conventions for labeling" 8 | type = map(string) 9 | } 10 | 11 | variable "vpc_tenancy" { 12 | description = "Set VPC Tenancy" 13 | type = string 14 | default = "default" 15 | } 16 | 17 | variable "tags" { 18 | description = "Additional Tags" 19 | type = map(string) 20 | default = {} 21 | } 22 | 23 | variable "tier" { 24 | type = object({ 25 | name = string 26 | network = string 27 | azs = map(object({ 28 | public = list(string) 29 | private = list(string) 30 | })) 31 | }) 32 | 33 | validation { 34 | condition = length([ 35 | for az in var.tier.azs : true 36 | if length(az.public) > 0 37 | ]) == length(var.tier.azs) 38 | error_message = "There must be at least 1 public subnet per az." 39 | } 40 | 41 | # This is an example of validating CIDR notation 42 | # I don't think its really needed because the provider 43 | # will provide subnet errors if there is invalid cidrs 44 | validation { 45 | # https://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/ 46 | # the aws provider will error on validate cidr subnets too. 47 | condition = can(regex("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(3[0-2]|[1-2][0-9]|[0-9]))$", var.tier.network)) 48 | error_message = "Tier network must be in valid cidr notation ie 10.46.0.0/20, x.x.x.x/xx ." 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /networking/tiered_vpc/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | } 7 | random = { 8 | source = "hashicorp/random" 9 | } 10 | } 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /networking/tiered_vpc_ng/base.tf: -------------------------------------------------------------------------------- 1 | # Note from AWS: 2 | # Some AWS services use the 172.17.0.0/16 CIDR range. To avoid future conflicts, don’t use this range when creating your VPC. 3 | # ^will not explicitly block this cidr via variable validation but important to know. 4 | 5 | # Pull caller identity data from provider 6 | data "aws_caller_identity" "this" {} 7 | 8 | # Pull region data from provider 9 | data "aws_region" "this" {} 10 | 11 | locals { 12 | account_id = data.aws_caller_identity.this.account_id 13 | region_name = data.aws_region.this.name 14 | region_label = lookup(var.region_az_labels, local.region_name) 15 | route_any_cidr = "0.0.0.0/0" 16 | route_any_ipv6_cidr = "::/0" 17 | upper_env_prefix = upper(var.env_prefix) 18 | default_tags = merge({ 19 | Environment = var.env_prefix 20 | }, var.tags) 21 | 22 | # the tiered-vpc name is redundant when viewing in vpc aws console 23 | # but is most useful when viewing a TGW's VPC attachment. 24 | vpc_full_name = format("%s-tiered-vpc-%s-%s", local.upper_env_prefix, var.tiered_vpc.name, local.region_label) 25 | } 26 | 27 | resource "aws_vpc" "this" { 28 | cidr_block = var.tiered_vpc.ipv4.network_cidr 29 | ipv4_ipam_pool_id = var.tiered_vpc.ipv4.ipam_pool.id 30 | ipv6_cidr_block = var.tiered_vpc.ipv6.network_cidr 31 | ipv6_ipam_pool_id = var.tiered_vpc.ipv6.ipam_pool.id 32 | enable_dns_support = var.tiered_vpc.dns_support 33 | enable_dns_hostnames = var.tiered_vpc.dns_hostnames 34 | tags = merge( 35 | local.default_tags, 36 | { Name = local.vpc_full_name } 37 | ) 38 | 39 | # only using cidrs 40 | lifecycle { 41 | ignore_changes = [ipv4_netmask_length, ipv6_netmask_length] 42 | } 43 | } 44 | 45 | locals { 46 | secondary_cidrs = toset(var.tiered_vpc.ipv4.secondary_cidrs) 47 | } 48 | 49 | resource "aws_vpc_ipv4_cidr_block_association" "this" { 50 | for_each = local.secondary_cidrs 51 | 52 | cidr_block = each.key 53 | vpc_id = aws_vpc.this.id 54 | ipv4_ipam_pool_id = var.tiered_vpc.ipv4.ipam_pool.id 55 | 56 | # only using cidrs 57 | lifecycle { 58 | ignore_changes = [ipv4_netmask_length] 59 | } 60 | } 61 | 62 | locals { 63 | ipv6_secondary_cidrs = toset(var.tiered_vpc.ipv6.secondary_cidrs) 64 | } 65 | 66 | resource "aws_vpc_ipv6_cidr_block_association" "this" { 67 | for_each = local.ipv6_secondary_cidrs 68 | 69 | ipv6_cidr_block = each.key 70 | vpc_id = aws_vpc.this.id 71 | ipv6_ipam_pool_id = var.tiered_vpc.ipv6.ipam_pool.id 72 | 73 | # only using cidrs 74 | lifecycle { 75 | ignore_changes = [ipv6_netmask_length] 76 | } 77 | } 78 | 79 | locals { 80 | igw = { for this in [local.public_any_subnet_exists] : this => this if local.public_any_subnet_exists } 81 | } 82 | 83 | resource "aws_internet_gateway" "this" { 84 | for_each = local.igw 85 | 86 | vpc_id = aws_vpc.this.id 87 | tags = merge( 88 | local.default_tags, 89 | { Name = local.vpc_full_name } 90 | ) 91 | } 92 | 93 | locals { 94 | eigw = { for this in [local.private_ipv6_any_eigw_enabled] : this => this if local.private_ipv6_any_eigw_enabled } 95 | } 96 | 97 | resource "aws_egress_only_internet_gateway" "this" { 98 | for_each = local.eigw 99 | 100 | vpc_id = aws_vpc.this.id 101 | tags = merge( 102 | local.default_tags, 103 | { Name = local.vpc_full_name } 104 | ) 105 | } 106 | -------------------------------------------------------------------------------- /networking/tiered_vpc_ng/isolated.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | isolated_label = "isolated" 3 | isolated_subnet_cidrs = toset(flatten([for az, this in var.tiered_vpc.azs : this.isolated_subnets[*].cidr])) 4 | isolated_any_subnet_exists = length(local.isolated_subnet_cidrs) > 0 5 | isolated_route_table = { for this in [local.isolated_any_subnet_exists] : this => this if local.isolated_any_subnet_exists } 6 | isolated_az_to_subnet_cidrs = { for az, this in var.tiered_vpc.azs : az => this.isolated_subnets[*].cidr } 7 | isolated_subnet_cidr_to_az = { for subnet_cidr, azs in transpose(local.isolated_az_to_subnet_cidrs) : subnet_cidr => element(azs, 0) } 8 | isolated_subnet_cidr_to_subnet_name = merge([for this in var.tiered_vpc.azs : zipmap(this.isolated_subnets[*].cidr, this.isolated_subnets[*].name)]...) 9 | isolated_subnet_cidr_to_tags = merge([for this in var.tiered_vpc.azs : zipmap(this.isolated_subnets[*].cidr, this.isolated_subnets[*].tags)]...) 10 | 11 | # isolated ipv6 dual stack subnets 12 | isolated_ipv6_subnet_cidrs = toset(flatten([for az, this in var.tiered_vpc.azs : compact(this.isolated_subnets[*].ipv6_cidr)])) 13 | isolated_subnet_cidr_to_ipv6_subnet_cidr = merge([for this in var.tiered_vpc.azs : zipmap(this.isolated_subnets[*].cidr, this.isolated_subnets[*].ipv6_cidr)]...) 14 | } 15 | 16 | # isolated subnets are technically private subnets 17 | resource "aws_subnet" "this_isolated" { 18 | for_each = local.isolated_subnet_cidrs 19 | 20 | vpc_id = aws_vpc.this.id 21 | availability_zone = format("%s%s", local.region_name, lookup(local.isolated_subnet_cidr_to_az, each.key)) 22 | cidr_block = each.key 23 | ipv6_cidr_block = lookup(local.isolated_subnet_cidr_to_ipv6_subnet_cidr, each.key) 24 | map_public_ip_on_launch = false 25 | tags = merge( 26 | lookup(local.isolated_subnet_cidr_to_tags, each.key), 27 | local.default_tags, 28 | { 29 | Name = format( 30 | "%s-%s-%s-%s-%s", 31 | local.upper_env_prefix, 32 | var.tiered_vpc.name, 33 | local.isolated_label, 34 | lookup(local.isolated_subnet_cidr_to_subnet_name, each.key), 35 | lookup(var.region_az_labels, format("%s%s", local.region_name, lookup(local.isolated_subnet_cidr_to_az, each.key))) 36 | ) 37 | }) 38 | 39 | # isolated subnets could be a secondary ipv4 or ipv6 cidr so need to wait for main secondaries 40 | depends_on = [aws_vpc_ipv4_cidr_block_association.this, aws_vpc_ipv6_cidr_block_association.this] 41 | } 42 | 43 | # isolated subnets route table is intentionally empty 44 | # they can only communicate with other subnets within the vpc 45 | # which is consistent behvaior even when the vpc is in a full mesh tgw configuration 46 | resource "aws_route_table" "this_isolated" { 47 | for_each = local.isolated_route_table 48 | 49 | vpc_id = aws_vpc.this.id 50 | tags = merge( 51 | local.default_tags, 52 | { 53 | Name = format( 54 | "%s-%s-%s-%s-%s", 55 | local.upper_env_prefix, 56 | var.tiered_vpc.name, 57 | local.isolated_label, 58 | "all", 59 | local.region_label 60 | ) 61 | }) 62 | } 63 | 64 | resource "aws_route_table_association" "this_isolated" { 65 | for_each = local.isolated_subnet_cidrs 66 | 67 | subnet_id = lookup(aws_subnet.this_isolated, each.key).id 68 | route_table_id = lookup(aws_route_table.this_isolated, local.isolated_any_subnet_exists).id 69 | } 70 | 71 | -------------------------------------------------------------------------------- /networking/tiered_vpc_ng/outputs.tf: -------------------------------------------------------------------------------- 1 | output "account_id" { 2 | value = local.account_id 3 | } 4 | 5 | output "region" { 6 | value = local.region_name 7 | } 8 | 9 | output "default_security_group_id" { 10 | value = aws_vpc.this.default_security_group_id 11 | } 12 | 13 | output "full_name" { 14 | value = local.vpc_full_name 15 | } 16 | 17 | output "id" { 18 | value = aws_vpc.this.id 19 | } 20 | 21 | output "intra_vpc_security_group_id" { 22 | value = aws_security_group.this_intra_vpc.id 23 | } 24 | 25 | output "name" { 26 | value = var.tiered_vpc.name 27 | } 28 | 29 | output "network_cidr" { 30 | value = var.tiered_vpc.ipv4.network_cidr 31 | } 32 | 33 | output "secondary_cidrs" { 34 | value = var.tiered_vpc.ipv4.secondary_cidrs 35 | } 36 | 37 | output "ipv6_network_cidr" { 38 | value = var.tiered_vpc.ipv6.network_cidr 39 | } 40 | 41 | output "ipv6_secondary_cidrs" { 42 | value = var.tiered_vpc.ipv6.secondary_cidrs 43 | } 44 | 45 | output "private_route_table_ids" { 46 | value = [for this in aws_route_table.this_private : this.id] 47 | } 48 | 49 | output "private_subnet_cidrs" { 50 | value = local.private_subnet_cidrs 51 | } 52 | 53 | output "private_ipv6_subnet_cidrs" { 54 | value = local.private_ipv6_subnet_cidrs 55 | } 56 | 57 | output "private_subnet_name_to_subnet_id" { 58 | value = { for this in aws_subnet.this_private : lookup(local.private_subnet_cidr_to_subnet_name, this.cidr_block) => this.id } 59 | } 60 | 61 | output "public_route_table_ids" { 62 | value = [for this in aws_route_table.this_public : this.id] 63 | } 64 | 65 | output "public_subnet_cidrs" { 66 | value = local.public_subnet_cidrs 67 | } 68 | 69 | output "public_ipv6_subnet_cidrs" { 70 | value = local.public_ipv6_subnet_cidrs 71 | } 72 | 73 | output "public_special_subnet_ids" { 74 | value = [for this in local.public_az_to_special_subnet_cidr : lookup(aws_subnet.this_public, this).id] 75 | } 76 | 77 | output "private_special_subnet_ids" { 78 | value = [for this in local.private_az_to_special_subnet_cidr : lookup(aws_subnet.this_private, this).id] 79 | } 80 | 81 | output "public_subnet_name_to_subnet_id" { 82 | value = { for this in aws_subnet.this_public : lookup(local.public_subnet_cidr_to_subnet_name, this.cidr_block) => this.id } 83 | } 84 | 85 | output "public_natgw_az_to_eip" { 86 | value = { for az, this in aws_eip.this_public : az => this.public_ip } 87 | } 88 | 89 | output "isolated_route_table_ids" { 90 | value = [for this in aws_route_table.this_isolated : this.id] 91 | } 92 | 93 | output "isolated_subnet_cidrs" { 94 | value = local.isolated_subnet_cidrs 95 | } 96 | 97 | output "isolated_ipv6_subnet_cidrs" { 98 | value = local.isolated_ipv6_subnet_cidrs 99 | } 100 | 101 | output "isolated_subnet_name_to_subnet_id" { 102 | value = { for this in aws_subnet.this_isolated : lookup(local.isolated_subnet_cidr_to_subnet_name, this.cidr_block) => this.id } 103 | } 104 | 105 | output "centralized_egress_private" { 106 | value = var.tiered_vpc.ipv4.centralized_egress.private 107 | } 108 | 109 | output "centralized_egress_central" { 110 | value = var.tiered_vpc.ipv4.centralized_egress.central 111 | } 112 | 113 | -------------------------------------------------------------------------------- /networking/tiered_vpc_ng/security_groups.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | intra_vpc_security_group_name = format("%s-%s-%s-%s", local.upper_env_prefix, "intra-vpc", var.tiered_vpc.name, local.region_label) 3 | } 4 | 5 | # SG rules will be added to this by the Intra VPC Security Group Rule module for access across VPCs 6 | resource "aws_security_group" "this_intra_vpc" { 7 | name = local.intra_vpc_security_group_name 8 | description = "Intra VPC traffic over Transit Gateway" 9 | vpc_id = aws_vpc.this.id 10 | tags = merge( 11 | local.default_tags, 12 | { Name = local.intra_vpc_security_group_name } 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /networking/tiered_vpc_ng/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.4" # using anytrue() 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=5.61" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/base.tf: -------------------------------------------------------------------------------- 1 | # Pull caller identity data from provider 2 | data "aws_caller_identity" "this" {} 3 | 4 | # Pull region data from provider 5 | data "aws_region" "this" {} 6 | 7 | locals { 8 | account_id = data.aws_caller_identity.this.account_id 9 | region_name = data.aws_region.this.name 10 | region_label = lookup(var.region_az_labels, local.region_name) 11 | upper_env_prefix = upper(var.env_prefix) 12 | default_tags = merge({ 13 | Environment = var.env_prefix 14 | }, var.tags) 15 | 16 | centralized_router_name = format("%s-%s-%s-%s", local.upper_env_prefix, "centralized-router", var.centralized_router.name, local.region_label) 17 | 18 | # add the vpc and it's azs the to the mesh if there's 1 or more AZs with special = true 19 | # if there are no AZs with special = true then the VPC is fully removed from the mesh (vpc and tgw routes) 20 | # making it easier to decomission AZs and VPCs without manual intervention 21 | vpcs = { 22 | for this in var.centralized_router.vpcs : 23 | this.id => this 24 | if length(concat(this.private_special_subnet_ids, this.public_special_subnet_ids)) > 0 25 | } 26 | } 27 | 28 | # one tgw that will route between all tiered vpcs. 29 | resource "aws_ec2_transit_gateway" "this" { 30 | amazon_side_asn = var.centralized_router.amazon_side_asn 31 | default_route_table_association = "disable" 32 | default_route_table_propagation = "disable" 33 | tags = merge( 34 | local.default_tags, 35 | { Name = local.centralized_router_name } 36 | ) 37 | 38 | lifecycle { 39 | # preconditions are evaluated on apply only. 40 | precondition { 41 | condition = alltrue([for this in local.vpcs : contains([local.region_name], this.region)]) 42 | error_message = "All VPC regions must match the aws provider region for Centralized Router." 43 | } 44 | 45 | precondition { 46 | condition = alltrue([for this in local.vpcs : contains([local.account_id], this.account_id)]) 47 | error_message = "All VPC account IDs must match the aws provider account ID for Centralized Router." 48 | } 49 | } 50 | } 51 | 52 | # one route table for all vpc network_cidrs 53 | resource "aws_ec2_transit_gateway_route_table" "this" { 54 | transit_gateway_id = aws_ec2_transit_gateway.this.id 55 | tags = merge( 56 | local.default_tags, 57 | { Name = local.centralized_router_name } 58 | ) 59 | } 60 | 61 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/centralized_egress_routes.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | centralized_egress_route_any_cidr = "0.0.0.0/0" 3 | centralized_egress_central_vpc_id_to_route_any_cidr = { 4 | for this in local.vpcs : 5 | this.id => local.centralized_egress_route_any_cidr 6 | if this.centralized_egress_central && !contains(var.centralized_router.blackhole.cidrs, local.centralized_egress_route_any_cidr) 7 | } 8 | } 9 | 10 | # central tgw route 11 | resource "aws_ec2_transit_gateway_route" "this_centralized_egress_tgw_central_vpc_route_any" { 12 | for_each = local.centralized_egress_central_vpc_id_to_route_any_cidr 13 | 14 | destination_cidr_block = each.value 15 | transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this.id 16 | transit_gateway_attachment_id = lookup(aws_ec2_transit_gateway_vpc_attachment.this, each.key).id 17 | } 18 | 19 | locals { 20 | centralized_egress_private_route_table_id_to_route_any_cidr = merge([ 21 | for this in local.vpcs : { 22 | for private_route_table_id in this.private_route_table_ids : 23 | private_route_table_id => local.centralized_egress_route_any_cidr 24 | } if this.centralized_egress_private 25 | ]...) 26 | } 27 | 28 | # private vpc routes 29 | resource "aws_route" "this_centralized_egress_private_vpc_route_any" { 30 | for_each = local.centralized_egress_private_route_table_id_to_route_any_cidr 31 | 32 | destination_cidr_block = each.value 33 | route_table_id = each.key 34 | transit_gateway_id = aws_ec2_transit_gateway.this.id 35 | 36 | # make sure the tgw route table is available first before the setting routes on the vpcs 37 | depends_on = [aws_ec2_transit_gateway_route_table.this] 38 | } 39 | 40 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/modules/generate_routes_to_other_vpcs/.terraform-version: -------------------------------------------------------------------------------- 1 | 1.9.8 2 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/modules/generate_routes_to_other_vpcs/base.tf: -------------------------------------------------------------------------------- 1 | # generate routes to other VPC network_cidrs, secondary_cidrs, ipv6_newtork_cidrs and ipv6_secondaary_cidrs in private and public route tables for each VPC 2 | locals { 3 | network_cidrs_with_route_table_ids = [ 4 | for this in var.vpcs : { 5 | network_cidrs = concat([this.network_cidr], this.secondary_cidrs) 6 | ipv6_network_cidrs = concat(compact([this.ipv6_network_cidr]), this.ipv6_secondary_cidrs) 7 | route_table_ids = concat(this.private_route_table_ids, this.public_route_table_ids) 8 | } 9 | ] 10 | 11 | # ipv4 12 | associated_route_table_ids_with_other_network_cidrs = flatten([ 13 | for this in local.network_cidrs_with_route_table_ids : [ 14 | for route_table_id in this.route_table_ids : { 15 | route_table_id = route_table_id 16 | other_network_cidrs = [for n in flatten(local.network_cidrs_with_route_table_ids[*].network_cidrs) : n if !contains(this.network_cidrs, n)] 17 | }]]) 18 | 19 | # the better way to serve routes like hotcakes 20 | # { route_table_id = "rtb-12345678", destination_cidr_block = "x.x.x.x/x" } 21 | # need extra toset in case there's duplicates per AZ after the flatten call 22 | routes = toset(flatten([ 23 | for this in local.associated_route_table_ids_with_other_network_cidrs : [ 24 | for route_table_id_and_network_cidr in setproduct([this.route_table_id], this.other_network_cidrs) : { 25 | route_table_id = route_table_id_and_network_cidr[0] 26 | destination_cidr_block = route_table_id_and_network_cidr[1] 27 | }]])) 28 | 29 | #ipv6 30 | associated_route_table_ids_with_other_ipv6_network_cidrs = flatten([ 31 | for this in local.network_cidrs_with_route_table_ids : [ 32 | for route_table_id in this.route_table_ids : { 33 | route_table_id = route_table_id 34 | other_ipv6_network_cidrs = [for n in flatten(local.network_cidrs_with_route_table_ids[*].ipv6_network_cidrs) : n if !contains(this.ipv6_network_cidrs, n)] 35 | }]]) 36 | 37 | ipv6_routes = toset(flatten([ 38 | for this in local.associated_route_table_ids_with_other_ipv6_network_cidrs : [ 39 | for route_table_id_and_ipv6_network_cidr in setproduct([this.route_table_id], this.other_ipv6_network_cidrs) : { 40 | route_table_id = route_table_id_and_ipv6_network_cidr[0] 41 | destination_ipv6_cidr_block = route_table_id_and_ipv6_network_cidr[1] 42 | }]])) 43 | } 44 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/modules/generate_routes_to_other_vpcs/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * # Generate Routes to Other VPCs Description 3 | * 4 | * Run the test suites with `terraform test` in the `./modules/generate_routes_to_other_vpcs` directory. 5 | * ``` 6 | * tests/generate_routes.tftest.hcl... in progress 7 | * run "setup"... pass 8 | * run "final"... pass 9 | * run "ipv4_call_with_n_greater_than_one"... pass 10 | * run "ipv4_call_with_n_equal_to_one"... pass 11 | * run "ipv4_call_with_n_equal_to_zero"... pass 12 | * run "ipv4_cidr_validation"... pass 13 | * run "ipv4_with_secondary_cidrs_call_with_n_greater_than_one"... pass 14 | * run "ipv4_with_secondary_cidrs_call_with_n_equal_to_one"... pass 15 | * run "ipv4_with_secondary_cidrs_call_with_n_equal_to_zero"... pass 16 | * run "ipv6_call_with_n_greater_than_one"... pass 17 | * run "ipv6_call_with_n_equal_to_one"... pass 18 | * run "ipv6_call_with_n_equal_to_zero"... pass 19 | * run "ipv6_call_with_ipv6_secondary_cidrs_with_n_greater_than_zero"... pass 20 | * run "ipv6_with_secondary_cidrs_call_with_n_equal_to_one"... pass 21 | * run "ipv6_with_ipv6_secondary_cidrs_call_with_n_equal_to_zero"... pass 22 | * tests/generate_routes.tftest.hcl... tearing down 23 | * tests/generate_routes.tftest.hcl... pass 24 | * 25 | * Success! 15 passed, 0 failed. 26 | * ``` 27 | * The test suite will help when refactoring is needed. 28 | * 29 | * `v1.9.0` 30 | * - supportes generating VPC routes for IPv6 secondary cidrs across vpcs. 31 | * 32 | * `v1.8.2` 33 | * - now supports generating VPC routes IPv4 Secondary cidrs and IPv6 cidrs across vpcs. 34 | * 35 | * `v1.8.1` 36 | * This is a function type module (no resources) that will take a map of `tiered_vpc_ng` objects with [Tiered VPC-NG](https://github.com/JudeQuintana/terraform-modules/tree/master/networking/tiered_vpc_ng). 37 | * 38 | * It will create a map of routes to other VPC networks (execept itself) which will then be consumed by route resources. 39 | * 40 | * The `call` output is `toset([{ route_table_id = "rtb-12345678", destination_cidr_block = "x.x.x.x/x" }, ...])`. 41 | * 42 | * A list of route objects makes it easier to handle when passing to other route resource types (ie vpc, tgw) than a map of routes. 43 | * 44 | * ```hcl 45 | * # snippet 46 | * module "generate_routes_to_other_vpcs" { 47 | * source = "./modules/generate_routes_to_other_vpcs" 48 | * 49 | * vpcs = var.vpcs 50 | * } 51 | * 52 | * locals { 53 | * vpc_routes_to_other_vpcs = { 54 | * for this in module.generate_routes_to_other_vpcs.call : 55 | * format("|", this.route_table_id, this.destination_cidr_block) => this 56 | * } 57 | * } 58 | * 59 | * resource "aws_route" "this" { 60 | * for_each = local.vpc_routes_to_other_vpcs 61 | * 62 | * destination_cidr_block = each.value.destination_cidr_block 63 | * route_table_id = each.value.route_table_id 64 | * transit_gateway_id = aws_ec2_transit_gateway.this.id 65 | * 66 | * # make sure the tgw route table is available first before the setting routes routes on the vpcs 67 | * depends_on = [aws_ec2_transit_gateway_route_table.this] 68 | * } 69 | * ``` 70 | * 71 | */ 72 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/modules/generate_routes_to_other_vpcs/outputs.tf: -------------------------------------------------------------------------------- 1 | # output routes as set of objects instead of a map 2 | # it makes it easier to handle when passing to other route resource types (vpc, tgw) 3 | # toset([{ route_table_id = "rtb-12345678", destination_cidr_block = "x.x.x.x/x" }, ...]) 4 | output "ipv4" { 5 | value = local.routes 6 | } 7 | 8 | output "ipv6" { 9 | value = local.ipv6_routes 10 | } 11 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/modules/generate_routes_to_other_vpcs/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpcs" { 2 | description = "map of tiered_vpc_ng objects" 3 | type = map(object({ 4 | network_cidr = string 5 | secondary_cidrs = optional(list(string), []) 6 | ipv6_network_cidr = optional(string) 7 | ipv6_secondary_cidrs = optional(list(string), []) 8 | private_route_table_ids = list(string) 9 | public_route_table_ids = list(string) 10 | })) 11 | 12 | # im using a manual CIDR notation check here because there are no vpc resources in use to validate the CIDR for me. 13 | validation { 14 | condition = alltrue([for this in var.vpcs : can(cidrnetmask(this.network_cidr))]) 15 | error_message = "The VPC network_cidr must be in valid IPv4 CIDR notation ie 10.46.0.0/20, x.x.x.x/xx . Check for typos." 16 | } 17 | 18 | validation { 19 | condition = alltrue(flatten([ 20 | for this in var.vpcs : [ 21 | for secondary_cidr in this.secondary_cidrs : 22 | can(cidrnetmask(secondary_cidr)) 23 | ]])) 24 | error_message = "Each Secondary VPC CIDR valid IPv4 CIDR notation (ie x.x.x.x/xx -> 10.46.0.0/20). Check for typos." 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/modules/generate_routes_to_other_vpcs/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3.0" 3 | } 4 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/outputs.tf: -------------------------------------------------------------------------------- 1 | output "account_id" { 2 | value = local.account_id 3 | } 4 | 5 | output "amazon_side_asn" { 6 | value = var.centralized_router.amazon_side_asn 7 | } 8 | 9 | output "blackhole_cidrs" { 10 | value = var.centralized_router.blackhole.cidrs 11 | } 12 | 13 | output "blackhole_ipv6_cidrs" { 14 | value = var.centralized_router.blackhole.ipv6_cidrs 15 | } 16 | 17 | output "full_name" { 18 | value = local.centralized_router_name 19 | } 20 | 21 | output "id" { 22 | value = aws_ec2_transit_gateway.this.id 23 | } 24 | 25 | output "name" { 26 | value = var.centralized_router.name 27 | } 28 | 29 | output "region" { 30 | value = local.region_name 31 | } 32 | 33 | output "route_table_id" { 34 | value = aws_ec2_transit_gateway_route_table.this.id 35 | } 36 | 37 | output "vpc" { 38 | value = { 39 | names = [for this in local.vpcs : this.name] 40 | network_cidrs = [for this in local.vpcs : this.network_cidr] 41 | secondary_cidrs = flatten([for this in local.vpcs : this.secondary_cidrs]) 42 | ipv6_network_cidrs = compact([for this in local.vpcs : this.ipv6_network_cidr]) 43 | ipv6_secondary_cidrs = flatten([for this in local.vpcs : this.ipv6_secondary_cidrs]) 44 | private_route_table_ids = flatten([for this in local.vpcs : this.private_route_table_ids]) 45 | public_route_table_ids = flatten([for this in local.vpcs : this.public_route_table_ids]) 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/tgw_routes.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | ipv4_network_cidr_to_vpc_id = merge([ 3 | for this in local.vpcs : { 4 | for network_cidr in concat([this.network_cidr], this.secondary_cidrs) : 5 | network_cidr => this.id 6 | if !contains(var.centralized_router.blackhole.cidrs, network_cidr) 7 | }]...) 8 | } 9 | 10 | resource "aws_ec2_transit_gateway_route" "this_tgw_routes_to_vpcs" { 11 | for_each = local.ipv4_network_cidr_to_vpc_id 12 | 13 | destination_cidr_block = each.key 14 | transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this.id 15 | transit_gateway_attachment_id = lookup(aws_ec2_transit_gateway_vpc_attachment.this, each.value).id 16 | } 17 | 18 | locals { 19 | ipv6_network_cidr_to_vpc_id = merge([ 20 | for this in local.vpcs : { 21 | for ipv6_network_cidr in concat(compact([this.ipv6_network_cidr]), this.ipv6_secondary_cidrs) : 22 | ipv6_network_cidr => this.id 23 | if !contains(var.centralized_router.blackhole.ipv6_cidrs, ipv6_network_cidr) 24 | }]...) 25 | } 26 | 27 | resource "aws_ec2_transit_gateway_route" "this_tgw_ipv6_routes_to_vpcs" { 28 | for_each = local.ipv6_network_cidr_to_vpc_id 29 | 30 | destination_cidr_block = each.key 31 | transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this.id 32 | transit_gateway_attachment_id = lookup(aws_ec2_transit_gateway_vpc_attachment.this, each.value).id 33 | } 34 | 35 | # propagate routes for all attachments 36 | locals { 37 | propagate_routes_vpc_id_to_vpc_attachment = { for vpc_id, this in local.vpc_id_to_vpc_attachment : vpc_id => this if var.centralized_router.propagate_routes } 38 | } 39 | 40 | resource "aws_ec2_transit_gateway_route_table_propagation" "this" { 41 | for_each = local.propagate_routes_vpc_id_to_vpc_attachment 42 | 43 | transit_gateway_attachment_id = lookup(aws_ec2_transit_gateway_vpc_attachment.this, each.key).id 44 | transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this.id 45 | } 46 | 47 | # blackhole routes 48 | locals { 49 | blackhole_all_cidrs = toset(concat(var.centralized_router.blackhole.cidrs, var.centralized_router.blackhole.ipv6_cidrs)) 50 | } 51 | 52 | resource "aws_ec2_transit_gateway_route" "this_blackholes" { 53 | for_each = local.blackhole_all_cidrs 54 | 55 | # destination_cidr_block can be ipv4 or ipv6 (no separate attribute or resource) 56 | destination_cidr_block = each.value 57 | blackhole = true 58 | transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this.id 59 | 60 | # blackhole routes are filtered out from each dependant resource 61 | # which gives the ability to gracefully override any automatic static tgw route (0.0.0.0/0, etc) 62 | depends_on = [ 63 | aws_ec2_transit_gateway_route.this_tgw_routes_to_vpcs, 64 | aws_ec2_transit_gateway_route.this_tgw_ipv6_routes_to_vpcs, 65 | aws_ec2_transit_gateway_route.this_centralized_egress_tgw_central_vpc_route_any 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=5.61" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/vpc_attachments.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | vpc_attachment_format = "%s <-> %s" 3 | vpc_id_to_vpc_attachment = { 4 | for this in local.vpcs : 5 | this.id => { 6 | full_name = this.full_name 7 | subnet_ids = concat(this.private_special_subnet_ids, this.public_special_subnet_ids) 8 | ipv6_support = this.ipv6_network_cidr != null ? "enable" : "disable" 9 | } 10 | } 11 | } 12 | 13 | # VPC attachments will use either a private subnet or public subnet tagged as speciale from each AZ to route traffic. 14 | resource "aws_ec2_transit_gateway_vpc_attachment" "this" { 15 | for_each = local.vpc_id_to_vpc_attachment 16 | 17 | subnet_ids = each.value.subnet_ids 18 | transit_gateway_id = aws_ec2_transit_gateway.this.id 19 | transit_gateway_default_route_table_association = false 20 | transit_gateway_default_route_table_propagation = false 21 | vpc_id = each.key 22 | ipv6_support = each.value.ipv6_support 23 | tags = merge( 24 | local.default_tags, 25 | { 26 | Name = format( 27 | local.vpc_attachment_format, 28 | each.value.full_name, 29 | local.centralized_router_name 30 | ) 31 | } 32 | ) 33 | } 34 | 35 | # associate attachments to route table 36 | resource "aws_ec2_transit_gateway_route_table_association" "this" { 37 | for_each = local.vpc_id_to_vpc_attachment 38 | 39 | transit_gateway_attachment_id = lookup(aws_ec2_transit_gateway_vpc_attachment.this, each.key).id 40 | transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this.id 41 | } 42 | -------------------------------------------------------------------------------- /networking/transit_gateway_centralized_router_for_tiered_vpc_ng/vpc_routes.tf: -------------------------------------------------------------------------------- 1 | # Create routes to other VPC network_cidrs in private and public route tables for each VPC 2 | module "this_generate_routes_to_other_vpcs" { 3 | source = "./modules/generate_routes_to_other_vpcs" 4 | 5 | vpcs = local.vpcs 6 | } 7 | 8 | locals { 9 | route_format = "%s|%s" 10 | vpc_routes_to_other_vpcs = { 11 | for this in module.this_generate_routes_to_other_vpcs.ipv4 : 12 | format(local.route_format, this.route_table_id, this.destination_cidr_block) => this 13 | } 14 | } 15 | 16 | resource "aws_route" "this_vpc_routes_to_other_vpcs" { 17 | for_each = local.vpc_routes_to_other_vpcs 18 | 19 | route_table_id = each.value.route_table_id 20 | destination_cidr_block = each.value.destination_cidr_block 21 | transit_gateway_id = aws_ec2_transit_gateway.this.id 22 | 23 | # make sure the tgw route table is available first before the setting routes on the vpcs 24 | depends_on = [aws_ec2_transit_gateway_route_table.this] 25 | } 26 | 27 | # ipv6 28 | locals { 29 | ipv6_vpc_routes_to_other_vpcs = { 30 | for this in module.this_generate_routes_to_other_vpcs.ipv6 : 31 | format(local.route_format, this.route_table_id, this.destination_ipv6_cidr_block) => this 32 | } 33 | } 34 | 35 | resource "aws_route" "this_ipv6_vpc_routes_to_other_vpcs" { 36 | for_each = local.ipv6_vpc_routes_to_other_vpcs 37 | 38 | route_table_id = each.value.route_table_id 39 | destination_ipv6_cidr_block = each.value.destination_ipv6_cidr_block 40 | transit_gateway_id = aws_ec2_transit_gateway.this.id 41 | 42 | # make sure the tgw route table is available first before the setting routes on the vpcs 43 | depends_on = [aws_ec2_transit_gateway_route_table.this] 44 | } 45 | 46 | -------------------------------------------------------------------------------- /networking/vpc_peering_deluxe/base.tf: -------------------------------------------------------------------------------- 1 | # Pull region data and account id from provider 2 | data "aws_caller_identity" "this_local" { 3 | provider = aws.local 4 | } 5 | 6 | data "aws_region" "this_local" { 7 | provider = aws.local 8 | } 9 | 10 | data "aws_caller_identity" "this_peer" { 11 | provider = aws.peer 12 | } 13 | 14 | data "aws_region" "this_peer" { 15 | provider = aws.peer 16 | } 17 | 18 | locals { 19 | local_provider_account_id = data.aws_caller_identity.this_local.account_id 20 | local_provider_region_name = data.aws_region.this_local.name 21 | 22 | peer_provider_account_id = data.aws_caller_identity.this_peer.account_id 23 | peer_provider_region_name = data.aws_region.this_peer.name 24 | 25 | upper_env_prefix = upper(var.env_prefix) 26 | default_tags = merge({ 27 | Environment = var.env_prefix 28 | }, var.tags) 29 | } 30 | 31 | -------------------------------------------------------------------------------- /networking/vpc_peering_deluxe/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * VPC Peering Deluxe module will create appropriate routes for all subnets in each cross region Tiered VPC-NG by default. 3 | * 4 | * Should also work for intra region VPCs. 5 | * 6 | * Can be used in tandem with Centralized Router, Super Router and Full Mesh Trio for workloads that transfer lots of data to save on cost instead of via TGW. 7 | * 8 | * See it in action in [Full Mesh Trio Demo](https://github.com/JudeQuintana/terraform-main/tree/main/full_mesh_trio_demo) 9 | * 10 | * `v1.9.0` 11 | * - ipv6 routes for VPC ipv6 subnet cidrs 12 | * - moar validation 13 | * ``` 14 | * module "vpc_peering_deluxe" { 15 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/vpc_peering_deluxe?ref=v1.9.0" 16 | * ... 17 | * ``` 18 | * 19 | * 20 | * `v1.7.5` 21 | * - ipv4 routes for VPC ipv4 subnet cidrs 22 | * ``` 23 | * module "vpc_peering_deluxe" { 24 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/vpc_peering_deluxe?ref=v1.7.5" 25 | * 26 | * providers = { 27 | * aws.local = aws.use1 28 | * aws.peer = aws.use2 29 | * } 30 | * 31 | * env_prefix = var.env_prefix 32 | * vpc_peering_deluxe = { 33 | * local = { 34 | * vpc = module.vpc_use1 35 | * } 36 | * peer = { 37 | * vpc = module.vpc_use2 38 | * } 39 | * } 40 | * } 41 | * ``` 42 | * 43 | * Specific subnet cidrs can be selected (instead of default behavior of allow all subnets) to route across the VPC peering connection via only_route_subnet_cidrs variable list is populated. 44 | * 45 | * Additional option to allow remote dns resolution too. 46 | * ``` 47 | * module "vpc_peering_deluxe" { 48 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/vpc_peering_deluxe?ref=v1.7.5" 49 | * 50 | * providers = { 51 | * aws.local = aws.use1 52 | * aws.peer = aws.use2 53 | * } 54 | * 55 | * env_prefix = var.env_prefix 56 | * vpc_peering_deluxe = { 57 | * allow_remote_vpc_dns_resolution = true 58 | * local = { 59 | * vpc = module.vpc_use1 60 | * only_route_subnet_cidrs = ["172.16.1.0/24"] 61 | * } 62 | * peer = { 63 | * vpc = module.vpc_use2 64 | * only_route_subnet_cidrs = ["192.168.13.0/28"] 65 | * } 66 | * } 67 | * } 68 | * ``` 69 | * 70 | * Inter region VPC peering works too, route all subnets across peering connection 71 | * ``` 72 | * module "vpc_peering_deluxe_inter_region" { 73 | * source = "git@github.com:JudeQuintana/terraform-modules.git//networking/vpc_peering_deluxe?ref=v1.7.5" 74 | * 75 | * providers = { 76 | * aws.local = aws.usw2 77 | * aws.peer = aws.usw2 78 | * } 79 | * 80 | * env_prefix = var.env_prefix 81 | * vpc_peering_deluxe = { 82 | * local = { 83 | * vpc = module.vpc_usw2 84 | * } 85 | * peer = { 86 | * vpc = module.vpc_usw2 87 | * } 88 | * } 89 | * } 90 | * ``` 91 | * 92 | * 93 | */ 94 | -------------------------------------------------------------------------------- /networking/vpc_peering_deluxe/outputs.tf: -------------------------------------------------------------------------------- 1 | output "peering" { 2 | value = { 3 | allow_remote_vpc_dns_resolution = var.vpc_peering_deluxe.allow_remote_vpc_dns_resolution 4 | connection_id = aws_vpc_peering_connection_accepter.this_local_to_this_peer.id 5 | from_local = var.vpc_peering_deluxe.local.vpc.full_name 6 | to_peer = var.vpc_peering_deluxe.peer.vpc.full_name 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /networking/vpc_peering_deluxe/preconditions.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # guarantee the vpcs match their relative provider's region and account id before creating the vpc peering connections 3 | local_vpc_provider_region_check = { 4 | condition = contains([local.local_provider_region_name], var.vpc_peering_deluxe.local.vpc.region) 5 | error_message = "The local VPC region must match the aws.local provider alias region for VPC Peering Deluxe." 6 | } 7 | 8 | local_vpc_provider_account_id_check = { 9 | condition = contains([local.local_provider_account_id], var.vpc_peering_deluxe.local.vpc.account_id) 10 | error_message = "The local VPC account ID must match the aws.local provider alias account VPC Peering Deluxe." 11 | } 12 | 13 | peer_vpc_provider_region_check = { 14 | condition = contains([local.peer_provider_region_name], var.vpc_peering_deluxe.peer.vpc.region) 15 | error_message = "The peer VPC region must match the aws.peer provider alias region for VPC Peering Deluxe." 16 | } 17 | 18 | peer_vpc_provider_account_id_check = { 19 | condition = contains([local.peer_provider_account_id], var.vpc_peering_deluxe.peer.vpc.account_id) 20 | error_message = "The peer VPC account ID must match the aws.peer provider alias account VPC Peering Deluxe." 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /networking/vpc_peering_deluxe/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">=5.61" 7 | configuration_aliases = [aws.local, aws.peer] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /opinions/opinion_23/README.md: -------------------------------------------------------------------------------- 1 | # Terraform Opinion #23: Use list of objects over map of maps. 2 | 3 | See the [blog post](https://jq1.io/posts/opinion_23) for more details. 4 | 5 | Use `terraform apply -refresh-only` in each directory to show the same collection types output below for `list_of_objects` and `map_of_maps`. 6 | 7 | ``` 8 | map_of_attribute1_value_to_name = { 9 | "name1-value1" = "name1" 10 | "name2-value1" = "name2" 11 | "name3-value1" = "name3" 12 | } 13 | map_of_attribute_value_to_object = { 14 | "name1-value1" = { 15 | "attribute1" = "name1-value1" 16 | "attribute2" = "name1-value2" 17 | "attribute3" = "name1-value3" 18 | "name" = "name1" 19 | } 20 | "name2-value1" = { 21 | "attribute1" = "name2-value1" 22 | "attribute2" = "name2-value2" 23 | "attribute3" = "name2-value3" 24 | "name" = "name2" 25 | } 26 | "name3-value1" = { 27 | "attribute1" = "name3-value1" 28 | "attribute2" = "name3-value2" 29 | "attribute3" = "name3-value3" 30 | "name" = "name3" 31 | } 32 | } 33 | set_of_attribute1_values = toset([ 34 | "name1-value1", 35 | "name2-value1", 36 | "name3-value1", 37 | ]) 38 | set_of_names = toset([ 39 | "name1", 40 | "name2", 41 | "name3", 42 | ]) 43 | ``` 44 | -------------------------------------------------------------------------------- /opinions/opinion_23/list_of_objects/.terraform-version: -------------------------------------------------------------------------------- 1 | 1.5.1 2 | -------------------------------------------------------------------------------- /opinions/opinion_23/list_of_objects/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | list_of_objects = [ 3 | { 4 | name = "name1" 5 | attribute1 = "name1-value1" 6 | attribute2 = "name1-value2" 7 | attribute3 = "name1-value3" 8 | }, 9 | { 10 | name = "name2" 11 | attribute1 = "name2-value1" 12 | attribute2 = "name2-value2" 13 | attribute3 = "name2-value3" 14 | }, 15 | { 16 | name = "name3" 17 | attribute1 = "name3-value1" 18 | attribute2 = "name3-value2" 19 | attribute3 = "name3-value3" 20 | } 21 | ] 22 | } 23 | 24 | locals { 25 | map_of_attribute1_value_to_name = zipmap(local.list_of_objects[*].attribute1, local.list_of_objects[*].name) 26 | map_of_attribute1_value_to_object = { for o in local.list_of_objects : o.attribute1 => o } 27 | set_of_attribute1_values = toset(local.list_of_objects[*].attribute1) 28 | set_of_names = toset(local.list_of_objects[*].name) 29 | } 30 | 31 | output "map_of_attribute1_value_to_name" { 32 | value = local.map_of_attribute1_value_to_name 33 | } 34 | 35 | output "map_of_attribute_value_to_object" { 36 | value = local.map_of_attribute1_value_to_object 37 | } 38 | 39 | output "set_of_attribute1_values" { 40 | value = local.set_of_attribute1_values 41 | } 42 | 43 | output "set_of_names" { 44 | value = local.set_of_names 45 | } 46 | 47 | # getting to a map of maps is just as easy. 48 | # locals { 49 | # map_of_maps = { 50 | # for o in local.list_of_objects : 51 | # o.name => { 52 | # attribute1 = o.attribute1 53 | # attribute2 = o.attribute2 54 | # attribute3 = o.attribute3 55 | # } 56 | # } 57 | # } 58 | # 59 | # output "map_of_maps" { 60 | # value = local.map_of_maps 61 | # } 62 | 63 | # then using the map of maps directly to create a resource, 64 | # just like before but starting with list of objects. 65 | # 66 | # resource "some_resource" "this" { 67 | # for_each = local.map_of_maps 68 | # 69 | # attribute1 = each.value.attribute1 70 | # attribute2 = each.value.attribute2 71 | # attribute3 = each.value.attribute3 72 | # } 73 | -------------------------------------------------------------------------------- /opinions/opinion_23/list_of_objects/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1" 3 | } 4 | -------------------------------------------------------------------------------- /opinions/opinion_23/map_of_maps/.terraform-version: -------------------------------------------------------------------------------- 1 | 1.5.1 2 | -------------------------------------------------------------------------------- /opinions/opinion_23/map_of_maps/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | map_of_maps = { 3 | name1 = { 4 | attribute1 = "name1-value1" 5 | attribute2 = "name1-value2" 6 | attribute3 = "name1-value3" 7 | } 8 | name2 = { 9 | attribute1 = "name2-value1" 10 | attribute2 = "name2-value2" 11 | attribute3 = "name2-value3" 12 | } 13 | name3 = { 14 | attribute1 = "name3-value1" 15 | attribute2 = "name3-value2" 16 | attribute3 = "name3-value3" 17 | } 18 | } 19 | } 20 | 21 | # Then using local.map_of_maps to create a map of resource objects. 22 | # 23 | # resource "some_resource" "this" { 24 | # for_each = local.map_of_maps 25 | # 26 | # attribute1 = each.value.attribute1 27 | # attribute2 = each.value.attribute2 28 | # attribute3 = each.value.attribute3 29 | # } 30 | 31 | locals { 32 | # map_of_attribute1_value_to_name = { 33 | # "name1-value1" = "name1" 34 | # "name2-value1" = "name2" 35 | # "name3-value1" = "name3" 36 | # } 37 | map_of_attribute1_value_to_name = merge( 38 | [for k, v in local.map_of_maps : 39 | { for i in [values(v)[0]] : i => k } 40 | ]... 41 | ) 42 | 43 | # map_of_attribute1_value_to_object = { 44 | # "name1-value1" = { 45 | # "attribute1" = "name1-value1" 46 | # "attribute2" = "name1-value2" 47 | # "attribute3" = "name1-value3" 48 | # "name" = "name1" 49 | # } 50 | # "name2-value1" = { 51 | # "attribute1" = "name2-value1" 52 | # "attribute2" = "name2-value2" 53 | # "attribute3" = "name2-value3" 54 | # "name" = "name2" 55 | # } 56 | # "name3-value1" = { 57 | # "attribute1" = "name3-value1" 58 | # "attribute2" = "name3-value2" 59 | # "attribute3" = "name3-value3" 60 | # "name" = "name3" 61 | # } 62 | # } 63 | map_of_attribute1_value_to_object = { 64 | for k, v in local.map_of_maps : 65 | v.attribute1 => { 66 | name = k 67 | attribute1 = v.attribute1 68 | attribute2 = v.attribute2 69 | attribute3 = v.attribute3 70 | } 71 | } 72 | 73 | # set_of_attribute1_values = toset([ 74 | # "name1-value1", 75 | # "name2-value1", 76 | # "name3-value1", 77 | # ]) 78 | set_of_attribute1_values = toset( 79 | [for k, v in local.map_of_maps : v.attribute1] 80 | ) 81 | 82 | # set_of_names = toset([ 83 | # "name1", 84 | # "name2", 85 | # "name3", 86 | # ]) 87 | set_of_names = toset(keys(local.map_of_maps)) 88 | } 89 | 90 | output "map_of_attribute1_values_to_name" { 91 | value = local.map_of_attribute1_value_to_name 92 | } 93 | 94 | output "map_of_attribute_to_object" { 95 | value = local.map_of_attribute1_value_to_object 96 | } 97 | 98 | output "set_of_attribute1_values" { 99 | value = local.set_of_attribute1_values 100 | } 101 | 102 | output "set_of_names" { 103 | value = local.set_of_names 104 | } 105 | -------------------------------------------------------------------------------- /opinions/opinion_23/map_of_maps/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1" 3 | } 4 | -------------------------------------------------------------------------------- /utils/generate_routes_to_other_vpcs/.terraform-version: -------------------------------------------------------------------------------- 1 | 1.5.7 2 | -------------------------------------------------------------------------------- /utils/generate_routes_to_other_vpcs/base.tf: -------------------------------------------------------------------------------- 1 | # generate routes to other VPC network_cidrs in private and public route tables for each VPC 2 | locals { 3 | # { vpc-1-network_cidr => [ "vpc-1-private-rtb-id-1", "vpc-1-public-rtb-id-1", ... ], ...} 4 | vpc_network_cidr_to_route_table_ids = { 5 | for this in var.vpcs : 6 | this.network_cidr => concat(this.private_route_table_ids, this.public_route_table_ids) 7 | } 8 | 9 | # [ { rtb_id = "vpc-1-rtb-id-123", other_network_cidrs = [ "other-vpc-2-network_cidr", "other-vpc3-network_cidr", ... ] }, ...] 10 | associate_route_table_ids_with_other_network_cidrs = flatten([ 11 | for network_cidr, route_table_ids in local.vpc_network_cidr_to_route_table_ids : [ 12 | for this in route_table_ids : { 13 | route_table_id = this 14 | other_network_cidrs = [for n in keys(local.vpc_network_cidr_to_route_table_ids) : n if n != network_cidr] 15 | }]]) 16 | 17 | # deprecated loco legacy style 18 | # { route-table-id|route => route, ... } 19 | routes_legacy = merge([ 20 | for this in local.associate_route_table_ids_with_other_network_cidrs : { 21 | for route_table_id_and_network_cidr in setproduct([this.route_table_id], this.other_network_cidrs) : 22 | format("%s|%s", route_table_id_and_network_cidr[0], route_table_id_and_network_cidr[1]) => route_table_id_and_network_cidr[1] # each key must be unique, dont group by key 23 | }]...) 24 | 25 | # the better way to serve routes like hotcakes 26 | # { route_table_id = "rtb-12345678", destination_cidr_block = "x.x.x.x/x" } 27 | # need extra toset because there will be duplicates per AZ after the flatten call 28 | routes = toset(flatten([ 29 | for this in local.associate_route_table_ids_with_other_network_cidrs : [ 30 | for route_table_id_and_network_cidr in setproduct([this.route_table_id], this.other_network_cidrs) : { 31 | route_table_id = route_table_id_and_network_cidr[0] 32 | destination_cidr_block = route_table_id_and_network_cidr[1] 33 | }]])) 34 | } 35 | -------------------------------------------------------------------------------- /utils/generate_routes_to_other_vpcs/main.tf: -------------------------------------------------------------------------------- 1 | /* 2 | * # Generate Routes to Other VPCs Description 3 | * See [Building a generate routes function using Terraform test](https://jq1.io/posts/generating_routes) blog post. 4 | * 5 | * This is a function type module (no resources) that will take a map of `tiered_vpc_ng` objects with [Tiered VPC-NG](https://github.com/JudeQuintana/terraform-modules/tree/master/networking/tiered_vpc_ng). 6 | * 7 | * It will create a map of routes to other VPC networks (execept itself) which will then be consumed by route resources. 8 | * 9 | * The `call` output is `toset([{ route_table_id = "rtb-12345678", destination_cidr_block = "x.x.x.x/x" }, ...])`. 10 | * 11 | * A list of route objects makes it easier to handle when passing to other route resource types (ie vpc, tgw) than a map of routes. 12 | * 13 | * ```hcl 14 | * # snippet 15 | * module "generate_routes_to_other_vpcs" { 16 | * source = "git@github.com:JudeQuintana/terraform-modules.git//utils/generate_routes_to_other_vpcs?ref=v1.4.16" 17 | * 18 | * vpcs = var.vpcs 19 | * } 20 | * 21 | * locals { 22 | * vpc_routes_to_other_vpcs = { 23 | * for this in module.generate_routes_to_other_vpcs.call : 24 | * format("|", this.route_table_id, this.destination_cidr_block) => this 25 | * } 26 | * } 27 | * 28 | * resource "aws_route" "this" { 29 | * for_each = local.vpc_routes_to_other_vpcs 30 | * 31 | * destination_cidr_block = each.value.destination_cidr_block 32 | * route_table_id = each.value.route_table_id 33 | * transit_gateway_id = aws_ec2_transit_gateway.this.id 34 | * 35 | * # make sure the tgw route table is available first before the setting routes routes on the vpcs 36 | * depends_on = [aws_ec2_transit_gateway_route_table.this] 37 | * } 38 | * ``` 39 | * 40 | * Example future use in [TGW Centralized Router](https://github.com/JudeQuintana/terraform-modules/blob/3be85f2cbd590fbb02dc9190213e0b9296388c56/networking/transit_gateway_centralized_router_for_tiered_vpc_ng/main.tf#L83-L113): 41 | * 42 | * You can still get the legacy map of routes with the `call_legacy` output. 43 | * 44 | * But I don’t think generating a map of routes with unique keys for the caller is not a shortcut worth taking becuase of it’s inflexibility when needing different transforms. 45 | * 46 | * The `call_legacy` output is `{ "rtb-id|route" => "route", ... }`. It has been deprecated in favor of `call` 47 | * 48 | * ```hcl 49 | * # snippet 50 | * module "generate_routes_to_other_vpcs" { 51 | * source = "git@github.com:JudeQuintana/terraform-modules.git//utils/generate_routes_to_other_vpcs?ref=v1.7.4" 52 | * 53 | * vpcs = var.vpcs 54 | * } 55 | * 56 | * resource "aws_route" "this" { 57 | * for_each = module.generate_routes_to_other_vpcs.call_legacy 58 | * 59 | * destination_cidr_block = each.value 60 | * route_table_id = split("|", each.key)[0] 61 | * transit_gateway_id = aws_ec2_transit_gateway.this.id 62 | * 63 | * # make sure the tgw route table is available first before the setting routes routes on the vpcs 64 | * depends_on = [aws_ec2_transit_gateway_route_table.this] 65 | * } 66 | * ``` 67 | * 68 | * Run `terraform test` in the `./utils/generate_routes_to_other_vpcs` directory to run the test suite. 69 | * 70 | * The test suite will help when refactoring is needed. 71 | */ 72 | -------------------------------------------------------------------------------- /utils/generate_routes_to_other_vpcs/outputs.tf: -------------------------------------------------------------------------------- 1 | # deprecated 2 | # { "route-table-id|route" => "route", ... } 3 | output "call_legacy" { 4 | value = local.routes_legacy 5 | } 6 | 7 | # output routes as set of objects instead of a map 8 | # it makes it easier to handle when passing to other route resource types (vpc, tgw) 9 | # toset([{ route_table_id = "rtb-12345678", destination_cidr_block = "x.x.x.x/x" }, ...]) 10 | output "call" { 11 | value = local.routes 12 | } 13 | -------------------------------------------------------------------------------- /utils/generate_routes_to_other_vpcs/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpcs" { 2 | description = "map of tiered_vpc_ng objects" 3 | type = map(object({ 4 | network_cidr = string 5 | private_route_table_ids = list(string) 6 | public_route_table_ids = list(string) 7 | })) 8 | 9 | # im using a manual CIDR notation check here because there are no vpc resources in use to validate the CIDR for me. 10 | validation { 11 | condition = alltrue([for this in var.vpcs : can(regex("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(3[0-2]|[1-2][0-9]|[0-9]))$", this.network_cidr))]) 12 | error_message = "The VPC network_cidr must be in valid CIDR notation ie 10.46.0.0/20, x.x.x.x/xx ." 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /utils/generate_routes_to_other_vpcs/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | } 4 | -------------------------------------------------------------------------------- /utils/tiered_subnet_calculator/.terraform-version: -------------------------------------------------------------------------------- 1 | 1.5.1 2 | -------------------------------------------------------------------------------- /utils/tiered_subnet_calculator/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # generate top level networks for each tier based on tier newbit + base_cidr_block mask ie /4 + /16 = /20 3 | tier_networks = zipmap(var.tiers[*].name, cidrsubnets(var.base_cidr_block, var.tiers[*].newbit...)) 4 | 5 | # generate a subnet based on az newbit per tier network ie /4 + /20 = /24 6 | tier_subnets = { for t, n in local.tier_networks : t => cidrsubnets(n, values(var.az_newbits)...) } 7 | 8 | # generate azs to subnet map per tier 9 | tier_az_subnets = { for t, s in local.tier_subnets : t => zipmap(keys(var.az_newbits), s) } 10 | 11 | # build new tiers list with their associated network and az to subnets map 12 | tiers_with_subnets_per_az = [ 13 | for t in var.tiers : { 14 | name = t.name 15 | acl = t.acl 16 | network = lookup(local.tier_networks, t.name) 17 | azs = lookup(local.tier_az_subnets, t.name) 18 | }] 19 | } 20 | 21 | output "calculated_tiers" { 22 | value = local.tiers_with_subnets_per_az 23 | } 24 | 25 | -------------------------------------------------------------------------------- /utils/tiered_subnet_calculator/tiers.auto.tfvars: -------------------------------------------------------------------------------- 1 | base_cidr_block = "10.0.0.0/16" 2 | 3 | tiers = [ 4 | { 5 | name = "app" 6 | acl = "public" 7 | newbit = 4 8 | }, 9 | { 10 | name = "db" 11 | acl = "private" 12 | newbit = 4 13 | }, 14 | { 15 | name = "worker" 16 | acl = "private" 17 | newbit = 4 18 | }, 19 | { 20 | name = "lbs" 21 | acl = "public" 22 | newbit = 4 23 | } 24 | ] 25 | 26 | az_newbits = { 27 | a = 4 28 | b = 4 29 | c = 4 30 | d = 4 31 | } 32 | 33 | -------------------------------------------------------------------------------- /utils/tiered_subnet_calculator/variables.tf: -------------------------------------------------------------------------------- 1 | variable "base_cidr_block" { 2 | description = "Large starting CIDR block ie 10.0.0.0/16" 3 | type = string 4 | } 5 | 6 | variable "tiers" { 7 | description = "Networking tiers" 8 | type = list(object({ 9 | name = string 10 | acl = string 11 | newbit = number 12 | })) 13 | } 14 | 15 | variable "az_newbits" { 16 | description = "New bits to add to calculated cidr blocks for subnets per AZ" 17 | type = map(number) 18 | } 19 | 20 | -------------------------------------------------------------------------------- /utils/tiered_subnet_calculator/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">=1.3" 3 | } 4 | --------------------------------------------------------------------------------