DEV Community

Cover image for [CFn] Shared use of AWS Transit Gateway by multiple accounts with AWS Resource Access Manager
yushi kato/mjxo for AWS Community Builders

Posted on

[CFn] Shared use of AWS Transit Gateway by multiple accounts with AWS Resource Access Manager

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.

Create a TransitGateway that can be shared among accounts.

Previously, I submitted the following article.
Creating AWS Transit Gateway with CloudFormation ~intra-region and inter-region

This time, we would like to check the communication between instances across accounts.

① Create a Transit Gateway in Resource Access Manager with an intermediate account as owner, and connect to the attachment created for the two accounts (*Resource region is common).

configuration diagram

The following is what we will be creating, although it is a bit long to try to convey in words.

In the previous article, we communicated with 4 instances within the same region and between different regions, so this time we will try to communicate within the same region and between different accounts.

Image description

The middle tgw account is also ap-northeast-1, although it is omitted in the above figure.

advance preparation

▪ Create two test accounts from AWS Organizations. (so that there are 3 accounts in total)

*If you have trouble with the email address for account creation, we recommend Gmail's alias address feature.
Example: Own "hogehoge@gmail.com" -> "hogehoge+fuga@gmail.com" and "hogehoge+piyo@gmail.com" are available as alias addresses

By the way, in this case, to work across 3 accounts, I used Chrome, Safari, and Firefox to browse each for clarity.

Procedure

*All tgw accounts, account A, and account B should work in the same region.
*Ami is assumed to be ap-northeast-1, so if you are in a different region, please change the value of the "ImageId" parameter when you create each stack.

Run the following template on the account you want to use for tgw.

tgw_account.yml

AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

  PJPrefix: 
    Type: String

  Environment: 
    Type: String
    Default: prd

  AccountAId:
    Type: String

  AccountBId: 
    Type: String

Resources: 
  # ------------------------------------------------------------#
  # RAM
  # ------------------------------------------------------------#
  ResourceShare:
    Type: AWS::RAM::ResourceShare
    DependsOn: 
      - TransitGateway
    Properties: 
      Name: !Sub ${PJPrefix}-${Environment}-ram
      ResourceArns:
        - !Sub arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:transit-gateway/${TransitGateway}
      Principals:
        - !Ref AccountAId
        - !Ref AccountBId
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-ram
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
  TransitGateway:
    Type: AWS::EC2::TransitGateway
    Properties:
      AmazonSideAsn: 64512 # default value
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: enable
      DefaultRouteTablePropagation: enable
      DnsSupport: enable
      VpnEcmpSupport: enable
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgateway

Outputs:
  TransitGatewayId:
    Value: !Ref TransitGateway
Enter fullscreen mode Exit fullscreen mode


Go to the AWS Resource Access Manager (RAM) console of the account for tgw and you will see that the following is displayed under "I share: resource sharing". default value

Image description

Go to the RAM console for Account A and Account B, respectively, and perform the following operations.

What to do on the RAM console

Go to "Share with Me: Share Resources" and follow the steps below to approve resource sharing from your tgw account.

Image description

Image description

Image description

Image description

The tgw resource that could be found in the "Share with Me: Share Resources" section will disappear, and the same resource will be found in the "Share with Me: Share Resources" tab one tab down.

Image description

If this is confirmed, the approval has been successfully completed.
Image description

After the approval is completed in the A/B accounts, you will see that the status of "Shared Principal" is "Associated" in the tgw account as shown below.
Image description

account_a.yml

Run the following template on account A.

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 2ndAccount
  # for VPC1
  2ndAccountVPC1CidrBlock:
    Type: String
    Default: 10.3.0.0/16

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

  TransitGatewayId:
    Type: String

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
# for VPC1
  VPC1TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC1PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGatewayId
      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 TransitGatewayId
      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 TransitGatewayId

  VPC1TransitGatewayRoutefor2ndAccountVPC1:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 2ndAccountVPC1CidrBlock
      TransitGatewayId: !Ref TransitGatewayId

  VPC1TransitGatewayRoutefor2ndAccountVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 2ndAccountVPC2CidrBlock
      TransitGatewayId: !Ref TransitGatewayId

# 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 TransitGatewayId

  VPC2TransitGatewayRoutefor2ndAccountVPC1:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 2ndAccountVPC1CidrBlock
      TransitGatewayId: !Ref TransitGatewayId

  VPC2TransitGatewayRoutefor2ndAccountVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 2ndAccountVPC2CidrBlock
      TransitGatewayId: !Ref TransitGatewayId

  # ------------------------------------------------------------#
  # 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
  VPC1EC2SecurityGroupIngressFromSameAccountVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC2CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId

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

  VPC1EC2SecurityGroupIngressFrom2ndAccountVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 2ndAccountVPC2CidrBlock
      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
  VPC2EC2SecurityGroupIngressFromSameAccountVPC1EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC1CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId

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

  VPC2EC2SecurityGroupIngressFrom2ndAccountVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 2ndAccountVPC2CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId
Enter fullscreen mode Exit fullscreen mode

account_b.yml

Run the following template on account B.

AWSTemplateFormatVersion: 2010-09-09

Parameters:

  PJPrefix: 
    Type: String

  Environment: 
    Type: String
    Default: prd

# for VPC1
  VPC1CidrBlock: 
    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-079a2a9ac6ed876fc

  InstanceType: 
    Type: String
    Default: t2.micro

# for 1stAccount
  # for VPC1
  1stAccountVPC1CidrBlock: 
    Type: String
    Default: 10.1.0.0/16

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

  TransitGatewayId: 
    Type: String

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
# for VPC1
  VPC1TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC1PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGatewayId
      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 TransitGatewayId
      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

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

  VPC1TransitGatewayRoutefor1stAccountVPC1:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 1stAccountVPC1CidrBlock
      TransitGatewayId: !Ref TransitGatewayId

  VPC1TransitGatewayRoutefor1stAccountVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 1stAccountVPC2CidrBlock
      TransitGatewayId: !Ref TransitGatewayId

# 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

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

  VPC2TransitGatewayRoutefor1stAccountVPC1:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 1stAccountVPC1CidrBlock
      TransitGatewayId: !Ref TransitGatewayId

  VPC2TransitGatewayRoutefor1stAccountVPC2:
    Type: AWS::EC2::Route
    DependsOn: VPC1TransitGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC2PrivateSubnetForEC2RouteTable
      DestinationCidrBlock: !Ref 1stAccountVPC2CidrBlock
      TransitGatewayId: !Ref TransitGatewayId

  # ------------------------------------------------------------#
  # 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
  VPC1EC2SecurityGroupIngressFromSameAccountVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC2CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId

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

  VPC1EC2SecurityGroupIngressFrom1stAccountVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 1stAccountVPC2CidrBlock
      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
  VPC2EC2SecurityGroupIngressFromSameAccountVPC1EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref VPC1CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId

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

  VPC2EC2SecurityGroupIngressFrom1stAccountVPC2EC2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 1stAccountVPC2CidrBlock
      GroupId: !GetAtt VPC2EC2SecurityGroup.GroupId
Enter fullscreen mode Exit fullscreen mode

That is all.

Execute ping on the EC2 instance to confirm communication

I was able to confirm the communication successfully.

Image description

What I've learned so far

The Transitgateway shared in RAM is a regional service, which is obvious when you think about it, so for example, if you try to run the Account B stack mentioned earlier on us-east-1, you will get an error as follows.

Resource handler returned message: "Transit Gateway tgw-xxxxxxxxxxxxxxxxx was deleted or does not exist. (Service: Ec2, Status Code: 400, Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)" (RequestToken: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, HandlerErrorCode: NotFound)
Enter fullscreen mode Exit fullscreen mode

②Connecting regions by different accounts (3 accounts ver.)

My understanding to date is that by creating a Peering Attachment in the tgw account, it may be possible to

(*I have included a diagram of 8 VPCs (within regions, between regions, and between accounts) with the intention of following the trend from before last time, but I will simplify what I actually create).
Image description

With this aim,
[account A/ap-northeast-1/VPC1].
↓↑
[account B/us-east-1/VPC1]
Let's see if we can get a communication like the following.

configuration diagram

The previous diagram was messy, but this time the quirks are abbreviated as follows.
Image description

procedure

tgw_account_1stRegion.yml

Run the following template in the tgw account ap-northeast-1.

AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

  PJPrefix: 
    Type: String

  Environment: 
    Type: String
    Default: prd

  AccountAId:
    Type: String

Resources: 
  # ------------------------------------------------------------#
  # RAM
  # ------------------------------------------------------------#
  ResourceShare:
    Type: AWS::RAM::ResourceShare
    DependsOn: 
      - TransitGateway
    Properties: 
      Name: !Sub ${PJPrefix}-${Environment}-ram
      ResourceArns:
        - !Sub arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:transit-gateway/${TransitGateway}
      Principals:
        - !Ref AccountAId
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-ram-for-account-a
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
  TransitGateway:
    Type: AWS::EC2::TransitGateway
    Properties:
      AmazonSideAsn: 64512 # default value
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: enable
      DefaultRouteTablePropagation: enable
      DnsSupport: enable
      VpnEcmpSupport: enable
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgateway-for-account-a

Outputs:
  TransitGatewayId:
    Value: !Ref TransitGateway

  PeerRegion:
    Value: !Ref AWS::Region

  PeerTransitGatewayId:
    Value: !Ref TransitGateway
Enter fullscreen mode Exit fullscreen mode

tgw_account_2ndRegion.yml

Run the following template for the same tgw account, this time in the us-east-1 region.
*Please copy and paste the same name output value from the "tgw_account_1stRegion.yml" stack for the blank parameter value.

AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

  PJPrefix: 
    Type: String

  Environment: 
    Type: String
    Default: prd

  AccountBId: 
    Type: String

  PeerRegion: # Input the same name output value of the 1st region's stack
    Type: String

  PeerTransitGatewayId: # Input the same name output value of the 1st region's stack
    Type: String

Resources: 
  # ------------------------------------------------------------#
  # RAM
  # ------------------------------------------------------------#
  ResourceShare:
    Type: AWS::RAM::ResourceShare
    DependsOn: 
      - TransitGateway
    Properties: 
      Name: !Sub ${PJPrefix}-${Environment}-ram
      ResourceArns:
        - !Sub arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:transit-gateway/${TransitGateway}
      Principals:
        - !Ref AccountBId
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-ram-for-account-b
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
  TransitGateway:
    Type: AWS::EC2::TransitGateway
    Properties:
      AmazonSideAsn: 64512 # default value
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: enable
      DefaultRouteTablePropagation: enable
      DnsSupport: enable
      VpnEcmpSupport: enable
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgateway-for-account-b

  TransitGatewayPeeringAttachment:
    Type: AWS::EC2::TransitGatewayPeeringAttachment
    Properties:
      PeerAccountId: !Ref AWS::AccountId
      PeerRegion: !Ref PeerRegion
      PeerTransitGatewayId: !Ref PeerTransitGatewayId
      TransitGatewayId: !Ref TransitGateway

Outputs:
  TransitGatewayId:
    Value: !Ref TransitGateway
Enter fullscreen mode Exit fullscreen mode


Peering Attachment that is in "Pending Acceptance" status in the "Transit Gateway Attachment" of the ap-northeast-1 region of the tgw account, go to "Action" -> "Transit Gateway Attachment. Accept".

consent procedure

Image description

Image description

Image description

Pending is displayed.
Image description

Change to Available. (Completed)
Image description

Go to the RAM console of account A ap-northeast-1 and approve the pending resource sharing (invitation). (*Refer to the previous chapter procedure "RAM Work" block for instructions)

Go to the RAM console of account B on us-east-1 and approve the pending resource sharing (invitation). (*Refer to the previous section, "RAM Work" block for instructions.)

Execute the following template on account A's ap-northeast-1.

AccountA_1stRegion.yml

*Please copy and paste the "TransitGatewayId" parameter value from the "tgw_account_1stRegion.yml" stack output value of the same name.

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

  ImageId: # EC2のImageId
    Type: String
    Default: ami-079a2a9ac6ed876fc

  InstanceType: 
    Type: String
    Default: t2.micro

# for 2ndAccount
  2ndAccountVPC1CidrBlock: 
    Type: String
    Default: 10.2.0.0/16

  # Input the same name output value in tgw_account.yml
  TransitGatewayId:
    Type: String

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
# for VPC1
  VPC1TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC1PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGatewayId
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc1
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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 2ndAccountVPC1CidrBlock
      TransitGatewayId: !Ref TransitGatewayId
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  VPC1EC2SecurityGroupIngressFrom2ndAccountVPC1CidrBlock:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 2ndAccountVPC1CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId
Enter fullscreen mode Exit fullscreen mode

AccountB_2ndRegion.yml

Run the following template on account B, us-east-1.
*Please copy and paste the "TransitGatewayId" parameter value from the "tgw_account_1stRegion.yml" stack output value of the same name.

AWSTemplateFormatVersion: 2010-09-09

Parameters:

  PJPrefix: 
    Type: String

  Environment: 
    Type: String
    Default: prd

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

  VPC1PrivateSubnetForEC2CidrBlock:
    Type: String
    Default: 10.2.0.0/24

  VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock: 
    Type: String
    Default: 10.2.1.0/28

  ImageId: 
    Type: String
    Default: ami-06e46074ae430fba6

  InstanceType:
    Type: String
    Default: t2.micro

# for 1stAccount
  1stAccountVPC1CidrBlock: 
    Type: String
    Default: 10.1.0.0/16

  # Input the same name output value in tgw_account.yml
  TransitGatewayId:
    Type: String

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
# for VPC1
  VPC1TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC1PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGatewayId
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc1
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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 1stAccountVPC1CidrBlock
      TransitGatewayId: !Ref TransitGatewayId
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  VPC1EC2SecurityGroupIngressFrom1stAccountVPC1CidrBlock:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 1stAccountVPC1CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId
Enter fullscreen mode Exit fullscreen mode


Go to the "VPC" console of the tgw account ap-northeast-1 and go to "Transit Gateway Route Table" -> created TGW route table ID -> "Create Static Route" to [10.2.0.0/16] for Peering Attachment Add a route.

Static route addition procedure

Image description

Image description

Image description

In the same way, go to the "VPC" console on us-east-1 of the tgw account and go to "Transit Gateway Route Table" -> created TGW route table ID -> "Create Static Route" for Peering Attachment at [10.1.0.0/16]. Add a static route for Peering Attachment.

The last step of adding a static route was done manually, instead of creating a template for each route.

Execute ping on the EC2 instance to confirm communication

account A's ap-northeast-1 -> account B's us-east-1
Image description

account B's us-east-1 -> account A's ap-northeast-1
Image description

I was able to confirm communication.

③Connect different accounts different regions (2 accounts ver.)

configuration diagram

  • Understanding made easyVersion

Image description

  • It is designed to eliminate wasted space and to keep things in order.

Image description

procedure

AccountA_1stRegion.yml

Run the following stack on account A ap-northeast-1

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

  ImageId: # EC2のImageId
    Type: String
    Default: ami-079a2a9ac6ed876fc

  InstanceType: 
    Type: String
    Default: t2.micro

# for 2ndAccount
  2ndAccountVPC1CidrBlock: 
    Type: String
    Default: 10.2.0.0/16

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

  VPC1TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC1PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGateway
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc1
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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 2ndAccountVPC1CidrBlock
      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
  # ------------------------------------------------------------#
  # 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
  VPC1EC2SecurityGroupIngressFrom2ndAccountVPC1CidrBlock:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 2ndAccountVPC1CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId

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

  PeerTransitGatewayId:
    Value: !Ref TransitGateway
Enter fullscreen mode Exit fullscreen mode

AccountA_2ndRegion.yml

Run the following stack on account A, us-east-1
*Please enter the ID of AccountB in the parameter value "AccountBId" and the same name output value of AccountA_1stRegion.yml in "PeerRegion" and "PeerTransitGatewayId".

AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

  PJPrefix: 
    Type: String

  Environment: 
    Type: String
    Default: prd

  AccountBId: 
    Type: String

  PeerRegion: # Input the same name output value of the 1st region's stack
    Type: String

  PeerTransitGatewayId: # Input the same name output value of the 1st region's stack
    Type: String

Resources: 
  # ------------------------------------------------------------#
  # RAM
  # ------------------------------------------------------------#
  ResourceShare:
    Type: AWS::RAM::ResourceShare
    DependsOn: 
      - TransitGateway
    Properties: 
      Name: !Sub ${PJPrefix}-${Environment}-ram
      ResourceArns:
        - !Sub arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:transit-gateway/${TransitGateway}
      Principals:
        - !Ref AccountBId
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-ram-for-account-b
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
  TransitGateway:
    Type: AWS::EC2::TransitGateway
    Properties:
      AmazonSideAsn: 64512 # default value
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: enable
      DefaultRouteTablePropagation: enable
      DnsSupport: enable
      VpnEcmpSupport: enable
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgateway-for-account-b

  TransitGatewayPeeringAttachment:
    Type: AWS::EC2::TransitGatewayPeeringAttachment
    Properties:
      PeerAccountId: !Ref AWS::AccountId
      PeerRegion: !Ref PeerRegion
      PeerTransitGatewayId: !Ref PeerTransitGatewayId
      TransitGatewayId: !Ref TransitGateway

Outputs:
  TransitGatewayId:
    Value: !Ref TransitGateway
Enter fullscreen mode Exit fullscreen mode


In the "Transit Gateway Attachment" of the "VPC" console of account A's ap-northeast1, select the Peering Attachment that is in the "Pending Acceptance" state under "Action" -> "Transit Gateway Accept Attachment".

Go to the "RAM" console of account B us-east-1 and accept the resource sharing.

AccountB_2ndRegion.yml

Go to the "Cloudformation" console of account B's us-east-1 and execute the following template

*Please copy and paste the "TransitGatewayId" parameter value from the AccountA_2ndRegion.yml stack with the same name output value.

AWSTemplateFormatVersion: 2010-09-09

Parameters:

  PJPrefix: 
    Type: String

  Environment: 
    Type: String
    Default: prd

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

  VPC1PrivateSubnetForEC2CidrBlock: 
    Type: String
    Default: 10.2.0.0/24

  VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock: 
    Type: String
    Default: 10.2.1.0/28

  ImageId: # EC2のImageId
    Type: String
    Default: ami-06e46074ae430fba6

  InstanceType: 
    Type: String
    Default: t2.micro

# for 1stAccount
  1stAccountVPC1CidrBlock: 
    Type: String
    Default: 10.1.0.0/16

  # Input the same name output value in AccountB_2ndRegion.yml
  TransitGatewayId:
    Type: String

Resources:
  # ------------------------------------------------------------#
  # TransitGateway
  # ------------------------------------------------------------#
# for VPC1
  VPC1TransitGatewayAttachment:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VPC1PrivateSubnetForTransitGatewayAttachment
      TransitGatewayId: !Ref TransitGatewayId
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgatewayattachment-vpc1
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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 1stAccountVPC1CidrBlock
      TransitGatewayId: !Ref TransitGatewayId
  # ------------------------------------------------------------#
  # 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
  # ------------------------------------------------------------#
  # 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
  VPC1EC2SecurityGroupIngressFrom1stAccountVPC1CidrBlock:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      FromPort: -1
      ToPort: -1
      IpProtocol: icmp
      CidrIp: !Ref 1stAccountVPC1CidrBlock
      GroupId: !GetAtt VPC1EC2SecurityGroup.GroupId
Enter fullscreen mode Exit fullscreen mode


Go to the "VPC" console of account A ap-northeast-1 and go to "Transit Gateway Route Table" -> created TGW route table ID -> "Create Static Route" and add a static route for Peering Attachment at [10.2.0.0/16]. Add a static route for Peering Attachment at [10.2.0.0.0/16].

Go to the "VPC" console of account A us-east-1 and add a static route for Peering Attachment at [10.1.0.0/16] under "Transit Gateway Route Table" -> created TGW Route Table ID -> "Create Static Route". Add a static route for Peering Attachment.

Execute ping on the EC2 instance to confirm communication

account A's ap-northeast-1 -> account B's us-east-1
Image description

account B's us-east-1 -> account A's ap-northeast-1

Image description

I was able to confirm communication.

That was all.

Thank you for reading.

Top comments (0)