aws-cloudformation/centralized_architecture/CentralizedArchitectureTgw.yaml [8:355]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AWSTemplateFormatVersion: "2010-09-09"

Description: >-
  AWS CloudFormation sample template for TGW setup for Gateway Load Balancer
  (GWLB) in centralized architecture. TGW is created in the same AWS account
  as Appliance and Spoke VPCs.
  
  This template creates:
    - 1 TGW
    - 3 VPC attachments, 2 for Spoke VPCs and one for Appliance VPC
    - 2 route tables: Egress and Transit Route Table
    - 3 Associations, 2 Spoke VPCs associated with Egress Route Table
      and Appliance VPC associated with Transit Route Table
    - Creates default route with Appliance VPC attachment as the target in
      Egress Route Table
    - Creates Spoke VPCs network address routes with appropriate Spoke VPC
      attachment as the target in Transit Route Table
    - Creates routes in Appliance VPC's Appliacetion Route Table with Transit
      Gateway as the target
  
  **WARNING** This template creates Transit Gateway with 3 VPC attachments. You
  will be billed for the AWS resources used if you create a stack from this template.

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: TGW Appliance VPC Configuration
        Parameters:
          - ApplianceVpcId
          - ApplianceVpcTgwAttachSubnet1Id
          - ApplianceVpcTgwAttachSubnet2Id
          - ApplianceVpcApplianceRtb1Id
          - ApplianceVpcApplianceRtb2Id
      - Label:
          default: TGW Spoke1 VPC Configuration
        Parameters:
          - Spoke1VpcId
          - Spoke1VpcCidr
          - Spoke1VpcTgwAttachSubnet1Id
          - Spoke1VpcTgwAttachSubnet2Id
          - Spoke1VpcRtb1Id
      - Label:
          default: TGW Spoke2 VPC Configuration
        Parameters:
          - Spoke2VpcId
          - Spoke2VpcCidr
          - Spoke2VpcTgwAttachSubnet1Id
          - Spoke2VpcTgwAttachSubnet2Id
          - Spoke2VpcRtb1Id
      - Label:
          default: Network CIDR for access
        Parameters:
          - AccessLocation
    ParameterLabels:
      # Appliance VPC Parameter Labels:
      ApplianceVpcId:
        default: Appliane VPC ID
      ApplianceVpcTgwAttachSubnet1Id:
        default: Appliance VPC Transit Gateway Subnet 1 ID
      ApplianceVpcTgwAttachSubnet2Id:
        default: Appliance VPC Transit Gateway Subnet 2 ID
      ApplianceVpcApplianceRtb1Id:
        default: Appliance VPC Appliance Route Table 1 ID
      ApplianceVpcApplianceRtb2Id:
        default: Appliance VPC Appliance Route Table 2 ID
      # Spoke1 VPC Parameter Labels:
      Spoke1VpcId:
        default: Spoke1 VPC ID
      Spoke1VpcCidr:
        default: Spoke1 VPC CIDR
      Spoke1VpcTgwAttachSubnet1Id:
        default: Spoke1 VPC Subnet1 ID
      Spoke1VpcTgwAttachSubnet2Id:
        default: Spoke1 VPC Subnet2 ID
      Spoke1VpcRtb1Id:
        default: Spoke1 VPC Application Route Table ID
      # Spoke2 VPC Parameter Labels:
      Spoke2VpcId:
        default: Spoke2 VPC ID
      Spoke2VpcCidr:
        default: Spoke2 VPC CIDR
      Spoke2VpcTgwAttachSubnet1Id:
        default: Spoke2 VPC Subnet1 ID
      Spoke2VpcTgwAttachSubnet2Id:
        default: Spoke2 VPC Subnet2 ID
      Spoke2VpcRtb1Id:
        default: Spoke2 VPC Application Route Table ID
      # Network CIDR Location:
      AccessLocation:
        default: Network CIDR for Routing and Access

Parameters:
  # Appliance VPC Parameters:
  ApplianceVpcId:
    Description: Appliance VPC ID
    Type: String
    ConstraintDescription: Must be a valid VPC ID  
  ApplianceVpcTgwAttachSubnet1Id:
    Description: Appliance VPC Subnet1 ID for TGW attachment in AZ1
    Type: String
    ConstraintDescription: Must be a valid Subnet ID    
  ApplianceVpcTgwAttachSubnet2Id:
    Description: Appliance VPC Subnet2 ID for TGW attachment in AZ2
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  ApplianceVpcApplianceRtb1Id:
    Description: Appliance VPC Appliance Route Table 1 ID
    Type: String
    ConstraintDescription: Must be a valid Route Table ID    
  ApplianceVpcApplianceRtb2Id:
    Description: Appliance VPC Appliance Route Table 2 ID
    Type: String
    ConstraintDescription: Must be a valid Route Table ID     
  # Spoke1 VPC Parameters:
  Spoke1VpcId:
    Description: Spoke1 VPC ID
    Type: String
    ConstraintDescription: Must be a valid VPC ID
  Spoke1VpcCidr:
    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]))$"
    Default: 10.0.0.0/24
    Description: Spoke1 VPC Network CIDR
    Type: String
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/y   
  Spoke1VpcTgwAttachSubnet1Id:
    Description: Spoke1 VPC Subnet1 ID for TGW attachment in AZ1
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  Spoke1VpcTgwAttachSubnet2Id:
    Description: Spoke1 VPC Subnet2 ID for TGW attachment in AZ2
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  Spoke1VpcRtb1Id:
    Description: Spoke1 VPC Application Route Table ID
    Type: String
    ConstraintDescription: Must be a valid Route Table ID
  # Spoke2 VPC Parameters:
  Spoke2VpcId:
    Description: Spoke2 VPC ID
    Type: String
    ConstraintDescription: Must be a valid VPC ID
  Spoke2VpcCidr:
    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]))$"
    Default: 10.0.1.0/24
    Description: Spoke2 VPC Network CIDR
    Type: String
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/y  
  Spoke2VpcTgwAttachSubnet1Id:
    Description: Spoke2 VPC Subnet1 ID for TGW attachment in AZ1
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  Spoke2VpcTgwAttachSubnet2Id:
    Description: Spoke2 VPC Subnet2 ID for TGW attachment in AZ2
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  Spoke2VpcRtb1Id:
    Description: Spoke2 VPC Application Route Table ID
    Type: String
    ConstraintDescription: Must be a valid Route Table ID  
  # Network CIDR Parameter:    
  AccessLocation:
    Description: >-
      Enter desired Network CIDR to access Bastion Host. Default is set to
      access from anywhere (0.0.0.0/0) and it is not recommended
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    MinLength: "9"
    MaxLength: "18"
    Default: 0.0.0.0/0
    Type: String
    ConstraintDescription: Must be a valid Network CIDR of the form x.x.x.x/y

Resources:
# Create Transit Gateway:
  Tgw1:
    Type: AWS::EC2::TransitGateway
    Properties:
      AmazonSideAsn: 64512
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: disable
      DefaultRouteTablePropagation: disable
      Description: Transit Gateway 1 for GWLB Centralized Architecture
      DnsSupport: enable
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-tgw-1"
      VpnEcmpSupport: enable

# Create Transit Gateway Attachments:
  Tgw1ApplianceVpcAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref ApplianceVpcTgwAttachSubnet1Id
        - !Ref ApplianceVpcTgwAttachSubnet2Id
      TransitGatewayId: !Ref Tgw1
      VpcId: !Ref ApplianceVpcId
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-appliance-vpc-attachment"

  Tgw1Spoke1VpcAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref Spoke1VpcTgwAttachSubnet1Id
        - !Ref Spoke1VpcTgwAttachSubnet2Id
      TransitGatewayId: !Ref Tgw1
      VpcId: !Ref Spoke1VpcId
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-spoke1-vpc-attachment"

  Tgw1Spoke2VpcAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref Spoke2VpcTgwAttachSubnet1Id
        - !Ref Spoke2VpcTgwAttachSubnet2Id
      TransitGatewayId: !Ref Tgw1
      VpcId: !Ref Spoke2VpcId
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-spoke2-vpc-attachment"

# Create Transit Gateway Route Tables:
  Tgw1TransitRtb:
    Type: AWS::EC2::TransitGatewayRouteTable
    Properties: 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-tgw-transit-rtb"   
      TransitGatewayId: !Ref Tgw1

  Tgw1EgressRtb:
    Type: AWS::EC2::TransitGatewayRouteTable
    Properties: 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-tgw-egress-rtb"
      TransitGatewayId: !Ref Tgw1

# Create Transit Gateway Attachment Associations:
  Tgw1ApplianceVpcAttachmentAssociation:
    Type: AWS::EC2::TransitGatewayRouteTableAssociation
    Properties: 
      TransitGatewayAttachmentId: !Ref Tgw1ApplianceVpcAttachment
      TransitGatewayRouteTableId: !Ref Tgw1TransitRtb

  Tgw1Spoke1VpcAttachmentAssociation:
    Type: AWS::EC2::TransitGatewayRouteTableAssociation
    Properties: 
      TransitGatewayAttachmentId: !Ref Tgw1Spoke1VpcAttachment
      TransitGatewayRouteTableId: !Ref Tgw1EgressRtb

  Tgw1Spoke2VpcAttachmentAssociation:
    Type: AWS::EC2::TransitGatewayRouteTableAssociation
    Properties: 
      TransitGatewayAttachmentId: !Ref Tgw1Spoke2VpcAttachment
      TransitGatewayRouteTableId: !Ref Tgw1EgressRtb      

# Create Transit Gateway Routes:
  Tgw1Route1:
    Type: AWS::EC2::TransitGatewayRoute
    Properties:
      TransitGatewayAttachmentId: !Ref Tgw1Spoke1VpcAttachment
      DestinationCidrBlock: !Ref Spoke1VpcCidr
      TransitGatewayRouteTableId: !Ref Tgw1TransitRtb

  Tgw1Route2:
    Type: AWS::EC2::TransitGatewayRoute
    Properties:
      TransitGatewayAttachmentId: !Ref Tgw1Spoke2VpcAttachment
      DestinationCidrBlock: !Ref Spoke2VpcCidr
      TransitGatewayRouteTableId: !Ref Tgw1TransitRtb

  Tgw1Route3:
    Type: AWS::EC2::TransitGatewayRoute
    Properties:
      TransitGatewayAttachmentId: !Ref Tgw1ApplianceVpcAttachment
      DestinationCidrBlock: !Ref AccessLocation
      TransitGatewayRouteTableId: !Ref Tgw1EgressRtb

# Add TGW as Target to VPC Route Tables:
  # Appliance VPC route table configuration:
  # AZ1:
  AddRoute1ApplianceVpc:
    DependsOn:
      - Tgw1
      - Tgw1ApplianceVpcAttachment     
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref Spoke1VpcCidr
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref ApplianceVpcApplianceRtb1Id

  AddRoute2ApplianceVpc:
    DependsOn: [Tgw1, Tgw1ApplianceVpcAttachment]  
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref Spoke2VpcCidr
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref ApplianceVpcApplianceRtb1Id
  # AZ2:
  AddRoute3ApplianceVpc:
    DependsOn: [Tgw1, Tgw1ApplianceVpcAttachment] 
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref Spoke1VpcCidr
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref ApplianceVpcApplianceRtb2Id

  AddRoute4ApplianceVpc:
    DependsOn: [Tgw1, Tgw1ApplianceVpcAttachment] 
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref Spoke2VpcCidr
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref ApplianceVpcApplianceRtb2Id  
  
  # Spoke1 VPC route table configuration:
  AddRoute1Spoke1Vpc:
    DependsOn: [Tgw1, Tgw1Spoke1VpcAttachment]
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref AccessLocation
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref Spoke1VpcRtb1Id 

  # Spoke2 VPC route table configuration:
  AddRoute1Spoke2Vpc:
    DependsOn: [Tgw1, Tgw1Spoke1VpcAttachment]
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref AccessLocation
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref Spoke2VpcRtb1Id

# To ensure flow symmetry, Transit Gateway appliance mode is enabled on the Inspection VPC’s attachment.
# For more details on Transit Gateway appliance mode, refer to:
# https://aws.amazon.com/blogs/networking-and-content-delivery/centralized-inspection-architecture-with-aws-gateway-load-balancer-and-aws-transit-gateway/
# https://docs.aws.amazon.com/vpc/latest/tgw/transit-gateway-appliance-scenario.html
# CloudFormation yet does not support enabling appliance mode. Hence need to enable it using Lambda custom resource:

# Transit Gateway appliance mode Lambda Role:
  TgwLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



aws-cloudformation/centralized_architecture/nested-stack/Tgw.yaml [8:355]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AWSTemplateFormatVersion: "2010-09-09"

Description: >-
  AWS CloudFormation sample template for TGW setup for Gateway Load Balancer
  (GWLB) in centralized architecture. TGW is created in the same AWS account
  as Appliance and Spoke VPCs.
  
  This template creates:
    - 1 TGW
    - 3 VPC attachments, 2 for Spoke VPCs and one for Appliance VPC
    - 2 route tables: Egress and Transit Route Table
    - 3 Associations, 2 Spoke VPCs associated with Egress Route Table
      and Appliance VPC associated with Transit Route Table
    - Creates default route with Appliance VPC attachment as the target in
      Egress Route Table
    - Creates Spoke VPCs network address routes with appropriate Spoke VPC
      attachment as the target in Transit Route Table
    - Creates routes in Appliance VPC's Appliacetion Route Table with Transit
      Gateway as the target
  
  **WARNING** This template creates Transit Gateway with 3 VPC attachments. You
  will be billed for the AWS resources used if you create a stack from this template.

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: TGW Appliance VPC Configuration
        Parameters:
          - ApplianceVpcId
          - ApplianceVpcTgwAttachSubnet1Id
          - ApplianceVpcTgwAttachSubnet2Id
          - ApplianceVpcApplianceRtb1Id
          - ApplianceVpcApplianceRtb2Id
      - Label:
          default: TGW Spoke1 VPC Configuration
        Parameters:
          - Spoke1VpcId
          - Spoke1VpcCidr
          - Spoke1VpcTgwAttachSubnet1Id
          - Spoke1VpcTgwAttachSubnet2Id
          - Spoke1VpcRtb1Id
      - Label:
          default: TGW Spoke2 VPC Configuration
        Parameters:
          - Spoke2VpcId
          - Spoke2VpcCidr
          - Spoke2VpcTgwAttachSubnet1Id
          - Spoke2VpcTgwAttachSubnet2Id
          - Spoke2VpcRtb1Id
      - Label:
          default: Network CIDR for access
        Parameters:
          - AccessLocation
    ParameterLabels:
      # Appliance VPC Parameter Labels:
      ApplianceVpcId:
        default: Appliane VPC ID
      ApplianceVpcTgwAttachSubnet1Id:
        default: Appliance VPC Transit Gateway Subnet 1 ID
      ApplianceVpcTgwAttachSubnet2Id:
        default: Appliance VPC Transit Gateway Subnet 2 ID
      ApplianceVpcApplianceRtb1Id:
        default: Appliance VPC Appliance Route Table 1 ID
      ApplianceVpcApplianceRtb2Id:
        default: Appliance VPC Appliance Route Table 2 ID
      # Spoke1 VPC Parameter Labels:
      Spoke1VpcId:
        default: Spoke1 VPC ID
      Spoke1VpcCidr:
        default: Spoke1 VPC CIDR
      Spoke1VpcTgwAttachSubnet1Id:
        default: Spoke1 VPC Subnet1 ID
      Spoke1VpcTgwAttachSubnet2Id:
        default: Spoke1 VPC Subnet2 ID
      Spoke1VpcRtb1Id:
        default: Spoke1 VPC Application Route Table ID
      # Spoke2 VPC Parameter Labels:
      Spoke2VpcId:
        default: Spoke2 VPC ID
      Spoke2VpcCidr:
        default: Spoke2 VPC CIDR
      Spoke2VpcTgwAttachSubnet1Id:
        default: Spoke2 VPC Subnet1 ID
      Spoke2VpcTgwAttachSubnet2Id:
        default: Spoke2 VPC Subnet2 ID
      Spoke2VpcRtb1Id:
        default: Spoke2 VPC Application Route Table ID
      # Network CIDR Location:
      AccessLocation:
        default: Network CIDR for Routing and Access

Parameters:
  # Appliance VPC Parameters:
  ApplianceVpcId:
    Description: Appliance VPC ID
    Type: String
    ConstraintDescription: Must be a valid VPC ID  
  ApplianceVpcTgwAttachSubnet1Id:
    Description: Appliance VPC Subnet1 ID for TGW attachment in AZ1
    Type: String
    ConstraintDescription: Must be a valid Subnet ID    
  ApplianceVpcTgwAttachSubnet2Id:
    Description: Appliance VPC Subnet2 ID for TGW attachment in AZ2
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  ApplianceVpcApplianceRtb1Id:
    Description: Appliance VPC Appliance Route Table 1 ID
    Type: String
    ConstraintDescription: Must be a valid Route Table ID    
  ApplianceVpcApplianceRtb2Id:
    Description: Appliance VPC Appliance Route Table 2 ID
    Type: String
    ConstraintDescription: Must be a valid Route Table ID     
  # Spoke1 VPC Parameters:
  Spoke1VpcId:
    Description: Spoke1 VPC ID
    Type: String
    ConstraintDescription: Must be a valid VPC ID
  Spoke1VpcCidr:
    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]))$"
    Default: 10.0.0.0/24
    Description: Spoke1 VPC Network CIDR
    Type: String
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/y   
  Spoke1VpcTgwAttachSubnet1Id:
    Description: Spoke1 VPC Subnet1 ID for TGW attachment in AZ1
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  Spoke1VpcTgwAttachSubnet2Id:
    Description: Spoke1 VPC Subnet2 ID for TGW attachment in AZ2
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  Spoke1VpcRtb1Id:
    Description: Spoke1 VPC Application Route Table ID
    Type: String
    ConstraintDescription: Must be a valid Route Table ID
  # Spoke2 VPC Parameters:
  Spoke2VpcId:
    Description: Spoke2 VPC ID
    Type: String
    ConstraintDescription: Must be a valid VPC ID
  Spoke2VpcCidr:
    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]))$"
    Default: 10.0.1.0/24
    Description: Spoke2 VPC Network CIDR
    Type: String
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/y  
  Spoke2VpcTgwAttachSubnet1Id:
    Description: Spoke2 VPC Subnet1 ID for TGW attachment in AZ1
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  Spoke2VpcTgwAttachSubnet2Id:
    Description: Spoke2 VPC Subnet2 ID for TGW attachment in AZ2
    Type: String
    ConstraintDescription: Must be a valid Subnet ID  
  Spoke2VpcRtb1Id:
    Description: Spoke2 VPC Application Route Table ID
    Type: String
    ConstraintDescription: Must be a valid Route Table ID  
  # Network CIDR Parameter:    
  AccessLocation:
    Description: >-
      Enter desired Network CIDR to access Bastion Host. Default is set to
      access from anywhere (0.0.0.0/0) and it is not recommended
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    MinLength: "9"
    MaxLength: "18"
    Default: 0.0.0.0/0
    Type: String
    ConstraintDescription: Must be a valid Network CIDR of the form x.x.x.x/y

Resources:
# Create Transit Gateway:
  Tgw1:
    Type: AWS::EC2::TransitGateway
    Properties:
      AmazonSideAsn: 64512
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: disable
      DefaultRouteTablePropagation: disable
      Description: Transit Gateway 1 for GWLB Centralized Architecture
      DnsSupport: enable
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-tgw-1"
      VpnEcmpSupport: enable

# Create Transit Gateway Attachments:
  Tgw1ApplianceVpcAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref ApplianceVpcTgwAttachSubnet1Id
        - !Ref ApplianceVpcTgwAttachSubnet2Id
      TransitGatewayId: !Ref Tgw1
      VpcId: !Ref ApplianceVpcId
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-appliance-vpc-attachment"

  Tgw1Spoke1VpcAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref Spoke1VpcTgwAttachSubnet1Id
        - !Ref Spoke1VpcTgwAttachSubnet2Id
      TransitGatewayId: !Ref Tgw1
      VpcId: !Ref Spoke1VpcId
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-spoke1-vpc-attachment"

  Tgw1Spoke2VpcAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref Spoke2VpcTgwAttachSubnet1Id
        - !Ref Spoke2VpcTgwAttachSubnet2Id
      TransitGatewayId: !Ref Tgw1
      VpcId: !Ref Spoke2VpcId
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-spoke2-vpc-attachment"

# Create Transit Gateway Route Tables:
  Tgw1TransitRtb:
    Type: AWS::EC2::TransitGatewayRouteTable
    Properties: 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-tgw-transit-rtb"   
      TransitGatewayId: !Ref Tgw1

  Tgw1EgressRtb:
    Type: AWS::EC2::TransitGatewayRouteTable
    Properties: 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-tgw-egress-rtb"
      TransitGatewayId: !Ref Tgw1

# Create Transit Gateway Attachment Associations:
  Tgw1ApplianceVpcAttachmentAssociation:
    Type: AWS::EC2::TransitGatewayRouteTableAssociation
    Properties: 
      TransitGatewayAttachmentId: !Ref Tgw1ApplianceVpcAttachment
      TransitGatewayRouteTableId: !Ref Tgw1TransitRtb

  Tgw1Spoke1VpcAttachmentAssociation:
    Type: AWS::EC2::TransitGatewayRouteTableAssociation
    Properties: 
      TransitGatewayAttachmentId: !Ref Tgw1Spoke1VpcAttachment
      TransitGatewayRouteTableId: !Ref Tgw1EgressRtb

  Tgw1Spoke2VpcAttachmentAssociation:
    Type: AWS::EC2::TransitGatewayRouteTableAssociation
    Properties: 
      TransitGatewayAttachmentId: !Ref Tgw1Spoke2VpcAttachment
      TransitGatewayRouteTableId: !Ref Tgw1EgressRtb      

# Create Transit Gateway Routes:
  Tgw1Route1:
    Type: AWS::EC2::TransitGatewayRoute
    Properties:
      TransitGatewayAttachmentId: !Ref Tgw1Spoke1VpcAttachment
      DestinationCidrBlock: !Ref Spoke1VpcCidr
      TransitGatewayRouteTableId: !Ref Tgw1TransitRtb

  Tgw1Route2:
    Type: AWS::EC2::TransitGatewayRoute
    Properties:
      TransitGatewayAttachmentId: !Ref Tgw1Spoke2VpcAttachment
      DestinationCidrBlock: !Ref Spoke2VpcCidr
      TransitGatewayRouteTableId: !Ref Tgw1TransitRtb

  Tgw1Route3:
    Type: AWS::EC2::TransitGatewayRoute
    Properties:
      TransitGatewayAttachmentId: !Ref Tgw1ApplianceVpcAttachment
      DestinationCidrBlock: !Ref AccessLocation
      TransitGatewayRouteTableId: !Ref Tgw1EgressRtb

# Add TGW as Target to VPC Route Tables:
  # Appliance VPC route table configuration:
  # AZ1:
  AddRoute1ApplianceVpc:
    DependsOn:
      - Tgw1
      - Tgw1ApplianceVpcAttachment     
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref Spoke1VpcCidr
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref ApplianceVpcApplianceRtb1Id

  AddRoute2ApplianceVpc:
    DependsOn: [Tgw1, Tgw1ApplianceVpcAttachment]  
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref Spoke2VpcCidr
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref ApplianceVpcApplianceRtb1Id
  # AZ2:
  AddRoute3ApplianceVpc:
    DependsOn: [Tgw1, Tgw1ApplianceVpcAttachment] 
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref Spoke1VpcCidr
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref ApplianceVpcApplianceRtb2Id

  AddRoute4ApplianceVpc:
    DependsOn: [Tgw1, Tgw1ApplianceVpcAttachment] 
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref Spoke2VpcCidr
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref ApplianceVpcApplianceRtb2Id  
  
  # Spoke1 VPC route table configuration:
  AddRoute1Spoke1Vpc:
    DependsOn: [Tgw1, Tgw1Spoke1VpcAttachment]
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref AccessLocation
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref Spoke1VpcRtb1Id 

  # Spoke2 VPC route table configuration:
  AddRoute1Spoke2Vpc:
    DependsOn: [Tgw1, Tgw1Spoke1VpcAttachment]
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: !Ref AccessLocation
      TransitGatewayId: !Ref Tgw1
      RouteTableId: !Ref Spoke2VpcRtb1Id

# To ensure flow symmetry, Transit Gateway appliance mode is enabled on the Inspection VPC’s attachment.
# For more details on Transit Gateway appliance mode, refer to:
# https://aws.amazon.com/blogs/networking-and-content-delivery/centralized-inspection-architecture-with-aws-gateway-load-balancer-and-aws-transit-gateway/
# https://docs.aws.amazon.com/vpc/latest/tgw/transit-gateway-appliance-scenario.html
# CloudFormation yet does not support enabling appliance mode. Hence need to enable it using Lambda custom resource:

# Transit Gateway appliance mode Lambda Role:
  TgwLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



