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 permits 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 infrastructure in an ever-expanding VPC environment, 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, verifiable 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