AWS Site-to-Site VPNで使用しているカスタマーゲートウェイを切り替える機会があったのでブログに残します。
どんな時にカスタマーゲートウェイを切り替えるのか
以下のドキュメントの通りカスタマーゲートウェイで使用しているパブリックIPアドレスが変更された場合などに行う作業になります。
AWS VPN 接続のカスタマーゲートウェイのパブリック IP アドレスを変更するにはどうすればよいですか?
検証で作成する環境
今回検証で作成する環境は以下の構成図の通りになります。
自宅にVPNルーターを準備する余裕が無かったので東京リージョンにVPCを2つ作成して、VyOSのAMIでEC2を起動後にVPN接続の設定を行います。
構成図の切り替え元VyOSとVPN接続ができたらカスタマーゲートウェイを切り替えます。
VyOSでのVPN設定は以下のブログを参考にしました。
VPN設定
まずは構成図に記載したAWSリソースを作成していきます。
作成にはCloudFormationを利用しました。
以下のCloudFormationテンプレートで構成図左側にあるVGWが紐づくVPCを作成を作成します。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: EC2 Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for VPC
Parameters:
- VPCCIDR
- Label:
default: Parameters for Subnet
Parameters:
- PublicSubnet01CIDR
- Label:
default: Parameters for EC2
Parameters:
- EC2VolumeSize
- EC2VolumeIOPS
- EC2AMI
- EC2InstanceType
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
VPCCIDR:
Default: 172.16.0.0/16
Type: String
PublicSubnet01CIDR:
Default: 172.16.0.0/24
Type: String
EC2VolumeSize:
Default: 30
Type: Number
EC2VolumeIOPS:
Default: 3000
Type: Number
EC2AMI:
Default: ami-06ee4e2261a4dc5c3
Type: AWS::EC2::Image::Id
EC2InstanceType:
Default: t3.micro
Type: String
Resources:
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: vpn-test-vpc
# ------------------------------------------------------------#
# InternetGateway
# ------------------------------------------------------------#
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: vpn-test-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: vpn-test-public-subnet-01
VpcId: !Ref VPC
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: vpn-test-public-rtb
PublicRouteTableRoute1:
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
# ------------------------------------------------------------#
# 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
# ------------------------------------------------------------#
# Security Group
# ------------------------------------------------------------#
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for ec2
GroupName: vpn-test-sg-ec2-ping
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
SecurityGroupIngress:
- CidrIp: 192.168.0.0/16
FromPort: -1
IpProtocol: icmp
ToPort: -1
Tags:
- Key: Name
Value: vpn-test-sg-ec2-ping
VpcId: !Ref VPC
# ------------------------------------------------------------#
# KeyPair
# ------------------------------------------------------------#
KeyPair:
Type: AWS::EC2::KeyPair
Properties:
KeyName: vpn-test-ec2-key
KeyType: rsa
Tags:
- Key: Name
Value: vpn-test-ec2-key
# ------------------------------------------------------------#
# 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
EbsOptimized: true
IamInstanceProfile: !Ref EC2IAMInstanceProfile
ImageId: !Ref EC2AMI
InstanceType: !Ref EC2InstanceType
KeyName: !Ref KeyPair
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref EC2SG
SubnetId: !Ref PublicSubnet01
Tags:
- Key: Name
Value: vpn-test-ec2-ping
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
VPCID:
Value: !Ref VPC
Export:
Name: VPCID
PublicRouteTableID:
Value: !Ref PublicRouteTable
Export:
Name: PublicRouteTableID
EC2IAMInstanceProfileName:
Value: !Ref EC2IAMInstanceProfile
Export:
Name: iam-instanceprofile-ec2
こちらのCloudFormationテンプレートではVPCと疎通確認用のEC2が作成されます。
以下のコマンドでデプロイします。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --capabilities CAPABILITY_NAMED_IAM
スタックが作成されたらVyOS側を作成します。
以下のCloudFormationテンプレートで作成します。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: VyOS Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for VPC
Parameters:
- VPCCIDR
- Label:
default: Parameters for Subnet
Parameters:
- PublicSubnet01CIDR
- Label:
default: Parameters for EC2
Parameters:
- MyIP
- EC2VolumeSize
- EC2VolumeIOPS
- EC2AMI
- VyOSAMI
- EC2InstanceType
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
VPCCIDR:
Default: 192.168.0.0/16
Type: String
PublicSubnet01CIDR:
Default: 192.168.0.0/24
Type: String
MyIP:
Type: String
EC2VolumeSize:
Default: 30
Type: Number
EC2VolumeIOPS:
Default: 3000
Type: Number
EC2AMI:
Default: ami-06ee4e2261a4dc5c3
Type: AWS::EC2::Image::Id
VyOSAMI:
Default: ami-0965b2be3f08e4cc4
Type: AWS::EC2::Image::Id
EC2InstanceType:
Default: t3.micro
Type: String
Resources:
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: vyos-test-vpc
# ------------------------------------------------------------#
# InternetGateway
# ------------------------------------------------------------#
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: vyos-test-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: vyos-test-public-subnet-01
VpcId: !Ref VPC
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: vyos-test-public-rtb
PublicRouteTableRoute1:
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
# ------------------------------------------------------------#
# Security Group
# ------------------------------------------------------------#
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for ec2
GroupName: vyos-test-sg-ec2-ping
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
SecurityGroupIngress:
- CidrIp: 172.16.0.0/16
FromPort: -1
IpProtocol: icmp
ToPort: -1
Tags:
- Key: Name
Value: vyos-test-sg-ec2-ping
VpcId: !Ref VPC
VyOSSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for VyOS
GroupName: vyos-test-sg-ec2-vpn
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
SecurityGroupIngress:
- CidrIp: !Ref MyIP
FromPort: 22
IpProtocol: tcp
ToPort: 22
- CidrIp: 192.168.0.0/16
FromPort: -1
IpProtocol: icmp
ToPort: -1
Tags:
- Key: Name
Value: vyos-test-sg-ec2-vpn
VpcId: !Ref VPC
# ------------------------------------------------------------#
# KeyPair
# ------------------------------------------------------------#
KeyPair:
Type: AWS::EC2::KeyPair
Properties:
KeyName: vyos-test-ec2-key
KeyType: rsa
Tags:
- Key: Name
Value: vyos-test-ec2-key
# ------------------------------------------------------------#
# 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
EbsOptimized: true
IamInstanceProfile: !ImportValue iam-instanceprofile-ec2
ImageId: !Ref EC2AMI
InstanceType: !Ref EC2InstanceType
KeyName: !Ref KeyPair
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref EC2SG
SubnetId: !Ref PublicSubnet01
Tags:
- Key: Name
Value: vyos-test-ec2-ping
VyOS1EC2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
VolumeSize: !Ref EC2VolumeSize
VolumeType: gp2
DisableApiTermination: false
EbsOptimized: true
ImageId: !Ref VyOSAMI
InstanceType: t3.small
KeyName: !Ref KeyPair
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref VyOSSG
SubnetId: !Ref PublicSubnet01
SourceDestCheck: false
Tags:
- Key: Name
Value: vyos-test-ec2-vpn1
VyOS2EC2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
VolumeSize: !Ref EC2VolumeSize
VolumeType: gp2
DisableApiTermination: false
EbsOptimized: true
ImageId: !Ref VyOSAMI
InstanceType: t3.small
KeyName: !Ref KeyPair
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref VyOSSG
SubnetId: !Ref PublicSubnet01
SourceDestCheck: false
Tags:
- Key: Name
Value: vyos-test-ec2-vpn2
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
VyOS1EC2PublicIP:
Value: !GetAtt VyOS1EC2.PublicIp
Export:
Name: VyOS1EC2PublicIP
VyOS2EC2PublicIP:
Value: !GetAtt VyOS2EC2.PublicIp
Export:
Name: VyOS2EC2PublicIP
こちらのCloudFormationテンプレートではVyOSのAMIを使用したEC2と疎通確認用のEC2が起動します。
以下のコマンドでデプロイします。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --capabilities CAPABILITY_NAMED_IAM --parameters ParameterKey=MyIP,ParameterValue=VyOSへSSHする接続元のIPアドレス
VyOSへSSHする接続元のIPアドレスは「/32」でサブネットマスクを設定します。
スタックが作成されたらカスタマーゲートウェイとVGW周りを作成していきます。
以下のCloudFormationテンプレートで作成します。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: VPN Stack
Resources:
# ------------------------------------------------------------#
# CustomerGateway
# ------------------------------------------------------------#
CustomerGateway1:
Type: AWS::EC2::CustomerGateway
Properties:
BgpAsn: 65000
DeviceName: vyos-test-ec2-vpn1
IpAddress: !ImportValue VyOS1EC2PublicIP
Tags:
- Key: Name
Value: vyos-test-ec2-vpn1
Type: ipsec.1
CustomerGateway2:
Type: AWS::EC2::CustomerGateway
Properties:
BgpAsn: 65000
DeviceName: vyos-test-ec2-vpn2
IpAddress: !ImportValue VyOS2EC2PublicIP
Tags:
- Key: Name
Value: vyos-test-ec2-vpn2
Type: ipsec.1
# ------------------------------------------------------------#
# VPNGateway
# ------------------------------------------------------------#
VPNGateway:
Type: AWS::EC2::VPNGateway
Properties:
Tags:
- Key: Name
Value: test-vgw
Type: ipsec.1
VPNGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !ImportValue VPCID
VpnGatewayId: !Ref VPNGateway
# ------------------------------------------------------------#
# VPNConnection
# ------------------------------------------------------------#
VPNConnection:
Type: AWS::EC2::VPNConnection
Properties:
CustomerGatewayId: !Ref CustomerGateway1
StaticRoutesOnly: false
Tags:
- Key: Name
Value: test-vpn-connection
Type: ipsec.1
VpnGatewayId: !Ref VPNGateway
VPNGatewayRoutePropagation:
Type: AWS::EC2::VPNGatewayRoutePropagation
DependsOn: VPNGatewayAttachment
Properties:
RouteTableIds:
- !ImportValue PublicRouteTableID
VpnGatewayId: !Ref VPNGateway
こちらのCloudFormationテンプレートではカスタマーゲートウェイ、VGW、VPN接続が作成されます。
また、62行目~68行目でルートのルート伝播を有効にしています。
ルート伝播を有効にするとカスタマーゲートウェイ側(VyOS側)から広告されてきたルーティング情報をルートテーブルに自動で登録してくれます。
以下のコマンドでデプロイします。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --capabilities CAPABILITY_NAMED_IAM
スタックが作成されたらVyOSにVPN設定を入れていきます。
以下の手順でマネジメントコンソールからVyOSのサンプルコンフィグをダウンロードしてきます。
マネジメントコンソールからVPCダッシュボードへ移動します。
移動したら画面左の項目から「Site-to-Site VPN 接続」をクリックします。
画面が遷移したら「Name」列が「test-vpn-connection」のものを選択して右上の「設定をダウンロードする」をクリックします。
クリックしたらベンダーなどの情報を以下の画像の通り選択して「ダウンロード」をクリックします。
ダウンロードしたサンプルコンフィグはそのままでは使用できないので少し修正します。
set vpn ipsec site-to-site peer ピアIPアドレス local-address 'VyOS EC2のグローバルIPアドレス'
set protocols bgp 65000 neighbor ネイバーIPアドレス soft-reconfiguration 'inbound'
set protocols bgp 65000 network 0.0.0.0/0
上記の部分を以下のように変更します。
set vpn ipsec site-to-site peer ピアIPアドレス local-address 'VyOS EC2のローカルIPアドレス'
set protocols bgp 65000 neighbor ネイバーIPアドレス address-family ipv4-unicast soft-reconfiguration 'inbound'
set protocols bgp 65000 address-family ipv4-unicast network 192.168.0.0/16
ローカルIPに修正しているのはEC2が直接グローバルIPを持っているわけではなくNATしてプライベートIPに紐づけているためです。
以下のドキュメントに記載されています。
パブリック IPv4 アドレス
サブネットで作成されたネットワークインターフェイスがパブリック IPv4 アドレス (このトピックではパブリック IP アドレスと呼ばれる) を自動的に受信するかどうかを判断する属性が、すべてのサブネットにあります。したがって、この属性が有効になっているサブネットに対してインスタンスを起動すると、パブリック IP アドレスがそのインスタンス用に作成されたプライマリネットワークインターフェイス (eth0) に割り当てられます。パブリック IP アドレスは、ネットワークアドレス変換 (NAT) によって、プライマリプライベート IP アドレスにマッピングされます。
修正したらVyOSのEC2へSSHします。
SSHに使用する鍵はSystems Managerのパラメータストアに保存されています。
SSHは以下のコマンドで行いました。
ssh -i 秘密鍵ファイル名.pem vyos@VyOS EC2のグローバルIPアドレス
設定をするには以下のコマンドでConfiguration Modeに移動します。
configure
Configuration Modeに移動したら修正したサンプルコンフィグの設定を入れていきます。
設定を入れたら以下のコマンドで保存します。
commit
save
設定が上手くできているとVPNトンネルが2つともUPになります。
UPになったことが確認できたらもう一台のVyOSにも設定を入れていきます。(IPアドレスは適所変更してください。)
ここまで完了したらVyOSが起動しているサブネットのルートテーブルを修正します。
マネジメントコンソールからVPCダッシュボードへ移動します。
移動したら画面左の項目から「ルートテーブル」をクリックします。
画面が遷移したら「Name」列が「vyos-test-public-rtb」のものを選択して右上の「アクション」から「ルートを編集」をクリックします。
クリックしたら「送信先」を「172.16.0.0/16」にして「ターゲット」をVPNを張っているVyOS EC2のENIのIDにしたルートを追加します。
これを入れることで疎通確認用のEC2から通信できるようになります。
疎通確認は以下のドキュメントの手順でNameタグが「vyos-test-ec2-ping」のEC2に接続して「vpn-test-ec2-ping」のプライベートIPアドレス宛にpingを実行します。
セッションを開始する (Amazon EC2 コンソール)
ここまででVPNの設定は完了です。
カスタマーゲートウェイの切り替え
ここから本題のカスタマーゲートウェイの切り替えを行います。
マネジメントコンソールから行う手順としては以下のドキュメントの通りです。
Site-to-Site VPN 接続のカスタマーゲートウェイの変更
今回はAWS CLIで切り替えてみます。
以下のコマンドで切り替えます。
aws ec2 modify-vpn-connection --vpn-connection-id VPN ID --customer-gateway-id 切り替え先のカスタマーゲートウェイID
実行するとVPN接続の「状態」列が「Modifying」になります。
少し待つと「状態」列が「Available」になります。
トンネルの「ステータス」列も少し待つとUPになります。
UPになったらVyOSが起動しているサブネットのルートテーブルを修正します。
今度は切り替え先のVyOS EC2のENI IDをターゲットにします。
ルート変更後、以下のドキュメントの手順でNameタグが「vyos-test-ec2-ping」のEC2に接続して「vpn-test-ec2-ping」のプライベートIPアドレス宛にpingを実行します。
セッションを開始する (Amazon EC2 コンソール)
疎通確認が成功すれば切り替え完了です。
さいごに
あまり発生しない作業かと思いますがネットワークに関わる作業なのでサクッと切り替えられるように手順は頭の片隅に入れておいてもよいと思いました。