AWS Site-to-Site VPN 接続を検証してみた

こんにちは、SCSKの内ヶ島です。

オンプレミス環境から手軽にAWS Site-to-Site VPN接続の検証環境を構築する方法を紹介します。
この記事では、CloudFormationを使った環境を一括管理し、Amazon Linux 2023のリポジトリに含まれるLibreswanを用いてVPN接続を行います。

はじめに

AWS Site-to-Site VPN接続は、オンプレミス環境とAWS環境を安全に接続するための重要な技術です。
しかし、VPN接続の検証には通常、実機のVPN機器が必要となりハードルが高いものでした。
そこで今回の検証では、以下の2点を主な目標として設定しました。

  1. ソフトウェアVPNを用いてVPN接続が正常に機能すること
  2. 環境全体をCloudFormationで管理し、簡単に作成・削除できること

実機のVPN機器がなくても、AWSの環境内で完結した形でVPN接続の検証が可能になります。
また、CloudFormationを活用することで、環境の再現性と管理の容易さを実現しています。

環境構成

今回構築する環境は以下の通りです。

  • オンプレミス側(AWS上に疑似環境として構築)
      – VPC (10.0.0.0/22)
      – プライベートサブネット (10.0.0.0/24)
      – パブリックサブネット (10.0.1.0/24)
      – EC2インスタンス x2(VPN装置、クライアント想定)
  • AWS側
      – VPC (192.168.0.0/22)
      – プライベートサブネット (192.168.0.0/24)
      – EC2インスタンス(AWSサーバー想定)
      – カスタマーゲートウェイ、仮想プライベートゲートウェイ

CloudFormationテンプレート

今回の検証環境構築には、オンプレミス環境用とAWS環境用の2つのCloudFormationテンプレートを使用しています。

CloudFormationテンプレートの特徴

複雑なVPN検証環境を簡単に、そして再現性高く構築することができます。
両環境とも、インターネットに直接接続せずにパッケージ管理やシステム更新が可能な、セキュアな設計となっています。

以下の内容を生成AIを使ってCloudFormationテンプレートを作成しました。
長いテンプレートの記述ミスや整合性をある程度チェックできるので便利です。

共通の特徴

  • VPC構成: 両テンプレートともVPCとサブネットを設定
  • EC2インスタンス: Amazon Linux 2023のEC2インスタンスを作成
  • セキュリティグループ: 必要最小限のトラフィックのみを許可するセキュリティグループを設定
  • IAMロールとVPCエンドポイント: Systems Manager Session Managerを使用してEC2インスタンスに接続できるよう、必要なIAMロールとVPCエンドポイント(SSM、EC2メッセージ、SSMメッセージ)を設定
  • S3 VPCエンドポイント: EC2インスタンスがインターネットを経由せずにS3にアクセスできるよう、S3用のVPCゲートウェイエンドポイントを設定。これにより、dnfやyumを使用したパッケージのインストールが可能となる。
  • タグ付け: すべてのリソースにタグを付け、管理を容易にしている。タグのプレフィックスはパラメータとして指定可能

オンプレミス環境用テンプレート(Onpre_resource.yaml)の固有の特徴

  • サブネット構成: パブリックサブネットとプライベートサブネットの両方を作成
  • EC2インスタンス(パブリックサブネット): VPN装置役のEC2インスタンス(Elastic IP付与)。ネットワークの送信元/送信先チェックをオフ
  • EC2インスタンス(プライベートサブネット): クライアント役のEC2インスタンス
  • ルーティング: プライベートサブネットからのトラフィックをパブリックEC2インスタンス(疑似NATゲートウェイ)経由でルーティング
  • インターネットゲートウェイ: パブリックサブネット用にインターネットゲートウェイを設定

AWS環境用テンプレート(AWS_resource.yaml)の固有の特徴

  • サブネット構成: プライベートサブネットのみを作成します。
  • VPNリソース: カスタマーゲートウェイ、仮想プライベートゲートウェイ、VPN接続、VPN接続ルートを作成
  • パラメータ: カスタマーゲートウェイのIPアドレスをパラメータとして受け取る
  • EC2インスタンス: プライベートサブネット内に1つのEC2インスタンスを作成(VPN経由でアクセスされるサーバー役)

CloudFormationテンプレート

オンプレミス環境用テンプレート(Onpre_resource.yaml)

AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC with Public and Private Subnets, EC2 Instances, SSM access, and S3 Endpoint'

Parameters:
  TagPrefix:
    Type: String
    Default: '00000'
    Description: 'Prefix for resource tags'
  AmazonLinux2023AMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/22
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-VPC'

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-IGW'

  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Public-Subnet'

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [1, !GetAZs '']
      CidrBlock: 10.0.0.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Private-Subnet'

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Public-RT'

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Private-RT'

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PrivateRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      InstanceId: !Ref PublicEC2Instance

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  PrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable

  PublicSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub '${TagPrefix}-Public-SG'
      GroupDescription: 'Security group for public EC2 instance'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: -1
          FromPort: -1
          ToPort: -1
          CidrIp: 10.0.0.0/22
      SecurityGroupEgress:
        - IpProtocol: -1
          FromPort: -1
          ToPort: -1
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Public-SG'

  PrivateSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub '${TagPrefix}-Private-SG'
      GroupDescription: 'Security group for private EC2 instance'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: -1
          FromPort: -1
          ToPort: -1
          SourceSecurityGroupId: !Ref PublicSecurityGroup
      SecurityGroupEgress:
        - IpProtocol: -1
          FromPort: -1
          ToPort: -1
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Private-SG'

  EndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub '${TagPrefix}-Endpoint-SG'
      GroupDescription: 'Security group for VPC Endpoints'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          SourceSecurityGroupId: !Ref PrivateSecurityGroup
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          SourceSecurityGroupId: !Ref PublicSecurityGroup
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Endpoint-SG'

  PublicEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro
      ImageId: !Ref AmazonLinux2023AMI
      SubnetId: !Ref PublicSubnet
      SecurityGroupIds:
        - !Ref PublicSecurityGroup
      IamInstanceProfile: !Ref EC2InstanceProfile
      SourceDestCheck: false
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Onpre-Public-EC2'

  PrivateEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro
      ImageId: !Ref AmazonLinux2023AMI
      SubnetId: !Ref PrivateSubnet
      SecurityGroupIds:
        - !Ref PrivateSecurityGroup
      IamInstanceProfile: !Ref EC2InstanceProfile
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Onpre-Private-EC2'

  PublicEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      InstanceId: !Ref PublicEC2Instance
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Public-EIP'

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
        - !Ref EC2SSMRole

  S3Endpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
      VpcEndpointType: Gateway
      RouteTableIds:
        - !Ref PrivateRouteTable

  EC2SSMRole:
    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
        - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-EC2-SSM-Role'

  SSMEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssm'
      VpcId: !Ref VPC
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref PrivateSubnet
        - !Ref PublicSubnet
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup

  SSMMessagesEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssmmessages'
      VpcId: !Ref VPC
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref PrivateSubnet
        - !Ref PublicSubnet
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup

Outputs:
  PublicEC2InstanceId:
    Description: 'Public EC2 Instance ID'
    Value: !Ref PublicEC2Instance
  PrivateEC2InstanceId:
    Description: 'Private EC2 Instance ID'
    Value: !Ref PrivateEC2Instance
  PublicEIP:
    Description: 'Elastic IP for Public EC2 Instance'
    Value: !Ref PublicEIP

AWS環境用テンプレート(AWS_resource.yaml)

AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC with Private Subnet, EC2 Instance, Site-to-Site VPN, and S3 Endpoint'

Parameters:
  TagPrefix:
    Type: String
    Default: '00000'
    Description: 'Prefix for resource tags'
  CustomerGatewayIp:
    Type: String
    Description: 'Public IP address of your Customer Gateway'
  AmazonLinux2023AMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64'
    Description: 'Amazon Linux 2023 AMI ID'

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 192.168.0.0/22
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-VPC'

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: 192.168.0.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Private-Subnet'

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-Private-RT'

  PrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable

  VPNSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub '${TagPrefix}-VPN-SG'
      GroupDescription: 'Security group for VPN connection and SSM'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: -1
          FromPort: -1
          ToPort: -1
          CidrIp: 10.0.0.0/22
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 192.168.0.0/22
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-VPN-SG'

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro
      ImageId: !Ref AmazonLinux2023AMI
      SubnetId: !Ref PrivateSubnet
      SecurityGroupIds:
        - !Ref VPNSecurityGroup
      IamInstanceProfile: !Ref EC2InstanceProfile
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-AWS-Private-EC2'

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
        - !Ref EC2SSMRole

  S3Endpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
      VpcEndpointType: Gateway
      RouteTableIds:
        - !Ref PrivateRouteTable

  EC2SSMRole:
    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
        - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-EC2-SSM-Role'

  CustomerGateway:
    Type: AWS::EC2::CustomerGateway
    Properties:
      Type: ipsec.1
      BgpAsn: 65000
      IpAddress: !Ref CustomerGatewayIp
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-CustomerGateway'

  VirtualPrivateGateway:
    Type: AWS::EC2::VPNGateway
    Properties:
      Type: ipsec.1
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-VPNGateway'

  VPNGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      VpnGatewayId: !Ref VirtualPrivateGateway

  VPNConnection:
    Type: AWS::EC2::VPNConnection
    DependsOn:
      - VirtualPrivateGateway
      - VPNGatewayAttachment
    Properties:
      Type: ipsec.1
      CustomerGatewayId: !Ref CustomerGateway
      VpnGatewayId: !Ref VirtualPrivateGateway
      StaticRoutesOnly: true
      Tags:
        - Key: Name
          Value: !Sub '${TagPrefix}-VPNConnection'

  VPNConnectionRoute:
    Type: AWS::EC2::VPNConnectionRoute
    DependsOn: VPNConnection
    Properties:
      DestinationCidrBlock: 10.0.0.0/22
      VpnConnectionId: !Ref VPNConnection

  VPNRoute:
    Type: AWS::EC2::Route
    DependsOn: VPNGatewayAttachment
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 10.0.0.0/22
      GatewayId: !Ref VirtualPrivateGateway

  SSMEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssm'
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref PrivateSubnet
      SecurityGroupIds:
        - !Ref VPNSecurityGroup

  EC2MessagesEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ec2messages'
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref PrivateSubnet
      SecurityGroupIds:
        - !Ref VPNSecurityGroup

  SSMMessagesEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssmmessages'
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref PrivateSubnet
      SecurityGroupIds:
        - !Ref VPNSecurityGroup

Outputs:
  EC2InstanceId:
    Description: 'EC2 Instance ID'
    Value: !Ref EC2Instance
  CustomerGatewayId:
    Description: 'Customer Gateway ID'
    Value: !Ref CustomerGateway
  VirtualPrivateGatewayId:
    Description: 'Virtual Private Gateway ID'
    Value: !Ref VirtualPrivateGateway
  VPNConnectionId:
    Description: 'VPN Connection ID'
    Value: !Ref VPNConnection

環境構築手順

なるべく少ない手数で再現性のある構築を進めるため、CloudShellでAWS CLIを用いて作業します。

AWSマネジメントコンソールの上部または左下の「>_」マークをクリックします。

立ち上がってきたCloudShell画面で「Open <リージョン名> environment」をクリックします。

Shellを打ち込める画面が出てきます。

# タグのプレフィックスを設定(任意の文字列を指定してください)
TAGPREFIX=00000

# オンプレ側構築
aws cloudformation deploy \
    --stack-name "VPNtest-Onpre-${TAGPREFIX}" \
    --template-file Onpre_resource.yaml \
    --capabilities CAPABILITY_IAM \
    --parameter-overrides TagPrefix=${TAGPREFIX}

# オンプレ側のVPN機器となるEC2インスタンスのGlobalIPを取得
GLOBALIP=`aws ec2 describe-addresses --query 'Addresses[].PublicIp' --filter "Name=tag:Name,Values=${TAGPREFIX}-Public-EIP" --output text` && echo ${GLOBALIP}

# AWS側構築
aws cloudformation deploy \
    --stack-name "VPNtest-AWS-${TAGPREFIX}" \
    --template-file AWS_resource.yaml \
    --capabilities CAPABILITY_IAM \
    --parameter-overrides TagPrefix=${TAGPREFIX} CustomerGatewayIp=${GLOBALIP}

VPN設定

AWS Site-to-Site VPNではオンプレ側VPN機器の設定サンプルをダウンロードできます。
オンプレ側ではソフトウェアVPNのLibreswanを使用しますが、該当するものがないので類似するOpenswanの設定サンプルをダウンロードします。

VPN設定ダウンロード

[VPC] – [Site-to-Site VPN 接続]
[設定をダウンロードする]

[ベンダー] Openswan
[プラットフォーム] Openswan
[ソフトウェア] Openswan 2.6.38+
[IKEバージョン] ikev1
を指定し、[ダウンロード]

ここでダウンロードした設定ファイルの一部を用いて、Libreswanの設定をしていきます。

Libreswan設定

LibreswanからAWS Site-to-Site VPNへの接続に利用するトンネルは1本のみとします。(2本用いるHA構成も可能だが「気軽な」検証にならないため)

AWS Systems Manager Session Managerを用いてオンプレ側Public EC2インスタンスにログインします。

[EC2] – [インスタンス] より、ログインしたいインスタンスにチェックを入れ、[接続] をクリックします。

[セッションマネージャー] タブを選択し、[接続] をクリックします。

# Libreswanインストール
sudo dnf install -y libreswan

# カーネルパラメータ修正
echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.d/custom-ip-forwarding.conf
sudo sysctl -p /etc/sysctl.d/custom-ip-forwarding.conf

# Libreswan設定
sudo vi /etc/ipsec.conf

config setup ブロックに下記設定のみを追記します。
        protostack=netkey

# ダウンロードしたVPN設定から接続部分を抜き出して貼り付け、内容を書き換える
# Tunnel1の部分のみ。
sudo vi /etc/ipsec.d/aws.conf

conn Tunnel1
    authby=secret
    auto=start
    left=%defaultroute
    leftid=<オンプレ側のGlobalIP>    # 記載のものをそのまま入力
    right=<AWS側のGlobalIP>          # 記載のものをそのまま入力
    type=tunnel
    ikelifetime=8h
    keylife=1h
    phase2alg=aes128-sha1;modp2048  # 末尾のmodp1024をmodp2048に変更
    ike=aes128-sha1;modp2048        # 末尾のmodp1024をmodp2048に変更
    auth=esp                        # この行は削除
    keyingtries=%forever
    keyexchange=ike
    leftsubnet=10.0.0.0/22          # leftがオンプレ側(今設定しているほう)
    rightsubnet=192.168.0.0/22      # rightがAWS側
    dpddelay=10
    dpdtimeout=30                   # この行は削除
    retransmit-timeout=30s          # この行を追加
    dpdaction=restart_by_peer

# シークレット情報を張り付ける
# ※Tunnel1もののみをそのまま貼り付け、Tunnel2のキーは貼り付けない
sudo vi /etc/ipsec.d/aws.secrets

<オンプレ側のGlobalIP> <AWS側のGlobalIP>: PSK "<キー情報>"

sudo systemctl start ipsec
sudo systemctl status ipsec

exit

VPNトンネル接続確認

[VPC] – [Site-to-Site VPN]
作成したVPN接続を選択
[トンネルの詳細] タブを選択

1つのトンネルが接続されていることを確認します。(リロードしながら少し待つ必要があります)
もう一つはダウンのままで構いません。

接続確認

IPアドレスを確認

TAGPREFIX=00000
aws ec2 describe-instances \
    --filters "Name=instance-state-name,Values=running" "Name=tag:Name,Values=*${TAGPREFIX}*" \
    --query "Reservations[*].Instances[*].[PrivateIpAddress, Tags[?Key=='Name'].Value | [0]]" \
    --output text

以下のようにIPアドレスが出力されます。このIPアドレスを用いて接続確認をしていきます。

10.0.0.148      00000-Onpre-Private-EC2
192.168.0.34    00000-AWS-Private-EC2
10.0.1.145      00000-Onpre-Public-EC2

通信確認

pingによる通信確認

AWS Systems Manager Session Managerを用いてオンプレ側プライベートEC2へログインします。

# AWS側プライベートEC2のIPに向けて通信確認
ping 192.168.0.34

→オンプレ側からAWS側へ通信できることを確認します。

同じく、AWS側プライベートEC2へログインします。

ping 10.0.0.148

→AWS側からオンプレ側へ通信できることを確認します。

HTTPによる通信確認

AWS側プライベートEC2で下記を実行します。

cd ~
touch iam_aws_private
python3 -m http.server 8000

今度は、オンプレ側プライベートEC2で下記を実行します。

curl 192.168.0.34:8000

→ディレクトリの中身が見えることを確認します(VPN接続先のiam_aws_privateファイルが見える)

AWS側プライベートEC2で、オンプレ側からアクセスがあったログを確認できます。

オンプレ側の通信確認

AWS側の通信確認

トラブルシューティング

VPN接続で問題が発生した場合は、以下の点を確認してください

  • セキュリティグループの設定
  • ルートテーブルの設定
  • Libreswanの設定ファイル
  • VPNログ(sudo journalctl -u ipsec)

クリーンアップ

検証が終わったら、以下のコマンドで環境を削除します

# CloudFormationスタックを削除
aws cloudformation delete-stack --stack-name "VPNtest-Onpre-${TAGPREFIX}"
aws cloudformation delete-stack --stack-name "VPNtest-AWS-${TAGPREFIX}"

# スタック削除を待つ
aws cloudformation wait stack-delete-complete --stack-name "VPNtest-Onpre-${TAGPREFIX}" &
aws cloudformation wait stack-delete-complete --stack-name "VPNtest-AWS-${TAGPREFIX}" &
wait

# 2つのスタックが削除され、プロンプトが戻れば終了

CloudShellの終了は、CloudShell画面の [アクション] – [削除] を選択し、表示された確認画面で「delete」と入力し、[削除] ボタンを押します。

参考資料

ソフトウェア VPN から AWS Site-to-Site VPN
https://docs.aws.amazon.com/ja_jp/whitepapers/latest/aws-vpc-connectivity-options/software-vpn-to-aws-site-to-site-vpn.html

OS設定でNATインスタンスのチュートリアルを参考にしました(特にnet.ipv4.ip_forward=1の設定)
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/work-with-nat-instances.html

SSMへの接続用VPCエンドポイントを作成の際、ec2messages:* エンドポイントは作成の必要がなくなりました。https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-setting-up-messageAPIs.html

SSM Agent のバージョン 3.3.40.0 以降、Systems Manager は、使用可能な場合には ec2messages:* エンドポイント (Amazon Message Delivery Service) の代わりに ssmmessages:* エンドポイント (Amazon Message Gateway Service) を使用するようになりました。

 

まとめ

今回の記事では、AWSでのSite-to-Site VPN接続の検証環境構築方法を紹介しました。CloudFormationを使うことで、複雑な環境も簡単に構築・管理できることがお分かりいただけたかと思います。

実際の本番環境では、セキュリティやパフォーマンスなどさらに考慮すべき点がありますが、この記事がVPN検証の参考になれば幸いです。

タイトルとURLをコピーしました