↔️

AWS Transit GatewayをCloudFormationで作成する[リージョン内・リージョン間]

2023/05/28に公開

TransitGatewayの作成

こんにちわ!

DevelopersIO BASECAMP一期参加の加藤です。

当記事はAdvanced Networking - Specialty試験取得の一環で、理解が曖昧な点を検証しつつ下書き状態にしていたもので、1月半ほど経過して再着手し書き終えたものです。

一期が終了してから、暫く日にちも経っておりますが、運営の皆様にこうしてアウトプットの場を残していただけている為、着手した場所で公開させていただく事といたしました。

2023年5月現在 CloudFormationでのTransitGatewayのお手本がそれほど豊富でない為、TGW RouteTableの設定など私のようにはまってしまう方も少なくないかと思います。当記事の例中に理解の助けになる部分があれば幸いです。


TransitGatewayとは

Transit Gatewayは、仮想プライベートクラウド (VPC) とオンプレミスネットワークを相互接続するために使用できるネットワークの中継ハブです。

TransitGatewayについての詳しくは公式ドキュメントを参照ください。


前置き

今回は、
・動的な伝播の設定
・アカウント跨ぎ

については踏み込めておりません。


①同一リージョン内の別VPC間

以下のブログでお作りになっているものを、周辺のリソースを省略せずに作ってみます。
https://dev.classmethod.jp/articles/transitgateway-cloudformation/

同一リージョン内の2VPC間で、それぞれプライベート上に立てたEC2同士でPingをTransitGatewayを経由して送り疎通を確認します。


構成図


テンプレート

※元の解説と重複になる為 説明は省略いたします。

sample.yml
sample.yml
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  PJPrefix: # リソース名やNameタグ値の接頭辞に利用
    Type: String

  Environment: # 同上(環境名)
    Type: String
    Default: prd

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

  VPC1PrivateSubnetForEC2CidrBlock: # VPC1のEC2を配置するサブネットのCIDRブロック
    Type: String
    Default: 10.1.0.0/24

  VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock: # VPC1のTransittGatewayをアタッチするサブネットのCIDRブロック
    Type: String
    Default: 10.1.1.0/28

# for VPC2
  VPC2CidrBlock: # VPC1のCIDRブロック
    Type: String
    Default:  10.2.0.0/16

  VPC2PrivateSubnetForEC2CidrBlock: # VPC2のEC2を配置するサブネットのCIDRブロック
    Type: String
    Default:  10.2.0.0/24

  VPC2PrivateSubnetForTransitGatewayAttachmentCidrBlock: # VPC1のTransitGatewayをアタッチするサブネットのCIDRブロック
    Type: String
    Default:  10.2.1.0/28

  ImageId: # EC2のImageId(今回は共通)
    Type: String
    Default: ami-079a2a9ac6ed876fc

  InstanceType: # EC2の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

コンソールを確認

コンソールから結果を確認してみます。

畳んでいます

TransitGateway(VPC)コンソール

TransitGateway


TransitGatewayアタッチメント



TransitGatewayルートテーブル

  • 関連付け

  • アタッチメント

  • ルート


EC2間でPingを実行

それぞれのインスタンスからPingを実行してみます。

VPC1→VPC2

VPC2→VPC1

無事疎通確認が出来ました。

②Inter-Region Peering

続いて、東京リージョンとバージニア北部リージョン間のEC2の疎通を確認してみます。

こちらのブログでのコンソール操作を参考にさせていただきました。
https://dev.classmethod.jp/articles/tgw-inter-region-peerinng-yattemita/

各1VPCでも良い所ですが、今回は①の環境をそれぞれのリージョンで作成し4つのEC2間で疎通を図ります。


構成図


テンプレート

1stRegion.yml
1stRegion.yml
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  PJPrefix: # リソース名やNameタグ値の接頭辞に利用
    Type: String

  Environment: # 同上(環境名)
    Type: String
    Default: prd

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

  VPC1PrivateSubnetForEC2CidrBlock: # VPC1のEC2を配置するサブネットのCIDRブロック
    Type: String
    Default: 10.1.0.0/24

  VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock: # VPC1のTransittGatewayをアタッチするサブネットのCIDRブロック
    Type: String
    Default: 10.1.1.0/28

  # for VPC2
  VPC2CidrBlock: # VPC1のCIDRブロック
    Type: String
    Default:  10.2.0.0/16

  VPC2PrivateSubnetForEC2CidrBlock: # VPC2のEC2を配置するサブネットのCIDRブロック
    Type: String
    Default:  10.2.0.0/24

  VPC2PrivateSubnetForTransitGatewayAttachmentCidrBlock: # VPC1のTransitGatewayをアタッチするサブネットのCIDRブロック
    Type: String
    Default:  10.2.1.0/28

  # for Both EC2
  ImageId: # EC2のImageId(今回は共通)
    Type: String
    Default: ami-079a2a9ac6ed876fc

  InstanceType: # EC2のInstanceType(今回は共通)
    Type: String
    Default: t2.micro

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

  # for VPC2
  2ndRegionVPC2CidrBlock: # VPC1のCIDRブロック
    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

※Parameter入力画面では、1stRegion.ymlスタックの同名出力値×2を利用ください。

2ndRegion.yml
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  PJPrefix: # リソース名やNameタグ値の接頭辞に利用
    Type: String

  Environment: # 同上(環境名)
    Type: String
    Default: prd

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

  VPC1PrivateSubnetForEC2CidrBlock: # VPC1のEC2を配置するサブネットのCIDRブロック
    Type: String
    Default: 10.3.0.0/24

  VPC1PrivateSubnetForTransitGatewayAttachmentCidrBlock: # VPC1のTransittGatewayをアタッチするサブネットのCIDRブロック
    Type: String
    Default: 10.3.1.0/28

# for VPC2
  VPC2CidrBlock: # VPC1のCIDRブロック
    Type: String
    Default:  10.4.0.0/16

  VPC2PrivateSubnetForEC2CidrBlock: # VPC2のEC2を配置するサブネットのCIDRブロック
    Type: String
    Default:  10.4.0.0/24

  VPC2PrivateSubnetForTransitGatewayAttachmentCidrBlock: # VPC1のTransitGatewayをアタッチするサブネットのCIDRブロック
    Type: String
    Default:  10.4.1.0/28

  # for Both EC2
  ImageId: # EC2のImageId(今回は共通)
    Type: String
    Default: ami-06e46074ae430fba6

  InstanceType: # EC2のInstanceType(今回は共通)
    Type: String
    Default: t2.micro

# for 1stRegion
  # for VPC1
  1stRegionVPC1CidrBlock: # VPC1のCIDRブロック
    Type: String
    Default: 10.1.0.0/16

  # for VPC2
  1stRegionVPC2CidrBlock: # VPC1のCIDRブロック
    Type: String
    Default:  10.2.0.0/16

  PeerRegion: # 1stリージョンのスタックの同名出力値を入力
    Type: String

  PeerTransitGatewayId: # 1stリージョンのスタックの同名出力値を入力
    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

コンソールからピアリングの承諾を行う

コンソールからピアリングの承諾を行う

「Transit Gateway アタッチメント」を確認すると、
状態:Pending Acceptanceとなっているリソースが確認できます。

  • us-east-1

  • ap-northeast-1

リクエスタとアクセプタがそれぞれ設定のリージョンになっている事が確認出来ました。

アクセプタリージョンであるap-northeast-1の当該アタッチメントの「アクション」から「TransitGatewayアタッチメントを承諾」をクリックします。



それぞれ、状態:Pendingに変わり、数分待つと

  • us-east-1

  • ap-northeast-1

状態:Availableとなりました!

追加テンプレート

1stRegionTransitRoute.yml

※Parameter入力画面では、AutoCreatedTransitGatewayRouteTableIdには1stRegionに自動作成された無名(※Name:「-」)のTransit Gateway ルートテーブル IDを、TransitGatewayPeeringAttachmentには2ndRegion.ymlスタックの同名出力値を入力ください。

1stRegionTransitRoute.yml
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  2ndRegionVPC1CidrBlock:
    Type: String
    Default: 10.3.0.0/16

  2ndRegionVPC2CidrBlock:
    Type: String
    Default: 10.4.0.0/16

  TransitGatewayPeeringAttachment: # 2ndリージョンのスタックの同名出力値を参照
    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

※Parameter入力画面では、AutoCreatedTransitGatewayRouteTableIdには2ndRegionに自動作成された無名(※Name:「-」)のTransit Gateway ルートテーブル IDを入力ください。

2ndRegionTransitRoute.yml
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

EC2間でPingを実行

こちらもEC2間で疎通確認をしてみます。


画像はひとつだけですが、全インスタンスで疎通確認が出来ました。

おまけ

ちなみに、当記事を下書きのまま公開出来ていなかったのは、Inter-Regionの例で何故かPingが通らなくて原因探しが必要だったという理由なのですが、あれこれ間違った理解の可能性をひっくり返して探す という事を本日していました。

結果、SecurityGroupIngressで!Refしていた論理IDを一文字間違えていたという凡ミスだった訳なのですが、そのおかげであれこれしている中でTGW Route Analyzerと出会う事ができました。

https://dev.classmethod.jp/articles/tgw-network-manager-route-analyzer/

この機能のおかげで「ここが問題ないって事はまさかSGミスってる..?」となり、解決に至る事ができました。

せっかくなので、簡易ですが使い方の流れをスクショで置いておきます。

TGW Route Analyzerの使い方

TGW Route Analyzerの使い方






















テンプレートで作成する場合は

以下のように、「TransitGatewayRegistration」は各リージョンでスタック実行をしないとエラーが起こります。

1stRegion_GlobalNetwork_and_TransitGatewayRegistration.yml
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
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}

終わりに

お読みいただき有難うございました。

デベキャン

Discussion