// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: MIT-0 variable "outbound_vpc_cidr" {} variable "EgressPublicAZ1_cidr" {} variable "EgressPublicAZ2_cidr" {} variable "EgressPrivateAZ1_cidr" {} variable "EgressPrivateAZ2_cidr" {} variable "tags" {} variable "Prod1_TGW_RT" { description = "TGW Attachment ID of Test VPC, enter N/A if you are running this script for the first time" type = string } variable "Prod2_TGW_RT" { description = "TGW Attachment ID of Dev VPC, enter N/A if you are running this script for the first time" type = string } variable "Prod3_TGW_RT" { description = "TGW Attachment ID of Prod VPC, enter N/A if you are running this script for the first time" type = string } variable "Sandbox_TGW_Attach" { description = "TGW Attachment ID of Sandbox VPC, enter N/A if you are running this script for the first time" type = string } ################################################################################ # List of Availability Zones ################################################################################ data "aws_availability_zones" "AZ" { state = "available" } ################################################################################ # VPC to route the traffic destined to Internet from all the accounts ################################################################################ resource "aws_vpc" "OutboundVPC" { cidr_block = var.outbound_vpc_cidr instance_tenancy = "default" tags = merge({ Name = "OutboundVPC" flowlog = "all"}, var.tags) } ################################################################################ # Public Subnet ################################################################################ resource "aws_subnet" "EgressPublicAZ1" { vpc_id = aws_vpc.OutboundVPC.id cidr_block = var.EgressPublicAZ1_cidr availability_zone = data.aws_availability_zones.AZ.names[0] tags = merge({ Name = "EgressPublicAZ1"}, var.tags) } resource "aws_subnet" "EgressPublicAZ2" { vpc_id = aws_vpc.OutboundVPC.id cidr_block = var.EgressPublicAZ2_cidr availability_zone = data.aws_availability_zones.AZ.names[1] tags = merge({ Name = "EgressPublicAZ2"}, var.tags) } ################################################################################ # Private Subnet ################################################################################ resource "aws_subnet" "EgressPrivateAZ1" { vpc_id = aws_vpc.OutboundVPC.id cidr_block = var.EgressPrivateAZ1_cidr availability_zone = data.aws_availability_zones.AZ.names[0] tags = merge({ Name = "EgressPrivateAZ1"}, var.tags) } resource "aws_subnet" "EgressPrivateAZ2" { vpc_id = aws_vpc.OutboundVPC.id cidr_block = var.EgressPrivateAZ2_cidr availability_zone = data.aws_availability_zones.AZ.names[1] tags = merge({ Name = "EgressPrivateAZ2"}, var.tags) } ################################################################################ # Internet Gateway ################################################################################ resource "aws_internet_gateway" "OutboundVPC_IGW" { vpc_id = aws_vpc.OutboundVPC.id tags = merge({ Name = "OutboundVPC_IGW"}, var.tags) } ################################################################################ # NAT Gateway ################################################################################ resource "aws_eip" "NATGW_EIP_AZ1" { vpc = true tags = merge({ Name = "NATGW_EIP_AZ1"}, var.tags) } resource "aws_eip" "NATGW_EIP_AZ2" { vpc = true tags = merge({ Name = "NATGW_EIP_AZ2"}, var.tags) } resource "aws_nat_gateway" "OutboundVPC_NATGW_AZ1" { allocation_id = aws_eip.NATGW_EIP_AZ1.id subnet_id = aws_subnet.EgressPublicAZ1.id tags = merge({ Name = "OutboundVPC_NATGW_AZ1"}, var.tags) } resource "aws_nat_gateway" "OutboundVPC_NATGW_AZ2" { allocation_id = aws_eip.NATGW_EIP_AZ2.id subnet_id = aws_subnet.EgressPublicAZ2.id tags = merge({ Name = "OutboundVPC_NATGW_AZ2"}, var.tags) } ################################################################################ # Route Table ################################################################################ resource "aws_route_table" "OutboundVPC_Public_RT" { vpc_id = aws_vpc.OutboundVPC.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.OutboundVPC_IGW.id } route { cidr_block = "10.120.0.0/16" transit_gateway_id = aws_ec2_transit_gateway.SharedNetwork_TGW.id } depends_on = [ aws_ec2_transit_gateway_vpc_attachment.OutboundVPC_TGW_Attach ] tags = merge({ Name = "OutboundVPC_Public_RT"}, var.tags) } resource "aws_route_table" "OutboundVPC_Private_RT_AZ1" { vpc_id = aws_vpc.OutboundVPC.id route { cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.OutboundVPC_NATGW_AZ1.id } tags = merge({ Name = "OutboundVPC_Private_RT_AZ1"}, var.tags) } resource "aws_route_table" "OutboundVPC_Private_RT_AZ2" { vpc_id = aws_vpc.OutboundVPC.id route { cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.OutboundVPC_NATGW_AZ2.id } tags = merge({ Name = "OutboundVPC_Private_RT_AZ2"}, var.tags) } ################################################################################ # Route Table Association ################################################################################ resource "aws_route_table_association" "OutboundVPC_Public_RT_AZ1_Association" { subnet_id = aws_subnet.EgressPublicAZ1.id route_table_id = aws_route_table.OutboundVPC_Public_RT.id } resource "aws_route_table_association" "OutboundVPC_Public_RT_AZ2_Association" { subnet_id = aws_subnet.EgressPublicAZ2.id route_table_id = aws_route_table.OutboundVPC_Public_RT.id } resource "aws_route_table_association" "OutboundVPC_Private_RT_AZ1_Association" { subnet_id = aws_subnet.EgressPrivateAZ1.id route_table_id = aws_route_table.OutboundVPC_Private_RT_AZ1.id } resource "aws_route_table_association" "OutboundVPC_Private_RT_AZ2_Association" { subnet_id = aws_subnet.EgressPrivateAZ2.id route_table_id = aws_route_table.OutboundVPC_Private_RT_AZ2.id } ################################################################################ # Transit Gateway ################################################################################ resource "aws_ec2_transit_gateway" "SharedNetwork_TGW" { auto_accept_shared_attachments = "enable" default_route_table_association = "disable" tags = merge({ Name = "SharedNetwork_TGW"}, var.tags) } ################################################################################ # Transit Gateway VPC Attachment ################################################################################ resource "aws_ec2_transit_gateway_vpc_attachment" "OutboundVPC_TGW_Attach" { subnet_ids = [aws_subnet.EgressPrivateAZ1.id, aws_subnet.EgressPrivateAZ2.id] transit_gateway_id = aws_ec2_transit_gateway.SharedNetwork_TGW.id vpc_id = aws_vpc.OutboundVPC.id transit_gateway_default_route_table_association = false tags = merge({ Name = "OutboundVPC_TGW_Attach"}, var.tags) } ################################################################################ # Transit Gateway VPN Attachment ################################################################################ resource "aws_customer_gateway" "Customer_Gateway" { bgp_asn = 65000 ip_address = "1.2.3.4" type = "ipsec.1" tags = merge({ Name = "Customer_Gateway"}, var.tags) } resource "aws_vpn_connection" "VPN" { customer_gateway_id = aws_customer_gateway.Customer_Gateway.id transit_gateway_id = aws_ec2_transit_gateway.SharedNetwork_TGW.id type = aws_customer_gateway.Customer_Gateway.type tags = merge({ Name = "VPN"}, var.tags) } ################################################################################ # Transit Gateway Route Table # We are creating one TGW route table for each organizational unit, so that the # VPCs part of the same OU can communicate with each other ################################################################################ resource "aws_ec2_transit_gateway_route_table" "OutboundVPC_TGW_RT" { transit_gateway_id = aws_ec2_transit_gateway.SharedNetwork_TGW.id tags = merge({ Name = "OutboundVPC_TGW_RT"}, var.tags) } resource "aws_ec2_transit_gateway_route_table" "Prod_TGW_RT" { transit_gateway_id = aws_ec2_transit_gateway.SharedNetwork_TGW.id tags = merge({ Name = "Prod_TGW_RT"}, var.tags) } resource "aws_ec2_transit_gateway_route_table" "Sandbox_TGW_RT" { transit_gateway_id = aws_ec2_transit_gateway.SharedNetwork_TGW.id tags = merge({ Name = "Sandbox_TGW_RT"}, var.tags) } ################################################################################ # Transit Gateway Routes ################################################################################ resource "aws_ec2_transit_gateway_route" "Sandbox_TGW_Attach_DefaultRoute" { destination_cidr_block = "0.0.0.0/0" transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.OutboundVPC_TGW_Attach.id transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.Sandbox_TGW_RT.id } ################################################################################ # Transit Gateway Route Table Association ################################################################################ resource "aws_ec2_transit_gateway_route_table_association" "OutboundVPC_TGW_RT_Association" { transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.OutboundVPC_TGW_Attach.id transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.OutboundVPC_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_association" "Prod1_TGW_RT_Association" { transit_gateway_attachment_id = var.Prod1_TGW_RT transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.Prod_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_association" "Prod2_TGW_RT_Association" { transit_gateway_attachment_id = var.Prod2_TGW_RT transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.Prod_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_association" "Prod3_TGW_RT_Association" { transit_gateway_attachment_id = var.Prod3_TGW_RT transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.Prod_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_association" "Sandbox_TGW_RT_Association" { transit_gateway_attachment_id = var.Sandbox_TGW_Attach transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.Sandbox_TGW_RT.id } ################################################################################ # Transit Gateway Route Table Propagation ################################################################################ resource "aws_ec2_transit_gateway_route_table_propagation" "Prod1_Propagation_OutboundVPC_TGW_RT" { transit_gateway_attachment_id = var.Prod1_TGW_RT transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.OutboundVPC_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_propagation" "Prod2_Propagation_OutboundVPC_TGW_RT" { transit_gateway_attachment_id = var.Prod2_TGW_RT transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.OutboundVPC_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_propagation" "Prod3_Propagation_OutboundVPC_TGW_RT" { transit_gateway_attachment_id = var.Prod3_TGW_RT transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.OutboundVPC_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_propagation" "Sandbox_Propagation_OutboundVPC_TGW_RT" { transit_gateway_attachment_id = var.Sandbox_TGW_Attach transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.OutboundVPC_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_propagation" "Prod1_Propagation_Sandbox_TGW_RT" { transit_gateway_attachment_id = var.Prod1_TGW_RT transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.Sandbox_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_propagation" "Prod2_Propagation_Sandbox_TGW_RT" { transit_gateway_attachment_id = var.Prod2_TGW_RT transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.Sandbox_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_propagation" "Prod3_Propagation_Sandbox_TGW_RT" { transit_gateway_attachment_id = var.Prod3_TGW_RT transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.Sandbox_TGW_RT.id } resource "aws_ec2_transit_gateway_route_table_propagation" "Sandbox_Propagation_Prod_TGW_RT" { transit_gateway_attachment_id = var.Sandbox_TGW_Attach transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.Prod_TGW_RT.id } ################################################################################ # TGW Attachment Tags ################################################################################ resource "aws_ec2_tag" "Prod1_TGW_RT" { resource_id = var.Prod1_TGW_RT key = "Name" value = "Prod1_TGW_RT" } resource "aws_ec2_tag" "Prod2_TGW_RT" { resource_id = var.Prod2_TGW_RT key = "Name" value = "Prod2_TGW_RT" } resource "aws_ec2_tag" "Prod3_TGW_RT" { resource_id = var.Prod3_TGW_RT key = "Name" value = "Prod3_TGW_RT" } resource "aws_ec2_tag" "Sandbox_TGW_Attach" { resource_id = var.Sandbox_TGW_Attach key = "Name" value = "Sandbox_TGW_Attach" } ################################################################################ # Resource Access Manager # Sharing the TGW with Prod and Sandbox OUs to attach the VPCs in the account # that are part of the respective OUs ################################################################################ resource "aws_ram_resource_share" "Shared_TGW_RAM" { name = "Shared_TGW_RAM" tags = merge({ Name = "Shared_TGW_RAM"}, var.tags) } resource "aws_ram_principal_association" "Shared_TGW_RAM_Principal_HealthSystem" { principal = "arn:aws:organizations::012345678910:ou/o-xxxxxxxx/ou-yyyy-zzzzzzz" resource_share_arn = aws_ram_resource_share.Shared_TGW_RAM.arn } resource "aws_ram_principal_association" "Shared_TGW_RAM_Principal_Sandbox" { principal = "arn:aws:organizations::012345678910:ou/o-xxxxxxxx/ou-yyyy-zzzzzzz" resource_share_arn = aws_ram_resource_share.Shared_TGW_RAM.arn } resource "aws_ram_resource_association" "Shared_TGW_RAM_Resource" { resource_arn = aws_ec2_transit_gateway.SharedNetwork_TGW.arn resource_share_arn = aws_ram_resource_share.Shared_TGW_RAM.arn }