VPCピアリングを使って同じアカウント内のVPCを繋げたことはあったのですが、別アカウントにあるVPCは繋げたことが無かったのでやってみました。
構成
構成図は以下になります。
アカウントAのプライベートサブネットに配置されているEC2からアカウントBのVPCへの通信 (RDS Aurora MySQLへのアクセスなど) をVPCピアリング経由で行う構成となっています。
それ以外の通信はNATゲートウェイを経由して通信を行います。
設定してみた
アカウントAでVPCピアリング以外のリソース作成
まずはアカウントAでVPCピアリング以外のリソースを作成します。
リソース作成には以下のCloudFormationテンプレートを使用しました。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: Network and EC2 Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for VPC
Parameters:
- VPCCIDR
- Label:
default: Parameters for Subnet
Parameters:
- PublicSubnet01CIDR
- PrivateSubnet01CIDR
- Label:
default: Parameters for ec2
Parameters:
- EC2VolumeSize
- EC2VolumeIOPS
- EC2AMI
- EC2InstanceType
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
VPCCIDR:
Default: 172.30.0.0/16
Type: String
PublicSubnet01CIDR:
Default: 172.30.1.0/24
Type: String
PrivateSubnet01CIDR:
Default: 172.30.3.0/24
Type: String
EC2VolumeSize:
Default: 32
Type: Number
EC2VolumeIOPS:
Default: 3000
Type: Number
EC2AMI:
Default: ami-06ee4e2261a4dc5c3
Type: AWS::EC2::Image::Id
EC2InstanceType:
Default: t3.micro
Type: String
Resources:
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
EC2IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
RoleName: iam-role-ec2
Tags:
- Key: Name
Value: iam-role-ec2
EC2IAMInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: iam-instanceprofile-ec2
Roles:
- !Ref EC2IAMRole
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: account-a-vpc
# ------------------------------------------------------------#
# InternetGateway
# ------------------------------------------------------------#
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: account-a-igw
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
# ------------------------------------------------------------#
# Subnet
# ------------------------------------------------------------#
PublicSubnet01:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PublicSubnet01CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub account-a-public-subnet-01
VpcId: !Ref VPC
PrivateSubnet01:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PrivateSubnet01CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub account-a-private-subnet-01
VpcId: !Ref VPC
# ------------------------------------------------------------#
# NatGateWay
# ------------------------------------------------------------#
NatGateWayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: eip-natgw
NatGateWay:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGateWayEIP.AllocationId
ConnectivityType: public
SubnetId: !Ref PublicSubnet01
Tags:
- Key: Name
Value: account-a-natgw-1a
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: account-a-public-rtb
PublicRouteTableRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
RouteTableId: !Ref PublicRouteTable
PublicRtAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet01
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: account-a-private-rtb
PrivateRouteTableRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateWay
RouteTableId: !Ref PrivateRouteTable
PrivateRtAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet01
# ------------------------------------------------------------#
# Security Group
# ------------------------------------------------------------#
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for ec2
GroupName: account-a-sg-ec2
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
Tags:
- Key: Name
Value: account-a-sg-ec2
VpcId: !Ref VPC
# ------------------------------------------------------------#
# EC2
# ------------------------------------------------------------#
EC2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: !Ref EC2VolumeIOPS
VolumeSize: !Ref EC2VolumeSize
VolumeType: gp3
DisableApiTermination: false
IamInstanceProfile: !Ref EC2IAMInstanceProfile
ImageId: !Ref EC2AMI
InstanceType: !Ref EC2InstanceType
NetworkInterfaces:
- DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref EC2SG
SubnetId: !Ref PrivateSubnet01
Tags:
- Key: Name
Value: test-ec2
UserData: !Base64 |
#!/bin/bash
yum remove mariadb-libs
rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-6.noarch.rpm -y
yum install -y mysql-community-client
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
VPCID:
Value: !Ref VPC
Export:
Name: VPC
PublicSubnet01ID:
Value: !Ref PublicSubnet01
Export:
Name: PublicSubnet01ID
PrivateSubnet01ID:
Value: !Ref PrivateSubnet01
Export:
Name: PrivateSubnet01ID
PrivateRouteTableID:
Value: !Ref PrivateRouteTable
Export:
Name: PrivateRouteTableID
EC2はMySQLクライアントをインストールするために「UserData」でインストールコマンドを記載しています。
デプロイは以下のコマンドを実行します。
VPCのCIDRなどを変更したい場合はコマンドのオプションで「--parameters」を入れてください。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --capabilities CAPABILITY_NAMED_IAM
アカウントBでリソースの作成
アカウントBではRDS Aurora MySQLをシングルAZで起動します。
まずはネットワーク部分とクロスアカウント用のIAMロールを作成してVPCピアリングをできるようにしていきます。
IAMロールは以下の公式ドキュメントと同じものになります。
チュートリアル: 別の AWS アカウント の VPC とピア接続する
リソース作成には以下のCloudFormationテンプレートを使用しました。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: Network Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for IAM
Parameters:
- PeerRequesterAccountId
- Label:
default: Parameters for VPC
Parameters:
- VPCCIDR
- Label:
default: Parameters for Subnet
Parameters:
- PrivateSubnet01CIDR
- PrivateSubnet02CIDR
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
PeerRequesterAccountId:
Type: Number
Description: AWS Account ID
VPCCIDR:
Default: 172.17.0.0/16
Type: String
PrivateSubnet01CIDR:
Default: 172.17.1.0/24
Type: String
PrivateSubnet02CIDR:
Default: 172.17.2.0/24
Type: String
Resources:
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
peerRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Statement:
- Principal:
AWS: !Ref PeerRequesterAccountId
Action:
- 'sts:AssumeRole'
Effect: Allow
Path: /
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: 'ec2:AcceptVpcPeeringConnection'
Resource: '*'
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: account-b-vpc
# ------------------------------------------------------------#
# Subnet
# ------------------------------------------------------------#
PrivateSubnet01:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PrivateSubnet01CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub account-b-private-subnet-01
VpcId: !Ref VPC
PrivateSubnet02:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1c
CidrBlock: !Ref PrivateSubnet02CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub account-b-private-subnet-02
VpcId: !Ref VPC
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: account-b-private-rtb
PrivateRtAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet01
PrivateRtAssociation2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet02
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
RoleARN:
Value: !GetAtt peerRole.Arn
Export:
Name: RoleARN
VPCID:
Value: !Ref VPC
Export:
Name: VPC
PrivateSubnet01ID:
Value: !Ref PrivateSubnet01
Export:
Name: PrivateSubnet01ID
PrivateSubnet02ID:
Value: !Ref PrivateSubnet02
Export:
Name: PrivateSubnet02ID
PrivateRouteTableID:
Value: !Ref PrivateRouteTable
Export:
Name: PrivateRouteTableID
こちらのCloudFormationテンプレートではプライベートサブネットを2つ作成しています。
デプロイは以下のコマンドを実行します。
こちらのCloudFormationはアカウントBで実行するものなので実行場所 (クレデンシャル) などに気を付けてください。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=PeerRequesterAccountId,ParameterValue=AWSアカウントAのID --capabilities CAPABILITY_NAMED_IAM
アカウントAでVPCピアリングの作成
ここからはアカウントAでVPCピアリングを作成していきます。
リソース作成には以下のCloudFormationテンプレートを使用しました。
AWSTemplateFormatVersion: "2010-09-09"
Description: Network Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for VPC Peering
Parameters:
- PeerOwnerId
- PeerRegion
- PeerRoleArn
- PeerVpcId
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
PeerOwnerId:
Type: Number
Description: AWS Account-b ID
PeerRegion:
Default: ap-northeast-1
Type: String
PeerRoleArn:
Type: String
Description: Account-b Role ARN
PeerVpcId:
Type: String
Description: Account-b VPC ID
Resources:
# ------------------------------------------------------------#
# VPC Peering
# ------------------------------------------------------------#
VPCPeering:
Type: AWS::EC2::VPCPeeringConnection
Properties:
PeerOwnerId: !Ref PeerOwnerId
PeerRegion: !Ref PeerRegion
PeerRoleArn: !Ref PeerRoleArn
PeerVpcId: !Ref PeerVpcId
VpcId: !ImportValue VPC
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PrivateRouteTableRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 172.17.0.0/16
VpcPeeringConnectionId: !Ref VPCPeering
RouteTableId: !ImportValue PrivateRouteTableID
こちらのCloudFormationテンプレートではVPCピアリングの作成とアカウントBのVPC向けの経路をルートテーブルに登録しています。
「PeerRoleArn」はクロスアカウントの場合は必要ですが、同一アカウント内であればIAMロールは不要になります。
デプロイは以下のコマンドを実行します。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=PeerOwnerId,ParameterValue=AWSアカウントBのID ParameterKey=PeerRoleArn,ParameterValue=AWSアカウントBで作成したIAMロールのARN ParameterKey=PeerVpcId,ParameterValue=AWSアカウントBのVPC ID
アカウントBでRDS Aurora MySQLの作成
ここではアカウントBでRDS Aurora MySQLの作成を行います。
リソース作成には以下のCloudFormationテンプレートを使用しました。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: RDS Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for Security Group
Parameters:
- EC2SG
- SourceSecurityGroupOwnerId
- Label:
default: Parameters for RDS Aurora MySQL
Parameters:
- InstanceClass
- AuroraMySQLVersion
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
EC2SG:
Type: String
Description: SecurityGroup ID
SourceSecurityGroupOwnerId:
Type: Number
Description: AWS Account-b ID
VpcPeeringConnectionId:
Type: String
Description: VPC Peering ID
InstanceClass:
Default: db.t3.medium
Type: String
AuroraMySQLVersion:
Default: 8.0.mysql_aurora.3.02.2
Type: String
Resources:
# ------------------------------------------------------------#
# Security Group
# ------------------------------------------------------------#
RDSSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for aurora mysql
GroupName: account-b-sg-aurora-mysql
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
SecurityGroupIngress:
- FromPort: 3306
IpProtocol: tcp
SourceSecurityGroupId: !Ref EC2SG
ToPort: 3306
Tags:
- Key: Name
Value: account-b-sg-aurora-mysql
VpcId: !ImportValue VPC
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PrivateRouteTableRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 172.16.0.0/16
VpcPeeringConnectionId: !Ref VpcPeeringConnectionId
RouteTableId: !ImportValue PrivateRouteTableID
# ------------------------------------------------------------#
# RDS Password
# ------------------------------------------------------------#
Password:
Type: AWS::SecretsManager::Secret
Properties:
Description: RDS Password
GenerateSecretString:
GenerateStringKey: password
SecretStringTemplate: '{"username": "root"}'
ExcludeCharacters: '"@/\'
Name: password-aurora-mysql
Tags:
- Key: Name
Value: password-aurora-mysql
# ------------------------------------------------------------#
# RDS Subnet Group
# ------------------------------------------------------------#
SubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: for aurora mysql subnet group
DBSubnetGroupName: subng-aurora-mysql
SubnetIds:
- !ImportValue PrivateSubnet01ID
- !ImportValue PrivateSubnet02ID
Tags:
- Key: Name
Value: subng-aurora-mysql
# ------------------------------------------------------------#
# RDS Cluster
# ------------------------------------------------------------#
Cluster:
Type: AWS::RDS::DBCluster
Properties:
BackupRetentionPeriod: 1
CopyTagsToSnapshot: true
DBClusterIdentifier: account-b-aurora-mysql
DBSubnetGroupName: !Ref SubnetGroup
DeletionProtection: false
Engine: aurora-mysql
EngineVersion: !Ref AuroraMySQLVersion
MasterUsername: !Sub '{{resolve:secretsmanager:${Password}::username}}'
MasterUserPassword: !Sub '{{resolve:secretsmanager:${Password}::password}}'
Port: 3306
StorageEncrypted: true
Tags:
- Key: Name
Value: account-b-aurora-mysql
VpcSecurityGroupIds:
- !Ref RDSSG
# ------------------------------------------------------------#
# RDS Instance
# ------------------------------------------------------------#
Instance:
Type: AWS::RDS::DBInstance
Properties:
AutoMinorVersionUpgrade: true
AvailabilityZone: ap-northeast-1a
DBClusterIdentifier: !Ref Cluster
DBInstanceClass: !Ref InstanceClass
DBInstanceIdentifier: account-b-aurora-mysql-1
Engine: aurora-mysql
PubliclyAccessible: false
Tags:
- Key: Name
Value: account-b-aurora-mysql-1
セキュリティグループではアカウントAのEC2からポート番号3306でアクセスしてこれるようにアカウントAのEC2が使用しているセキュリティグループを送信元として設定します。
クロスアカウントのセキュリティグループ参照については以下の公式ドキュメントをご確認ください。
セキュリティグループの更新とピアセキュリティグループの参照
RDS Aurora MySQLのマスターユーザー、パスワードはSecrets Managerに格納されるようにしています。
デプロイは以下のコマンドを実行します。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=EC2SG,ParameterValue=アカウントAにあるEC2のセキュリティグループID ParameterKey=SourceSecurityGroupOwnerId,ParameterValue=アカウントAのID
デプロイが完了したら以下のコマンドを実行してRDS Aurora MySQLのマスターユーザーのパスワードを確認します。
get-secret-value --secret-id Secrets ManagerのARN --query SecretString
実行すると以下のような結果が返ってきます。
"{\"password\":\"RDS Aurora MySQLのパスワード\",\"username\":\"root\"}"
動作確認
アカウントAのEC2に接続して以下のコマンドを実行してください
パスワードは上記手順で確認したものになります。
mysql -h RDS Aurora MySQLのライターエンドポイント -u root -P 3306 -p
接続ができれば成功です。
さいごに
クロスアカウントでのVPCピアリング設定は初めてやりましたが詰まる部分も無くサクサク進められました。
アプリケーションを乗せたVPCと管理用のVPCで分けたりするときに使えるので手順は覚えておいて損はないといった印象です。