AWS VPCs are a beautiful thing. So much more than just networking, I think of them as the top-level technical container for many other AWS resources. They are so flexible, so convenient that you should — and can — build your entire AWS environment and development process around them.
There was just one fly in the ointment: when you wanted traffic to flow between VPCs, you had to peer them in a mesh network. And transitive routing was a no-no, making a hub and spoke environment harder to build.
Last fall at re:Invent 2018, AWS fixed this with a major new VPC feature. The elegant Transit Gateway capability solves for all the issues that made scaling VPCs hard. Now, it’s both possible and desirable to churn out VPCs like M&Ms.
Recently, I developed a transit gateway template for a client and I thought that generalizing it might make it a useful sample for others to base their network designs on. In the JSON and YAML templates that follow, you’ll find the outline of a transit gateway along with a couple of VPCs and associated resources that could be the model for your environment as well.
Here’s a visual of what the template produces. The JSON and YAML versions are identical and produce the same outputs.
The design underlying this example of a transit gateway has the following attributes:
- I assume that the first VPC (
MgmtVPC
) will have access to all subnets in all VPCs. It’s where you would put monitoring and management resources. App1VPC
is one of what would probably be many VPCs added to the transit gateway. I create route tables and a security group that permit out-of-VPC traffic only to the management VPC’s first subnet.
The idea is that you could use this template for the basic networking infrstructure in an ever-expanding VPC envionment, each of which would be connected to the virtual gateway. You could simply add each additional VPC and update the CloudFormation stack by replacing the entire template. As you probably know, exisiting VPCs, route tables, security groups and, of course, the transit gateway itself would not be affected. You’d only add the additional VPCs.
This way, you’d be able to design and implement in code an auditable, verifyable network environment using transit gateways. Of course, you need to adjust the addressing, routes and security groups for your design.
I hope this transit gateway example and template is helpful to you. The template is provided first as a YAML template, followed by a JSON version. Both produce identical resources.
Updated: 2021-08-19. This template could fail if you run it in an AWS region in which your account has been assigned fewer than three AZs. It now only distributes subnets between AZs 0 and 1.
AWSTemplateFormatVersion: 2010-09-09 Description: >- Creates a transit gateway two VPCs each with two private subnets and routes for each subnet to the TGW. A security group permitting all traffic to/from the MgmtVPC is created and an SG that permits inbound traffic from MgmtVPC to App1VPC is also created. MgmtVPC would have all of the necessary monitoring and management tools. App1VPC is a model of just one of many possible App1VPC Alex Neihaus 2019-08-17 (c) 2019 Air11 Technology LLC -- licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0 Metadata: 'AWS::CloudFormation::Interface': ParameterGroups: - Label: default: VPC and Transit Gateway configuration parameters Parameters: - MgmtVPCCIDR - MgmtVPCSubnet1CIDR - MgmtVPCSubnet2CIDR - App1VPCCIDR - App1VPCSubnet1CIDR - App1VPCSubnet2CIDR - TransitGatewayASN - TransitGatewayRoute ParameterLabels: TransitGatewayRoute: default: >- Enter the CIDR that contains ALL VPCs that can be routed through the Transit Gateway (probably a /16) TransitGatewayASN: default: Enter the ASN of the transit gateway MgmtVPCCIDR: default: Enter CIDR of management VPC MgmtVPCSubnet1CIDR: default: Enter CIDR of the first private subnet in the management VPC MgmtVPCSubnet2CIDR: default: Enter CIDR of the second private subnet in the management VPC App1VPCCIDR: default: Enter the CIDR of the App1 VPC App1VPCSubnet1CIDR: default: Enter the CIDR of the first private subnet in the App1 VPC App1VPCSubnet2CIDR: default: Enter the CIDR of the second private subnet in the App1 VPC Parameters: TransitGatewayRoute: AllowedPattern: >- ^(([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])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Default: 10.10.0.0/16 Description: CIDR block for address range that contains ALL VPCs. Type: String MgmtVPCCIDR: AllowedPattern: >- ^(([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])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Default: 10.10.0.0/17 Description: CIDR block for Management VPC Type: String App1VPCCIDR: AllowedPattern: >- ^(([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])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Default: 10.10.128.0/17 Description: CIDR block for App1 VPC Type: String MgmtVPCSubnet1CIDR: AllowedPattern: >- ^(([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])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Default: 10.10.0.0/24 Description: CIDR block for the first management VPC subnet Type: String MgmtVPCSubnet2CIDR: AllowedPattern: >- ^(([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])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Default: 10.10.1.0/24 Description: CIDR block for the second management VPC subnet Type: String App1VPCSubnet1CIDR: AllowedPattern: >- ^(([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])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Default: 10.10.128.0/24 Description: CIDR block for the first private subnet in the App1 VPC Type: String App1VPCSubnet2CIDR: AllowedPattern: >- ^(([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])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Default: 10.10.129.0/24 Description: CIDR block for the second private subnet in the App1 VPC Type: String TransitGatewayASN: Default: '64612' ConstraintDescription: Must be an integer between 64512 and 65534 Description: The ASN for the AWS Transit Gateway Type: Number MinValue: '64512' MaxValue: '65534' Mappings: {} Resources: TransitGateway: Type: 'AWS::EC2::TransitGateway' Properties: AmazonSideAsn: !Ref TransitGatewayASN Description: VPC transit gateway AutoAcceptSharedAttachments: enable DefaultRouteTableAssociation: enable DnsSupport: enable VpnEcmpSupport: enable Tags: - Key: Name Value: !Join - '' - - TransitGateway- - !Ref TransitGatewayASN MgmtVPC: Type: 'AWS::EC2::VPC' Properties: EnableDnsSupport: 'true' EnableDnsHostnames: 'true' CidrBlock: !Ref MgmtVPCCIDR Tags: - Key: Name Value: !Join - '' - - MgmtVPC- - !Ref MgmtVPCCIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' DependsOn: TransitGateway MgmtVPCTGWAttachment: Type: 'AWS::EC2::TransitGatewayAttachment' Properties: SubnetIds: - !Ref MgmtVPCSubnet1 - !Ref MgmtVPCSubnet2 TransitGatewayId: !Ref TransitGateway VpcId: !Ref MgmtVPC Tags: - Key: Name Value: !Join - '' - - MgmtVPCAttachment- - !Ref MgmtVPCCIDR MgmtVPCSubnet1: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref MgmtVPC CidrBlock: !Ref MgmtVPCSubnet1CIDR AvailabilityZone: !Select - '1' - !GetAZs '' Tags: - Key: Name Value: !Join - '' - - MgmtVPCSubnet1- - !Ref MgmtVPCSubnet1CIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' MgmtVPCSubnet1RouteTable: Type: 'AWS::EC2::RouteTable' Properties: VpcId: !Ref MgmtVPC Tags: - Key: Name Value: !Join - '' - - MgmtVPCSubnet1RouteTable- - !Ref MgmtVPCSubnet1CIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' MgmtVPCSubnet1TGWRoute: Type: 'AWS::EC2::Route' DependsOn: MgmtVPCTGWAttachment Properties: RouteTableId: !Ref MgmtVPCSubnet1RouteTable DestinationCidrBlock: !Ref TransitGatewayRoute TransitGatewayId: !Ref TransitGateway MgmtSubnet1RouteTableAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref MgmtVPCSubnet1 RouteTableId: !Ref MgmtVPCSubnet1RouteTable MgmtVPCSubnet2: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref MgmtVPC CidrBlock: !Ref MgmtVPCSubnet2CIDR AvailabilityZone: !Select - '0' - !GetAZs '' Tags: - Key: Name Value: !Join - '' - - MgmtVPCSubnet2- - !Ref MgmtVPCSubnet2CIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' MgmtVPCSubnet2RouteTable: Type: 'AWS::EC2::RouteTable' Properties: VpcId: !Ref MgmtVPC Tags: - Key: Name Value: !Join - '' - - MgmtVPCSubnet2RouteTable- - !Ref MgmtVPCSubnet2CIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' MgmtVPCSubnet2TGWRoute: Type: 'AWS::EC2::Route' DependsOn: MgmtVPCTGWAttachment Properties: RouteTableId: !Ref MgmtVPCSubnet2RouteTable DestinationCidrBlock: !Ref TransitGatewayRoute TransitGatewayId: !Ref TransitGateway MgmtSubnet2RouteTableAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref MgmtVPCSubnet2 RouteTableId: !Ref MgmtVPCSubnet2RouteTable MgmtVPCSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: VpcId: !Ref MgmtVPC GroupDescription: Allow all traffic to TGW-connected VPCs SecurityGroupIngress: - IpProtocol: tcp FromPort: '0' ToPort: '1024' CidrIp: !Ref TransitGatewayRoute SecurityGroupEgress: - IpProtocol: tcp FromPort: '0' ToPort: '1024' CidrIp: !Ref TransitGatewayRoute Tags: - Key: Name Value: !Join - '' - - MgmtVPCSecurityGroup- - !Ref MgmtVPC - Key: CloudFormationStack Value: !Ref 'AWS::StackId' App1VPC: Type: 'AWS::EC2::VPC' DependsOn: TransitGateway Properties: EnableDnsSupport: 'true' EnableDnsHostnames: 'true' CidrBlock: !Ref App1VPCCIDR Tags: - Key: Name Value: !Join - '' - - App1VPC- - !Ref App1VPCCIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' App1VPCTGWAttachment: Type: 'AWS::EC2::TransitGatewayAttachment' Properties: SubnetIds: - !Ref App1VPCSubnet1 - !Ref App1VPCSubnet2 TransitGatewayId: !Ref TransitGateway VpcId: !Ref App1VPC Tags: - Key: Name Value: !Join - '' - - App1Attachment- - !Ref App1VPCCIDR App1VPCSubnet1: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref App1VPC CidrBlock: !Ref App1VPCSubnet1CIDR AvailabilityZone: !Select - '1' - !GetAZs '' Tags: - Key: Name Value: !Join - '' - - App1VPCSubnet1- - !Ref App1VPCSubnet1CIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' App1VPCSubnet1RouteTable: Type: 'AWS::EC2::RouteTable' Properties: VpcId: !Ref App1VPC Tags: - Key: Name Value: !Join - '' - - App1VPCSubnet1RouteTable- - !Ref App1VPCSubnet1CIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' App1VPCSubnet1TGWRoute: Type: 'AWS::EC2::Route' DependsOn: App1VPCTGWAttachment Properties: RouteTableId: !Ref App1VPCSubnet1RouteTable DestinationCidrBlock: !Ref MgmtVPCSubnet1CIDR TransitGatewayId: !Ref TransitGateway App1Subnet1RouteTableAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref App1VPCSubnet1 RouteTableId: !Ref App1VPCSubnet1RouteTable App1VPCSubnet2: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref App1VPC CidrBlock: !Ref App1VPCSubnet2CIDR AvailabilityZone: !Select - '0' - !GetAZs '' Tags: - Key: Name Value: !Join - '' - - App1VPCSubnet2- - !Ref App1VPCSubnet2CIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' App1VPCSubnet2RouteTable: Type: 'AWS::EC2::RouteTable' Properties: VpcId: !Ref App1VPC Tags: - Key: Name Value: !Join - '' - - App1VPCSubnet2RouteTable- - !Ref App1VPCSubnet2CIDR - Key: CloudFormationStack Value: !Ref 'AWS::StackId' App1VPCSubnet2TGWRoute: Type: 'AWS::EC2::Route' DependsOn: App1VPCTGWAttachment Properties: RouteTableId: !Ref App1VPCSubnet2RouteTable DestinationCidrBlock: !Ref MgmtVPCSubnet1CIDR TransitGatewayId: !Ref TransitGateway App1Subnet2RouteTableAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref App1VPCSubnet2 RouteTableId: !Ref App1VPCSubnet2RouteTable App1VPCSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: VpcId: !Ref App1VPC GroupDescription: Allow all traffic to MgmtVPC SecurityGroupIngress: - IpProtocol: tcp FromPort: '0' ToPort: '1024' CidrIp: !Ref MgmtVPCCIDR SecurityGroupEgress: - IpProtocol: tcp FromPort: '0' ToPort: '1024' CidrIp: !Ref MgmtVPCSubnet1CIDR Tags: - Key: Name Value: !Join - '' - - App1VPCSecurityGroup- - !Ref App1VPC - Key: CloudFormationStack Value: !Ref 'AWS::StackId' Outputs: TransitGateway: Description: Transit Gateway Value: !Ref TransitGateway Export: Name: !Sub '${AWS::StackName}-TransitGateway' MgmtVPCTGWAttachment: Description: Attachment ID of management VPC to Transit Gateway Value: !Ref MgmtVPCTGWAttachment MgmtVPCID: Description: VPCID of the management VPC Value: !Ref MgmtVPC Export: Name: !Sub '${AWS::StackName}-MgmtVPC' MgmtVPCSubnet1: Description: SubnetId of the first subnet in the management VPC Value: !Ref MgmtVPCSubnet1 MgmtVPCSubnet1RouteTable: Description: Route table ID of the first subnet in the management VPC Value: !Ref MgmtVPCSubnet1RouteTable MgmtVPCSubnet2: Description: SubnetId of the second subnet in the management VPC Value: !Ref MgmtVPCSubnet2 MgmtVPCSubnet2RouteTable: Description: Route table ID of the second subnet in the management VPC Value: !Ref MgmtVPCSubnet2RouteTable App1VPCID: Description: VPCID of the App1 VPC Value: !Ref App1VPC Export: Name: !Sub '${AWS::StackName}-App1VPC' App1VPCSubnet1: Description: SubnetId of the first subnet in the App1 VPC Value: !Ref App1VPCSubnet1 App1VPCSubnet1RouteTable: Description: Route table ID of the first subnet in the App1 VPC Value: !Ref App1VPCSubnet1RouteTable App1VPCSubnet2: Description: SubnetId of the second subnet in the App1 VPC Value: !Ref App1VPCSubnet2 App1VPCSubnet2RouteTable: Description: Route table ID of the second subnet in the App1 VPC Value: !Ref App1VPCSubnet2RouteTable
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "Creates a transit gateway two VPCs each with two private subnets and routes for each subnet to the TGW. A security group permitting all traffic to/from the MgmtVPC is created and an SG that permits inbound traffic from MgmtVPC to App1VPC is also created. MgmtVPC would have all of the necessary monitoring and management tools. App1VPC is a model of just one of many possible App1VPC Alex Neihaus 2019-08-17 (c) 2019 Air11 Technology LLC -- licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0", "Metadata": { "AWS::CloudFormation::Interface": { "ParameterGroups": [ { "Label": { "default": "VPC and Transit Gateway configuration parameters" }, "Parameters": [ "MgmtVPCCIDR", "MgmtVPCSubnet1CIDR", "MgmtVPCSubnet2CIDR", "App1VPCCIDR", "App1VPCSubnet1CIDR", "App1VPCSubnet2CIDR", "TransitGatewayASN", "TransitGatewayRoute" ] } ], "ParameterLabels": { "TransitGatewayRoute": { "default": "Enter the CIDR that contains ALL VPCs that can be routed through the Transit Gateway (probably a /16)" }, "TransitGatewayASN": { "default": "Enter the ASN of the transit gateway" }, "MgmtVPCCIDR": { "default": "Enter CIDR of management VPC" }, "MgmtVPCSubnet1CIDR": { "default": "Enter CIDR of the first private subnet in the management VPC" }, "MgmtVPCSubnet2CIDR": { "default": "Enter CIDR of the second private subnet in the management VPC" }, "App1VPCCIDR": { "default": "Enter the CIDR of the App1 VPC" }, "App1VPCSubnet1CIDR": { "default": "Enter the CIDR of the first private subnet in the App1 VPC" }, "App1VPCSubnet2CIDR": { "default": "Enter the CIDR of the second private subnet in the App1 VPC" } } } }, "Parameters": { "TransitGatewayRoute": { "AllowedPattern": "^(([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])(\\/(1[6-9]|2[0-8]))$", "ConstraintDescription": "CIDR block parameter must be in the form x.x.x.x/16-28", "Default": "10.10.0.0/16", "Description": "CIDR block for address range that contains ALL VPCs.", "Type": "String" }, "MgmtVPCCIDR": { "AllowedPattern": "^(([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])(\\/(1[6-9]|2[0-8]))$", "ConstraintDescription": "CIDR block parameter must be in the form x.x.x.x/16-28", "Default": "10.10.0.0/17", "Description": "CIDR block for Management VPC", "Type": "String" }, "App1VPCCIDR": { "AllowedPattern": "^(([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])(\\/(1[6-9]|2[0-8]))$", "ConstraintDescription": "CIDR block parameter must be in the form x.x.x.x/16-28", "Default": "10.10.128.0/17", "Description": "CIDR block for App1 VPC", "Type": "String" }, "MgmtVPCSubnet1CIDR": { "AllowedPattern": "^(([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])(\\/(1[6-9]|2[0-8]))$", "ConstraintDescription": "CIDR block parameter must be in the form x.x.x.x/16-28", "Default": "10.10.0.0/24", "Description": "CIDR block for the first management VPC subnet", "Type": "String" }, "MgmtVPCSubnet2CIDR": { "AllowedPattern": "^(([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])(\\/(1[6-9]|2[0-8]))$", "ConstraintDescription": "CIDR block parameter must be in the form x.x.x.x/16-28", "Default": "10.10.1.0/24", "Description": "CIDR block for the second management VPC subnet", "Type": "String" }, "App1VPCSubnet1CIDR": { "AllowedPattern": "^(([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])(\\/(1[6-9]|2[0-8]))$", "ConstraintDescription": "CIDR block parameter must be in the form x.x.x.x/16-28", "Default": "10.10.128.0/24", "Description": "CIDR block for the first private subnet in the App1 VPC", "Type": "String" }, "App1VPCSubnet2CIDR": { "AllowedPattern": "^(([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])(\\/(1[6-9]|2[0-8]))$", "ConstraintDescription": "CIDR block parameter must be in the form x.x.x.x/16-28", "Default": "10.10.129.0/24", "Description": "CIDR block for the second private subnet in the App1 VPC", "Type": "String" }, "TransitGatewayASN": { "Default": "64612", "ConstraintDescription": "Must be an integer between 64512 and 65534", "Description": "The ASN for the AWS Transit Gateway", "Type": "Number", "MinValue": "64512", "MaxValue": "65534" } }, "Mappings": {}, "Resources": { "TransitGateway": { "Type": "AWS::EC2::TransitGateway", "Properties": { "AmazonSideAsn": { "Ref": "TransitGatewayASN" }, "Description": "VPC transit gateway", "AutoAcceptSharedAttachments": "enable", "DefaultRouteTableAssociation": "enable", "DnsSupport": "enable", "VpnEcmpSupport": "enable", "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "TransitGateway-", { "Ref": "TransitGatewayASN" } ] ] } } ] } }, "MgmtVPC": { "Type": "AWS::EC2::VPC", "Properties": { "EnableDnsSupport": "true", "EnableDnsHostnames": "true", "CidrBlock": { "Ref": "MgmtVPCCIDR" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "MgmtVPC-", { "Ref": "MgmtVPCCIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] }, "DependsOn": "TransitGateway" }, "MgmtVPCTGWAttachment": { "Type": "AWS::EC2::TransitGatewayAttachment", "Properties": { "SubnetIds": [ { "Ref": "MgmtVPCSubnet1" }, { "Ref": "MgmtVPCSubnet2" } ], "TransitGatewayId": { "Ref": "TransitGateway" }, "VpcId": { "Ref": "MgmtVPC" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "MgmtVPCAttachment-", { "Ref": "MgmtVPCCIDR" } ] ] } } ] } }, "MgmtVPCSubnet1": { "Type": "AWS::EC2::Subnet", "Properties": { "VpcId": { "Ref": "MgmtVPC" }, "CidrBlock": { "Ref": "MgmtVPCSubnet1CIDR" }, "AvailabilityZone": { "Fn::Select": [ "1", { "Fn::GetAZs": "" } ] }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "MgmtVPCSubnet1-", { "Ref": "MgmtVPCSubnet1CIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "MgmtVPCSubnet1RouteTable": { "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": { "Ref": "MgmtVPC" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "MgmtVPCSubnet1RouteTable-", { "Ref": "MgmtVPCSubnet1CIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "MgmtVPCSubnet1TGWRoute": { "Type": "AWS::EC2::Route", "DependsOn": "MgmtVPCTGWAttachment", "Properties": { "RouteTableId": { "Ref": "MgmtVPCSubnet1RouteTable" }, "DestinationCidrBlock": { "Ref": "TransitGatewayRoute" }, "TransitGatewayId": { "Ref": "TransitGateway" } } }, "MgmtSubnet1RouteTableAssociation": { "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "SubnetId": { "Ref": "MgmtVPCSubnet1" }, "RouteTableId": { "Ref": "MgmtVPCSubnet1RouteTable" } } }, "MgmtVPCSubnet2": { "Type": "AWS::EC2::Subnet", "Properties": { "VpcId": { "Ref": "MgmtVPC" }, "CidrBlock": { "Ref": "MgmtVPCSubnet2CIDR" }, "AvailabilityZone": { "Fn::Select": [ "0", { "Fn::GetAZs": "" } ] }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "MgmtVPCSubnet2-", { "Ref": "MgmtVPCSubnet2CIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "MgmtVPCSubnet2RouteTable": { "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": { "Ref": "MgmtVPC" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "MgmtVPCSubnet2RouteTable-", { "Ref": "MgmtVPCSubnet2CIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "MgmtVPCSubnet2TGWRoute": { "Type": "AWS::EC2::Route", "DependsOn": "MgmtVPCTGWAttachment", "Properties": { "RouteTableId": { "Ref": "MgmtVPCSubnet2RouteTable" }, "DestinationCidrBlock": { "Ref": "TransitGatewayRoute" }, "TransitGatewayId": { "Ref": "TransitGateway" } } }, "MgmtSubnet2RouteTableAssociation": { "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "SubnetId": { "Ref": "MgmtVPCSubnet2" }, "RouteTableId": { "Ref": "MgmtVPCSubnet2RouteTable" } } }, "MgmtVPCSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "VpcId": { "Ref": "MgmtVPC" }, "GroupDescription": "Allow all traffic to TGW-connected VPCs", "SecurityGroupIngress": [ { "IpProtocol": "tcp", "FromPort": "0", "ToPort": "1024", "CidrIp": { "Ref": "TransitGatewayRoute" } } ], "SecurityGroupEgress": [ { "IpProtocol": "tcp", "FromPort": "0", "ToPort": "1024", "CidrIp": { "Ref": "TransitGatewayRoute" } } ], "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "MgmtVPCSecurityGroup-", { "Ref": "MgmtVPC" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "App1VPC": { "Type": "AWS::EC2::VPC", "DependsOn": "TransitGateway", "Properties": { "EnableDnsSupport": "true", "EnableDnsHostnames": "true", "CidrBlock": { "Ref": "App1VPCCIDR" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "App1VPC-", { "Ref": "App1VPCCIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "App1VPCTGWAttachment": { "Type": "AWS::EC2::TransitGatewayAttachment", "Properties": { "SubnetIds": [ { "Ref": "App1VPCSubnet1" }, { "Ref": "App1VPCSubnet2" } ], "TransitGatewayId": { "Ref": "TransitGateway" }, "VpcId": { "Ref": "App1VPC" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "App1Attachment-", { "Ref": "App1VPCCIDR" } ] ] } } ] } }, "App1VPCSubnet1": { "Type": "AWS::EC2::Subnet", "Properties": { "VpcId": { "Ref": "App1VPC" }, "CidrBlock": { "Ref": "App1VPCSubnet1CIDR" }, "AvailabilityZone": { "Fn::Select": [ "1", { "Fn::GetAZs": "" } ] }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "App1VPCSubnet1-", { "Ref": "App1VPCSubnet1CIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "App1VPCSubnet1RouteTable": { "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": { "Ref": "App1VPC" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "App1VPCSubnet1RouteTable-", { "Ref": "App1VPCSubnet1CIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "App1VPCSubnet1TGWRoute": { "Type": "AWS::EC2::Route", "DependsOn": "App1VPCTGWAttachment", "Properties": { "RouteTableId": { "Ref": "App1VPCSubnet1RouteTable" }, "DestinationCidrBlock": { "Ref": "MgmtVPCSubnet1CIDR" }, "TransitGatewayId": { "Ref": "TransitGateway" } } }, "App1Subnet1RouteTableAssociation": { "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "SubnetId": { "Ref": "App1VPCSubnet1" }, "RouteTableId": { "Ref": "App1VPCSubnet1RouteTable" } } }, "App1VPCSubnet2": { "Type": "AWS::EC2::Subnet", "Properties": { "VpcId": { "Ref": "App1VPC" }, "CidrBlock": { "Ref": "App1VPCSubnet2CIDR" }, "AvailabilityZone": { "Fn::Select": [ "0", { "Fn::GetAZs": "" } ] }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "App1VPCSubnet2-", { "Ref": "App1VPCSubnet2CIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "App1VPCSubnet2RouteTable": { "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": { "Ref": "App1VPC" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "App1VPCSubnet2RouteTable-", { "Ref": "App1VPCSubnet2CIDR" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } }, "App1VPCSubnet2TGWRoute": { "Type": "AWS::EC2::Route", "DependsOn": "App1VPCTGWAttachment", "Properties": { "RouteTableId": { "Ref": "App1VPCSubnet2RouteTable" }, "DestinationCidrBlock": { "Ref": "MgmtVPCSubnet1CIDR" }, "TransitGatewayId": { "Ref": "TransitGateway" } } }, "App1Subnet2RouteTableAssociation": { "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "SubnetId": { "Ref": "App1VPCSubnet2" }, "RouteTableId": { "Ref": "App1VPCSubnet2RouteTable" } } }, "App1VPCSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "VpcId": { "Ref": "App1VPC" }, "GroupDescription": "Allow all traffic to MgmtVPC", "SecurityGroupIngress": [ { "IpProtocol": "tcp", "FromPort": "0", "ToPort": "1024", "CidrIp": { "Ref": "MgmtVPCCIDR" } } ], "SecurityGroupEgress": [ { "IpProtocol": "tcp", "FromPort": "0", "ToPort": "1024", "CidrIp": { "Ref": "MgmtVPCSubnet1CIDR" } } ], "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "", [ "App1VPCSecurityGroup-", { "Ref": "App1VPC" } ] ] } }, { "Key": "CloudFormationStack", "Value": { "Ref": "AWS::StackId" } } ] } } }, "Outputs": { "TransitGateway": { "Description": "Transit Gateway", "Value": { "Ref": "TransitGateway" }, "Export": { "Name": { "Fn::Sub": "${AWS::StackName}-TransitGateway" } } }, "MgmtVPCTGWAttachment": { "Description": "Attachment ID of management VPC to Transit Gateway", "Value": { "Ref": "MgmtVPCTGWAttachment" } }, "MgmtVPCID": { "Description": "VPCID of the management VPC", "Value": { "Ref": "MgmtVPC" }, "Export": { "Name": { "Fn::Sub": "${AWS::StackName}-MgmtVPC" } } }, "MgmtVPCSubnet1": { "Description": "SubnetId of the first subnet in the management VPC", "Value": { "Ref": "MgmtVPCSubnet1" } }, "MgmtVPCSubnet1RouteTable": { "Description": "Route table ID of the first subnet in the management VPC", "Value": { "Ref": "MgmtVPCSubnet1RouteTable" } }, "MgmtVPCSubnet2": { "Description": "SubnetId of the second subnet in the management VPC", "Value": { "Ref": "MgmtVPCSubnet2" } }, "MgmtVPCSubnet2RouteTable": { "Description": "Route table ID of the second subnet in the management VPC", "Value": { "Ref": "MgmtVPCSubnet2RouteTable" } }, "App1VPCID": { "Description": "VPCID of the App1 VPC", "Value": { "Ref": "App1VPC" }, "Export": { "Name": { "Fn::Sub": "${AWS::StackName}-App1VPC" } } }, "App1VPCSubnet1": { "Description": "SubnetId of the first subnet in the App1 VPC", "Value": { "Ref": "App1VPCSubnet1" } }, "App1VPCSubnet1RouteTable": { "Description": "Route table ID of the first subnet in the App1 VPC", "Value": { "Ref": "App1VPCSubnet1RouteTable" } }, "App1VPCSubnet2": { "Description": "SubnetId of the second subnet in the App1 VPC", "Value": { "Ref": "App1VPCSubnet2" } }, "App1VPCSubnet2RouteTable": { "Description": "Route table ID of the second subnet in the App1 VPC", "Value": { "Ref": "App1VPCSubnet2RouteTable" } } } }
Leave a Reply