🔄

[CFn]AWS Resource Access ManagerでAWS Transit Gatewayを複数アカウントから共有利用する

2023/05/29に公開

アカウント間で共有利用出来るTransitGatewayの作成

こんにちわ!

DevelopersIO BASECAMP一期の加藤です。

前回、以下のような記事を投稿いたしました。
https://zenn.dev/devcamp/articles/ecda0152105d6d

今回はアカウント跨ぎでインスタンス同士の疎通確認まで行ってみたいと思います。


①中間アカウントをオーナーとしてResource Access ManagerでTransit Gatewayを作成し、2つのアカウント(※リソースのリージョンは共通)に作成したアタッチメントと接続

字で伝えようとすると少し長くなりましたが、以下が今回作成するものです。

前回記事で同リージョン内と別リージョン間で4つのインスタンスでの疎通をしましたので、今回は同リージョン内と別アカウント間を試してみます。


構成図


※上図では抜けておりますが、中間のtgwアカウントもap-northeast-1となります。


参考にした記事。

以下の記事を参考にさせていただきました。
序盤に試すものだけであれば以下の記事を見ていただければ、テンプレの良さも一緒に勉強出来ますのでお勧めです。ConditonsやMappingを利用して、複数アカウントで共有にしている所が美しいです。
https://www.qes.co.jp/media/aws/a176


事前準備

AWS Organizationsからテスト用のアカウントを2つ作成します。(合計3つのアカウントが存在するように)

※アカウント作成時のメールアドレスにお困りの方はGmailのエイリアスアドレス機能がおすすめです。
例:「hogehoge@gmail.com」を所有→「hogehoge+fuga@gmail.com」「hogehoge+piyo@gmail.com」をエイリアスアドレスとして利用可能

ちなみに今回は、3アカウントを横断して作業する為、私はわかりやすいようにChrome,Safari,Firefoxでそれぞれ閲覧するようにしていました。


手順

※tgwアカウント、アカウントA、アカウントB全ての作業は同一リージョンで行ってください。
※amiがap-northeast-1を想定していますので、別リージョンの場合はそれぞれのスタック作成時に「ImageId」パラメーターの値を変更してください。


tgw用にするアカウントで以下テンプレートを実行。

tgw_account.yml
tgw_account.yml
AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

  PJPrefix: # リソース名やNameタグ値の接頭辞に利用
    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 # デフォルト値
      AutoAcceptSharedAttachments: enable
      DefaultRouteTableAssociation: enable
      DefaultRouteTablePropagation: enable
      DnsSupport: enable
      VpnEcmpSupport: enable
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-${Environment}-transitgateway

Outputs:
  TransitGatewayId:
    Value: !Ref TransitGateway


tgw用アカウントのAWS Resource Access Manager(RAM)コンソールへ移動してみると、「自分が共有:リソース共有」に以下のように表示されている事が見て取れます。


アカウントA、アカウントBでもそれぞれ、RAMコンソールに移動し以下作業を実行。

RAM作業

「自分と共有:リソースの共有」へ移動し、以下の手順でtgwアカウントからのリソース共有の承認を行います。








「自分と共有:リソースの共有」の中に先ほど確認出来たtgwリソースがなくなり、一つ下のタブの「自分と共有:共有リソース」に同リソースが確認出来るようになります。


これが確認出来ていれば承認は正常に完了しています。


A/Bのアカウントで承認が完了すると、tgwアカウントで以下のように「共有プリンシパル」のステータスが「関連付け済み」になっている事が確認出来ます。


アカウントAで以下テンプレートを実行します。

tgw_account.yml
account_a.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 2ndAccount
  # for VPC1
  2ndAccountVPC1CidrBlock: # VPC1のCIDRブロック
    Type: String
    Default: 10.3.0.0/16

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

  # 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

# 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


アカウントBで以下テンプレートを実行します。

tgw_account.yml
account_b.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-079a2a9ac6ed876fc

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

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

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

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

以上で完了です。


EC2インスタンスでpingを実行し疎通確認

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


ここまでで勉強になった事

RAMで共有したTransitgatewayは、考えてみれば当たり前ですがリージョナルサービスなので、例えば先程のアカウントBスタックをus-east-1で実行しようとすると以下のようにエラーが起きます。

直訳/「tgw-xxxxxxxxxxxxxxxxxは削除されたか存在しません。」
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)

これを踏まえてアカウントAのリージョン1と、アカウントBのリージョン2を接続するにはどうしたらいいかを考えてみました。


②別アカウント別リージョンを接続する(3アカウントver)

現在までの理解だと、tgwアカウント内にPeering Attachmentを作成する事で、以下が可能なのではないかと考えました。

(※前回以前からの流れを汲む意図で8VPC(リージョン内、リージョン間、アカウント間)の図を記載していますが、実際に作成するものはシンプルにします。)

この狙いで、
[アカウントA/ap-northeast-1/VPC1]
↓↑
[アカウントB/us-east-1/VPC1]
のような疎通が取れるか確認してみます。


構成図

先ほどの図ではごちゃごちゃとしていましたが、流石に今回は以下のように省略します。


手順

※手順に混乱が起きないよう、コンソールの作業場所を図にしました。(以下は構成図ではないです。)


tgwアカウントのap-northeast-1で以下テンプレートを実行します。

tgw_account_1stRegion.yml
tgw_account_1stRegion.yml
AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

  PJPrefix: # リソース名やNameタグ値の接頭辞に利用
    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 # デフォルト値
      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


同じくtgwアカウントの、今度はus-east-1リージョンで以下テンプレートを実行します。

tgw_account_2ndRegion.yml

※空欄パラメーター値は「tgw_account_1stRegion.yml」スタックの同名出力値をコピペください。

tgw_account_2ndRegion.yml
AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

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

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

  AccountBId: 
    Type: String

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

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


tgwアカウントのap-northeast-1リージョンの「Transit Gateway アタッチメント」で「Pending Acceptance」状態になっているPeering Attachmentを「アクション」→「Transit Gatewayアタッチメントを承諾」する。

承諾手順







Pending(保留中)になる。


Availableに変わる。(完了)


アカウントAのap-northeast-1のRAMコンソール移動し、保留中のリソース共有(招待)を承認する。(※手順は前章手順「RAM作業」ブロックを参照)

アカウントBのus-east-1のRAMコンソール移動し、保留中のリソース共有(招待)を承認する。(※手順は前章手順「RAM作業」ブロックを参照)

アカウントAのap-northeast-1で以下テンプレートを実行。

AccountA_1stRegion.yml

※「TransitGatewayId」パラメーター値は「tgw_account_1stRegion.yml」スタックの同名出力値をコピペください。

AccountA_1stRegion.yml
AWSTemplateFormatVersion: 2010-09-09

Parameters:

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

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

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

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

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

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

  # 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


アカウントBのus-east-1で以下テンプレートを実行。

AccountB_2ndRegion.yml

※「TransitGatewayId」パラメーター値は「tgw_account_1stRegion.yml」スタックの同名出力値をコピペください。

AccountB_2ndRegion.yml
AWSTemplateFormatVersion: 2010-09-09

Parameters:

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

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

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

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

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

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

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

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

  # 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


tgwアカウントのap-northeast-1の「VPC」コンソールに移動して、「Transit Gateway ルートテーブル」→作成済みのTGWルートテーブル ID→「静的ルートを作成」で[10.2.0.0/16]でPeering Attachment向けの静的ルートを追加する。

静的ルート追加手順






同じ要領で、tgwアカウントのus-east-1の「VPC」」コンソールに移動して、「Transit Gateway ルートテーブル」→作成済みのTGWルートテーブル ID→「静的ルートを作成」で[10.1.0.0/16]でPeering Attachment向けの静的ルートを追加する。

※最後の静的ルートの追加はさすがにそれぞれテンプレを作る事はせず手動にしました。

EC2インスタンスでpingを実行し疎通確認

アカウントAのap-northeast-1→アカウントBのus-east-1

アカウントBのus-east-1→アカウントAのap-northeast-1

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


③別アカウント別リージョンを接続する(2アカウントver)

最後に②で作成したものから中間のアカウントを省いたものを作ってみます!


構成図

理解優先Ver

※整えると

無駄なスペースを省いたVer


手順

※こちらも手順に混乱が起きないよう、コンソールの作業場所を図にしました。


アカウントAのap-northeast-1で以下スタックを実行します。

AccountA_1stRegion.yml
AccountA_1stRegion.yml
AWSTemplateFormatVersion: 2010-09-09

Parameters:

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

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

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

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

  InstanceType: # EC2の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 # デフォルト値
      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


アカウントAのus-east-1で以下スタックを実行します。

AccountA_2ndRegion.yml

※パラメーター値「AccountBId」にはAccountBのIDを、「PeerRegion」と「PeerTransitGatewayId」にはAccountA_1stRegion.ymlの同名出力値を入力ください。

AccountA_2ndRegion.yml
AWSTemplateFormatVersion: "2010-09-09"

Parameters: 

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

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

  AccountBId: 
    Type: String

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

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


アカウントAのap-northeast1の「VPC」コンソールの「Transit Gateway アタッチメント」で「Pending Acceptance」状態になっているPeering Attachmentを「アクション」→「Transit Gatewayアタッチメントを承諾」します。

アカウントBのus-east-1の「RAM」コンソールに移動し、リソースの共有を承諾します。

アカウントBのus-east-1の「Cloudformation」コンソールに移動し、以下テンプレートを実行します。

AccountB_2ndRegion.yml

※「TransitGatewayId」パラメーター値はAccountA_2ndRegion.ymlスタックの同名出力値をコピペください。

AccountB_2ndRegion.yml
AWSTemplateFormatVersion: 2010-09-09

Parameters:

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

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

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

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

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

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

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

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

  # 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


アカウントAのap-northeast-1の「VPC」コンソールに移動して、「Transit Gateway ルートテーブル」→作成済みのTGWルートテーブル ID→「静的ルートを作成」で[10.2.0.0/16]でPeering Attachment向けの静的ルートを追加する。

アカウントAのus-east-1の「VPC」コンソールに移動して、「Transit Gateway ルートテーブル」→作成済みのTGWルートテーブル ID→「静的ルートを作成」で[10.1.0.0/16]でPeering Attachment向けの静的ルートを追加する。


EC2インスタンスでpingを実行し疎通確認

アカウントAのap-northeast-1→アカウントBのus-east-1

アカウントBのus-east-1→アカウントAのap-northeast-1

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

終わりに

構成図でもっとRAMの状態と意図が一目でわかる表現を見つけたいなと思ってしまいました。

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

デベキャン

Discussion