Creating AWS Transit Gateway with CloudFormation ~intra-region and inter-region
Published: 2023-08-28 05:45:27

## The first thing I want to tell you
Some of the screenshots in this article are in my native language, Japanese.

However, it is my opinion that if the order is followed, there will be no significant difference in the indications.

I hope this article will be of help to you.

## What is TransitGateway?
>Transit Gateway is a network relay hub that can be used to interconnect virtual private clouds (VPC) and on-premise networks.

For more information about TransitGateway, please refer to [official documentation](https://docs.aws.amazon.com/ja_jp/vpc/latest/tgw/what-is-transit-gateway.html).

## Preface

This article does not go into setting up dynamic propagation and account crossing.

## ① Between different VPCs in the same region

Ping is sent between two VPCs in the same region via TransitGateway to check the communication between the EC2s on the private side.

### configuration diagram

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v4ya1aus2bu0gjr847bh.png)

### Template
```YAML
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  PJPrefix: # 
    Type: String

  Environment:
    Type: String
    Default: prd

# for VPC1
  VPC1CidrBlock: 
    Type: String
    Default: 10.1.0.0/16

  VPC1PrivateSubnetForEC2CidrBlock:
    Type: String
    Default: 10.1.0.0/24

  VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock:
    Type: String
    Default: 10.1.1.0/28

# for VPC2
  VPC2CidrBlock:
    Type: String
    Default:  10.2.0.0/16

  VPC2PrivateSubnetForEC2CidrBlock: 
    Type: String
    Default:  10.2.0.0/24

  VPC2PrivateSubnetForTransitGatewayAttachmentCidrBlock: 
    Type: String
    Default:  10.2.1.0/28

  ImageId: 
    Type: String
    Default: ami-079a2a9ac6ed876fc

  InstanceType: 
    Type: String
    Default: t2.micro

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
  TransitGateway:
    Type: AWS::EC2::TransitGateway
    Properties:
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: enable
      DefaultRouteTablePropagation: enable
      VpnEcmpSupport: enable
      DnsSupport: enable
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgateway

# for VPC1
  VPC1TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC1PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGateway
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc1

# for VPC2
  VPC2TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC2PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGateway
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc2
  # ------------------------------------------------------------#
  # VPC
  # ------------------------------------------------------------#
# for VPC1
  VPC1:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPC1CidrBlock
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-vpc1

# for VPC2
  VPC2:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPC2CidrBlock
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-vpc2
  # ------------------------------------------------------------#
  # Subnet
  # ------------------------------------------------------------#
# for VPC1
  VPC1PrivateSubnetForEC2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC1PrivateSubnetForEC2CidrBlock
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc1forec2

  VPC1PrivateSubnetForTransitGatewayAttachment:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc1forec2transitgatewayattachment

# for VPC2
  VPC2PrivateSubnetForEC2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC2PrivateSubnetForEC2CidrBlock
      VpcId: !Ref VPC2
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc2forec2

  VPC2PrivateSubnetForTransitGatewayAttachment:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC2PrivateSubnetForTransitGatewayAttachmentCidrBlock
      VpcId: !Ref VPC2
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc2forec2transitgatewayattachment
  # ------------------------------------------------------------#
  # VPCEndpoint
  # ------------------------------------------------------------#
# for VPC1
  VPC1VPCEndpointSSM:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC1VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref VPC1PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC1

  VPC1VPCEndpointSSMMessages:  
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC1VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref VPC1PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC1

  VPC1VPCEndpointEC2Messages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC1VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref VPC1PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC1

  VPC1VPCEndpointS3:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref VPC1PrivateSubnetForEC2RouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref VPC1

# for VPC2
  VPC2VPCEndpointSSM:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC2VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref VPC2PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC2

  VPC2VPCEndpointSSMMessages:  
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC2VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref VPC2PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC2

  VPC2VPCEndpointEC2Messages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC2VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref VPC2PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC2

  VPC2VPCEndpointS3:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref VPC2PrivateSubnetForEC2RouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref VPC2

  # ------------------------------------------------------------#
  # RouteTable
  # ------------------------------------------------------------#
# for VPC1
  # PrivateSubnetForEC2
  VPC1PrivateSubnetForEC2RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-routetable-vpc1privatesubnetforec2

  VPC1PrivateSubnetForEC2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref VPC1PrivateSubnetForEC2
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable

  VPC1TransitGatewayRoute:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref VPC2CidrBlock
      TransitGatewayId: !Ref TransitGateway

# for VPC2
  # PrivateSubnetForEC2
  VPC2PrivateSubnetForEC2RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-routetable--vpc2privatesubnetforec2

  VPC2PrivateSubnetForEC2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref VPC2PrivateSubnetForEC2
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable

  VPC2TransitGatewayRoute:
    Type: AWS::EC2::Route
    DependsOn: VPC2TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref VPC1CidrBlock
      TransitGatewayId: !Ref TransitGateway

  # ------------------------------------------------------------#
  # EC2
  # ------------------------------------------------------------#
# for VPC1
  VPC1EC2:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref EC2InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref VPC1PrivateSubnetForEC2
          GroupSet:
            - !Ref VPC1EC2SecurityGroup

# for VPC2
  VPC2EC2:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref EC2InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref VPC2PrivateSubnetForEC2
          GroupSet:
            - !Ref VPC2EC2SecurityGroup
  # ------------------------------------------------------------#
  # IAM
  # ------------------------------------------------------------#
# Role
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

# InstanceProfile
  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref EC2Role
  # ------------------------------------------------------------#
  # SecurityGroup
  # ------------------------------------------------------------#
# for VPC1
  # SecurityGroup
  VPC1VPCEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC1
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc1
      GroupDescription: for VPCE
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc1

  # Ingress
  VPC1VPCEndpointSecurityGroupIngressEC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: 443
      ToPort: 443
      IpProtocol: tcp
      SourceSecurityGroupId: !Ref VPC1EC2SecurityGroup
      GroupId: !GetAtt VPC1VPCEndpointSecurityGroup.GroupId

# SecurityGroup
  VPC1EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: VPC1EC2SecurityGroup
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc1ec2
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc1ec2

  # Ingress
  VPC1EC2SecurityGroupIngressforPing:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC2CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId

# for VPC2
  # SecurityGroup
  VPC2VPCEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC2
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc2
      GroupDescription: for VPCE
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc2

  # Ingress
  VPC2VPCEndpointSecurityGroupIngressEC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: 443
      ToPort: 443
      IpProtocol: tcp
      SourceSecurityGroupId: !Ref VPC2EC2SecurityGroup
      GroupId: !GetAtt VPC2VPCEndpointSecurityGroup.GroupId

# SecurityGroup
  VPC2EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: VPC2EC2SecurityGroup
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc2ec2
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc2ec2

  # Ingress
  VPC2EC2SecurityGroupIngressforPing:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC1CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId
```
### Check the management console

Check the results.

#### TransitGateway (VPC) Console

TransitGateway
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vqsf2oygxwqqifc0amtw.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qdwvbm3x4vvnncvukeu5.png)


TransitGateway Attachment

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/itqd6vtlbojq4945vzzh.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qjt5ejuza6vk8bwoj9d9.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rnvpb6uzb84bmiz3977q.png)

TransitGateway Route Table

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qsvmrufc6loppgtva26a.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xs1gnpcepejmaltdw2en.png)

- association
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wqxf5qrajx2lq8f43sdh.png)

- attachment
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hhdyeq0j1qyljwtpo5nz.png)

- Route
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9f0h2elsw2176uflbz7w.png)

#### Ping between EC2

Ping from each instance.

VPC1 to VPC2

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hfz022plgy91e432tyyw.png)

VPC2 to VPC1
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8eqv1kq4yhx10cmgiqmi.png)

I was able to confirm the communication successfully.

## ②Inter-Region Peering

Next, let's check the EC2 communication between the Tokyo region and the Northern Virginia region.

Although it would be fine to use one VPC for each, this time we will create the environment in ① in each of the four EC2s in the respective regions to ensure communication between the four EC2s.

### configuration diagram

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjr4vzu302vltjdhg3uy.png)

#### 1stRegion.yml
```YAML
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  PJPrefix:
    Type: String

  Environment: 
    Type: String
    Default: prd

  # for VPC1
  VPC1CidrBlock: 
    Type: String
    Default: 10.1.0.0/16

  VPC1PrivateSubnetForEC2CidrBlock: 
    Type: String
    Default: 10.1.0.0/24

  VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock:
    Type: String
    Default: 10.1.1.0/28

  # for VPC2
  VPC2CidrBlock: 
    Type: String
    Default:  10.2.0.0/16

  VPC2PrivateSubnetForEC2CidrBlock: 
    Type: String
    Default:  10.2.0.0/24

  VPC2PrivateSubnetForTransitGatewayAttachmentCidrBlock:
    Type: String
    Default:  10.2.1.0/28

  # for Both EC2
  ImageId: 
    Type: String
    Default: ami-079a2a9ac6ed876fc

  InstanceType: 
    Type: String
    Default: t2.micro

# for 2ndRegion
  # for VPC1
  2ndRegionVPC1CidrBlock: 
    Type: String
    Default: 10.3.0.0/16

  # for VPC2
  2ndRegionVPC2CidrBlock: 
    Type: String
    Default:  10.4.0.0/16

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
  TransitGateway:
    Type: AWS::EC2::TransitGateway
    Properties:
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: enable
      DefaultRouteTablePropagation: enable
      VpnEcmpSupport: enable
      DnsSupport: enable
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgateway

# for VPC1
  VPC1TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC1PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGateway
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc1

# for VPC2
  VPC2TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC2PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGateway
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc2
  # ------------------------------------------------------------#
  # VPC
  # ------------------------------------------------------------#
# for VPC1
  VPC1:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPC1CidrBlock
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-vpc1

# for VPC2
  VPC2:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPC2CidrBlock
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-vpc2
  # ------------------------------------------------------------#
  # Subnet
  # ------------------------------------------------------------#
# for VPC1
  VPC1PrivateSubnetForEC2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC1PrivateSubnetForEC2CidrBlock
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc1forec2

  VPC1PrivateSubnetForTransitGatewayAttachment:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc1forec2transitgatewayattachment

# for VPC2
  VPC2PrivateSubnetForEC2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC2PrivateSubnetForEC2CidrBlock
      VpcId: !Ref VPC2
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc2forec2

  VPC2PrivateSubnetForTransitGatewayAttachment:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC2PrivateSubnetForTransitGatewayAttachmentCidrBlock
      VpcId: !Ref VPC2
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc2forec2transitgatewayattachment
  # ------------------------------------------------------------#
  # VPCEndpoint
  # ------------------------------------------------------------#
# for VPC1
  VPC1VPCEndpointSSM:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC1VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref VPC1PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC1

  VPC1VPCEndpointSSMMessages:  
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC1VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref VPC1PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC1

  VPC1VPCEndpointEC2Messages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC1VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref VPC1PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC1

  VPC1VPCEndpointS3:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref VPC1PrivateSubnetForEC2RouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref VPC1

# for VPC2
  VPC2VPCEndpointSSM:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC2VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref VPC2PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC2

  VPC2VPCEndpointSSMMessages:  
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC2VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref VPC2PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC2

  VPC2VPCEndpointEC2Messages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC2VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref VPC2PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC2

  VPC2VPCEndpointS3:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref VPC2PrivateSubnetForEC2RouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref VPC2

  # ------------------------------------------------------------#
  # RouteTable
  # ------------------------------------------------------------#
# for VPC1
  # PrivateSubnetForEC2
  VPC1PrivateSubnetForEC2RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-routetable-vpc1privatesubnetforec2

  VPC1PrivateSubnetForEC2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref VPC1PrivateSubnetForEC2
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable

  VPC1TransitGatewayRoute:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref VPC2CidrBlock
      TransitGatewayId: !Ref TransitGateway

  VPC1TransitGatewayRoutefor2ndRegionVPC1:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 2ndRegionVPC1CidrBlock
      TransitGatewayId: !Ref TransitGateway

  VPC1TransitGatewayRoutefor2ndRegionVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 2ndRegionVPC2CidrBlock
      TransitGatewayId: !Ref TransitGateway

# for VPC2
  # PrivateSubnetForEC2
  VPC2PrivateSubnetForEC2RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-routetable-vpc2privatesubnetforec2

  VPC2PrivateSubnetForEC2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref VPC2PrivateSubnetForEC2
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable

  VPC2TransitGatewayRoute:
    Type: AWS::EC2::Route
    DependsOn: VPC2TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref VPC1CidrBlock
      TransitGatewayId: !Ref TransitGateway

  VPC2TransitGatewayRoutefor2ndRegionVPC1:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 2ndRegionVPC1CidrBlock
      TransitGatewayId: !Ref TransitGateway

  VPC2TransitGatewayRoutefor2ndRegionVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 2ndRegionVPC2CidrBlock
      TransitGatewayId: !Ref TransitGateway

  # ------------------------------------------------------------#
  # EC2
  # ------------------------------------------------------------#
# for VPC1
  VPC1EC2:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref EC2InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref VPC1PrivateSubnetForEC2
          GroupSet:
            - !Ref VPC1EC2SecurityGroup

# for VPC2
  VPC2EC2:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref EC2InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref VPC2PrivateSubnetForEC2
          GroupSet:
            - !Ref VPC2EC2SecurityGroup
  # ------------------------------------------------------------#
  # IAM
  # ------------------------------------------------------------#
# Role
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

# InstanceProfile
  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref EC2Role
  # ------------------------------------------------------------#
  # SecurityGroup
  # ------------------------------------------------------------#
# for VPC1
  # SecurityGroup
  VPC1VPCEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC1
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc1
      GroupDescription: for VPCE
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc1

  # Ingress
  VPC1VPCEndpointSecurityGroupIngressEC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: 443
      ToPort: 443
      IpProtocol: tcp
      SourceSecurityGroupId: !Ref VPC1EC2SecurityGroup
      GroupId: !GetAtt VPC1VPCEndpointSecurityGroup.GroupId
  #------------------------------------------------------------#
  # SecurityGroup
  VPC1EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: VPC1EC2SecurityGroup
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc1ec2
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc1ec2

  # Ingress
  VPC1EC2SecurityGroupIngressFromSameRegionVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC2CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId

  VPC1EC2SecurityGroupIngressFrom2ndRegionVPC1EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 2ndRegionVPC1CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId

  VPC1EC2SecurityGroupIngressFrom2ndRegionVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 2ndRegionVPC2CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId
  #------------------------------------------------------------#
# for VPC2
  # SecurityGroup
  VPC2VPCEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC2
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc2
      GroupDescription: for VPCE
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc2

  # Ingress
  VPC2VPCEndpointSecurityGroupIngressEC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: 443
      ToPort: 443
      IpProtocol: tcp
      SourceSecurityGroupId: !Ref VPC2EC2SecurityGroup
      GroupId: !GetAtt VPC2VPCEndpointSecurityGroup.GroupId
  #------------------------------------------------------------#
  # SecurityGroup
  VPC2EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: VPC2EC2SecurityGroup
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc2ec2
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc2ec2

  # Ingress
  VPC2EC2SecurityGroupIngressFromSameRegionVPC1EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC1CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId

  VPC2EC2SecurityGroupIngressFrom2ndRegionVPC1EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 2ndRegionVPC1CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId

  VPC2EC2SecurityGroupIngressFrom2ndRegionVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 2ndRegionVPC2CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId

Outputs:
  PeerRegion:
    Value: !Ref AWS::Region

  PeerTransitGatewayId:
    Value: !Ref TransitGateway
```
↓
#### 2ndRegion.yml

*Please use the same name output value x 2 in the 1stRegion.yml stack in the Parameter input screen.

```YAML
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  PJPrefix:
    Type: String

  Environment:
    Type: String
    Default: prd

# for VPC1
  VPC1CidrBlock: # VPC1のCIDRブロック
    Type: String
    Default: 10.3.0.0/16

  VPC1PrivateSubnetForEC2CidrBlock: 
    Type: String
    Default: 10.3.0.0/24

  VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock:
    Type: String
    Default: 10.3.1.0/28

# for VPC2
  VPC2CidrBlock: 
    Type: String
    Default:  10.4.0.0/16

  VPC2PrivateSubnetForEC2CidrBlock:
    Type: String
    Default:  10.4.0.0/24

  VPC2PrivateSubnetForTransitGatewayAttachmentCidrBlock: 
    Type: String
    Default:  10.4.1.0/28

  # for Both EC2
  ImageId: 
    Type: String
    Default: ami-06e46074ae430fba6

  InstanceType: 
    Type: String
    Default: t2.micro

# for 1stRegion
  # for VPC1
  1stRegionVPC1CidrBlock: 
    Type: String
    Default: 10.1.0.0/16

  # for VPC2
  1stRegionVPC2CidrBlock: 
    Type: String
    Default:  10.2.0.0/16

  PeerRegion: 
    Type: String

  PeerTransitGatewayId: 
    Type: String

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
  TransitGateway:
    Type: AWS::EC2::TransitGateway
    Properties:
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: enable
      DefaultRouteTablePropagation: enable
      VpnEcmpSupport: enable
      DnsSupport: enable
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgateway

# for VPC1
  VPC1TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC1PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGateway
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc1

# for VPC2
  VPC2TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC2PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGateway
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc2

  TransitGatewayPeeringAttachment:
    Type: AWS::EC2::TransitGatewayPeeringAttachment
    Properties:
      PeerAccountId: !Ref AWS::AccountId
      PeerRegion: !Ref PeerRegion
      PeerTransitGatewayId: !Ref PeerTransitGatewayId
      TransitGatewayId: !Ref TransitGateway
  # ------------------------------------------------------------#
  # VPC
  # ------------------------------------------------------------#
# for VPC1
  VPC1:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPC1CidrBlock
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-vpc1

# for VPC2
  VPC2:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPC2CidrBlock
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-vpc2
  # ------------------------------------------------------------#
  # Subnet
  # ------------------------------------------------------------#
# for VPC1
  VPC1PrivateSubnetForEC2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC1PrivateSubnetForEC2CidrBlock
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc1forec2

  VPC1PrivateSubnetForTransitGatewayAttachment:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc1forec2transitgatewayattachment

# for VPC2
  VPC2PrivateSubnetForEC2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC2PrivateSubnetForEC2CidrBlock
      VpcId: !Ref VPC2
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc2forec2

  VPC2PrivateSubnetForTransitGatewayAttachment:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VPC2PrivateSubnetForTransitGatewayAttachmentCidrBlock
      VpcId: !Ref VPC2
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-subnet-private-vpc2forec2transitgatewayattachment
  # ------------------------------------------------------------#
  # VPCEndpoint
  # ------------------------------------------------------------#
# for VPC1
  VPC1VPCEndpointSSM:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC1VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref VPC1PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC1

  VPC1VPCEndpointSSMMessages:  
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC1VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref VPC1PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC1

  VPC1VPCEndpointEC2Messages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC1VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref VPC1PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC1

  VPC1VPCEndpointS3:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref VPC1PrivateSubnetForEC2RouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref VPC1

# for VPC2
  VPC2VPCEndpointSSM:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC2VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref VPC2PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC2

  VPC2VPCEndpointSSMMessages:  
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC2VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref VPC2PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC2

  VPC2VPCEndpointEC2Messages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref VPC2VPCEndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref VPC2PrivateSubnetForEC2
      VpcEndpointType: Interface
      VpcId: !Ref VPC2

  VPC2VPCEndpointS3:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref VPC2PrivateSubnetForEC2RouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref VPC2

  # ------------------------------------------------------------#
  # RouteTable
  # ------------------------------------------------------------#
# for VPC1
  # PrivateSubnetForEC2
  VPC1PrivateSubnetForEC2RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-routetable-vpc1privatesubnetforec2

  VPC1PrivateSubnetForEC2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref VPC1PrivateSubnetForEC2
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable

  VPC1TransitGatewayRouteforSameRegionVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref VPC2CidrBlock
      TransitGatewayId: !Ref TransitGateway

  VPC1TransitGatewayRoutefor1stRegionVPC1:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 1stRegionVPC1CidrBlock
      TransitGatewayId: !Ref TransitGateway

  VPC1TransitGatewayRoutefor1stRegionVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 1stRegionVPC2CidrBlock
      TransitGatewayId: !Ref TransitGateway

# for VPC2
  # PrivateSubnetForEC2
  VPC2PrivateSubnetForEC2RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-routetable-vpc2privatesubnetforec2

  VPC2PrivateSubnetForEC2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref VPC2PrivateSubnetForEC2
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable

  VPC2TransitGatewayRouteforSameRegionVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC2TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref VPC1CidrBlock
      TransitGatewayId: !Ref TransitGateway

  VPC2TransitGatewayRoutefor1stRegionVPC1:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 1stRegionVPC1CidrBlock
      TransitGatewayId: !Ref TransitGateway

  VPC2TransitGatewayRoutefor1stRegionVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 1stRegionVPC2CidrBlock
      TransitGatewayId: !Ref TransitGateway

  # ------------------------------------------------------------#
  # EC2
  # ------------------------------------------------------------#
# for VPC1
  VPC1EC2:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref EC2InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref VPC1PrivateSubnetForEC2
          GroupSet:
            - !Ref VPC1EC2SecurityGroup

# for VPC2
  VPC2EC2:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref EC2InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref VPC2PrivateSubnetForEC2
          GroupSet:
            - !Ref VPC2EC2SecurityGroup
  # ------------------------------------------------------------#
  # IAM
  # ------------------------------------------------------------#
# Role
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

# InstanceProfile
  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref EC2Role
  # ------------------------------------------------------------#
  # SecurityGroup
  # ------------------------------------------------------------#
# for VPC1
  # SecurityGroup
  VPC1VPCEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC1
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc1
      GroupDescription: for VPCE
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc1

  # Ingress
  VPC1VPCEndpointSecurityGroupIngressEC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: 443
      ToPort: 443
      IpProtocol: tcp
      SourceSecurityGroupId: !Ref VPC1EC2SecurityGroup
      GroupId: !GetAtt VPC1VPCEndpointSecurityGroup.GroupId
  #------------------------------------------------------------#
  # SecurityGroup
  VPC1EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: VPC1EC2SecurityGroup
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc1ec2
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc1ec2

  # Ingress
  VPC1EC2SecurityGroupIngressFromSameRegionVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC2CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId

  VPC1EC2SecurityGroupIngressFrom1atRegionVPC1EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 1stRegionVPC1CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId

  VPC1EC2SecurityGroupIngressFrom1stRegionVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 1stRegionVPC2CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId
  #------------------------------------------------------------#
# for VPC2
  # SecurityGroup
  VPC2VPCEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC2
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc2
      GroupDescription: for VPCE
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpcendpoint-vpc2

  # Ingress
  VPC2VPCEndpointSecurityGroupIngressEC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: 443
      ToPort: 443
      IpProtocol: tcp
      SourceSecurityGroupId: !Ref VPC2EC2SecurityGroup
      GroupId: !GetAtt VPC2VPCEndpointSecurityGroup.GroupId
  #------------------------------------------------------------#
  # SecurityGroup
  VPC2EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: VPC2EC2SecurityGroup
      GroupName: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc2ec2
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-securitygroup-vpc2ec2

  # Ingress
  VPC2EC2SecurityGroupIngressFromSameRegionVPC1EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC1CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId

  VPC2EC2SecurityGroupIngressFrom1atRegionVPC1EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 1stRegionVPC1CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId

  VPC2EC2SecurityGroupIngressFrom1stRegionVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 1stRegionVPC2CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId

Outputs:
  TransitGatewayPeeringAttachment:
    Value: !Ref TransitGatewayPeeringAttachment
    Export:
      Name: TransitGatewayPeeringAttachment
```
↓
#### Accept peering from the console
Check the Transit Gateway Attachment,
Transit Gateway Attachment", you can see the resource with the status: Pending Acceptance.

- us-east-1

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6pavnjv3re5au81wy2mx.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oymsfcq3hmx7kty9cc6t.png)

- ap-northeast-1

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pq8l8b4za17rkbfnccrj.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jy3ej26fq17fdnv6egmn.png)

We can confirm that the requestor and acceptor are each in the region of the setting.
↓
Click "Accept TransitGateway Attachment" from "Action" of the relevant attachment in the acceptor region, ap-northeast-1.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/be5qr4a1lfr0wrj888fo.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sg90109tlw72rkt08hjr.png)
↓
Each of them changes to Status:Pending, wait for a few minutes, and then
↓
- us-east-1
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owq57eozx4pjvgya3150.png)

- ap-northeast-1
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1m37htnppbo4kkn08h7.png)

Status:Available

↓

### Additional Templates
#### 1stRegionTransitRoute.yml
In the Parameter entry screen, for AutoCreatedTransitGatewayRouteTableId, enter the unnamed (*Name: "-") Transit Gateway Route Table ID that was automatically created in the 1stRegion, and for Transi TransitGatewayPeeringAttachment should be the output value of the same name from the 2ndRegion.yml stack.

```YAML
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  2ndRegionVPC1CidrBlock:
    Type: String
    Default: 10.3.0.0/16

  2ndRegionVPC2CidrBlock:
    Type: String
    Default: 10.4.0.0/16

  TransitGatewayPeeringAttachment: # Refer to the homonymous output value of the 2nd region stack
    Type: String
  
  AutoCreatedTransitGatewayRouteTableId:
    Type: String

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
  TransitGatewayRouteFor2ndRegionVPC1:
    Type: AWS::EC2::TransitGatewayRoute
    Properties: 
      Blackhole: false
      DestinationCidrBlock: !Ref 2ndRegionVPC1CidrBlock
      TransitGatewayAttachmentId: !Ref TransitGatewayPeeringAttachment
      TransitGatewayRouteTableId: !Ref AutoCreatedTransitGatewayRouteTableId

  TransitGatewayRouteFor2ndRegionVPC2:
    Type: AWS::EC2::TransitGatewayRoute
    Properties: 
      Blackhole: false
      DestinationCidrBlock: !Ref 2ndRegionVPC2CidrBlock
      TransitGatewayAttachmentId: !Ref TransitGatewayPeeringAttachment
      TransitGatewayRouteTableId: !Ref AutoCreatedTransitGatewayRouteTableId
```
↓
#### 2ndRegionTransitRoute.yml
In the Parameter entry screen, enter an unnamed (*Name: "-") Transit Gateway route table ID automatically created in the 2ndRegion in the AutoCreatedTransitGatewayRouteTableId field.
```YAML
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  1stResionVPC1CidrBlock:
    Type: String
    Default: 10.1.0.0/16

  1stResionVPC2CidrBlock:
    Type: String
    Default: 10.2.0.0/16

  AutoCreatedTransitGatewayRouteTableId:
    Type: String

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
  TransitGatewayRouteFor1stResionVPC1:
    Type: AWS::EC2::TransitGatewayRoute
    Properties: 
      Blackhole: false
      DestinationCidrBlock: !Ref 1stResionVPC1CidrBlock
      TransitGatewayAttachmentId: !ImportValue TransitGatewayPeeringAttachment
      TransitGatewayRouteTableId: !Ref AutoCreatedTransitGatewayRouteTableId

  TransitGatewayRouteFor1stResionVPC2:
    Type: AWS::EC2::TransitGatewayRoute
    Properties: 
      Blackhole: false
      DestinationCidrBlock: !Ref 1stResionVPC2CidrBlock
      TransitGatewayAttachmentId: !ImportValue TransitGatewayPeeringAttachment
      TransitGatewayRouteTableId: !Ref AutoCreatedTransitGatewayRouteTableId
```

### Ping between EC2
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b9439ffffiid64g11hni.png)
Although only one image is shown, we were able to confirm communication in all instances.

## extra
While searching for the reason why the ping did not go through in the Inter-Region example, I made the common mistake of mistaking one letter in the logical ID that I had used in the SecurityGroupIngress! During the process, I came across the TGW Route Analyzer.

[TGW Route Analyzer](https://docs.aws.amazon.com/network-manager/latest/tgwnm/route-analyzer.html)

Thanks to this feature, I realized, "If there is no problem here, it may be a mistake in the SecurityGroup setting.

### How to use TGW Route Analyzer

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oekj676gvq15adncizwt.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/scwvxsekan1bjtvfq0v0.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/na627ifdfzqsoyg4e614.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xj9ptk1nysaxv6lnvxv1.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/glngp5ptdmgxyt317ugj.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qyfwegq4p80sxub3vdy8.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fo5x7q6rkt6iw3sia3ci.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vvt9zh9bj7llqebsvrez.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sxyju2c7dz25cvwxdz7x.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9763papxgdqo3y03tc6d.png)
↓
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6m6g1fdj6dvi9k4i84te.png)

### If you want to create it with a template
As shown below, "TransitGatewayRegistration" must be run on a stack in each region or an error will occur.

#### 1stRegion_GlobalNetwork_and_TransitGatewayRegistration.yml

```YAML
AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

  TransitGatewayId:
    Type: String

Resources: 
  # ------------------------------------------------------------#
  # NetworkManager
  # ------------------------------------------------------------#
  # GlobalNetwork
  GlobalNetwork:
    Type: AWS::NetworkManager::GlobalNetwork
    Properties: 
      Description: this is test.
      Tags:
        - Key: Name
          Value: test-globalnetwork

  # TransitGatewayRegistration
  TransitGatewayRegistration:
    Type: AWS::NetworkManager::TransitGatewayRegistration
    Properties: 
      GlobalNetworkId: !Ref GlobalNetwork
      TransitGatewayArn: !Sub arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:transit-gateway/${TransitGatewayId}

Outputs:
  GlobalNetworkId:
    Value: !Ref GlobalNetwork
```
↓
#### 2ndRegion_TransitGatewayRegistration.yml
```YAML
AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

  TransitGatewayId:
    Type: String

  GlobalNetworkId:
    Type: String

Resources: 
  # ------------------------------------------------------------#
  # NetworkManager
  # ------------------------------------------------------------#
  # TransitGatewayRegistration
  TransitGatewayRegistration:
    Type: AWS::NetworkManager::TransitGatewayRegistration
    Properties: 
      GlobalNetworkId: !Ref GlobalNetworkId
      TransitGatewayArn: !Sub arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:transit-gateway/${TransitGatewayId}
```

## That was all.

Thank you for reading.