AWS Site-to-Site VPNで使用しているカスタマーゲートウェイをAWS CLIで切り替えてみた
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 コンソール)
疎通確認が成功すれば切り替え完了です。
さいごに
あまり発生しない作業かと思いますがネットワークに関わる作業なのでサクッと切り替えられるように手順は頭の片隅に入れておいてもよいと思いました。