AWSでOpenVPNを使った固定IPインターネット接続環境を作成する方法

IP接続制限をかけたサーバーにアクセスする場合には、あらかじめアクセスを許可したIPアドレスを登録しておく必要がありますが、昨今ではDS-LiteやMAP-Eなどで共有グローバルIPアドレスが利用されていることから、意図せず不特定多数の人のアクセスを許してしまう危険性があります。

プロバイダーが提供している固定IPサービスを利用していない(提供がない)場合は民営のVPNの固定IPサービスを利用する方法もありますが、後者は手軽で安価に利用できる一方、秘匿性が高いデータを国内外のサーバーに経由することへの懸念や、スループットが問題となる場合も多々あるかと思います。

そこで、今回はAWSのEC2/VPC/EIPとOpenVPNサーバーを使い、お手軽に自分専用の固定IP VPN環境を構築する方法を紹介します。

ちなみに本記事では解説していませんが、WireGuardを追加インストールしてSecurityGroupのWireGuardポートを開放すれば、WireGuardを利用することも可能です(WireGuardサーバーは設定が簡単)。

EC2/EBS(gp2)/EIP/データ転送(アウト)には従量課金でコストが掛かりますのでご注意ください。
参考として2024.8現在でリージョンがap-northeast-1の場合は
・t3.nano … USD $0.0052/時間
・gp2(1GBあたり) … $0.1/月
・EIP … $0.005/時間
・データ転送(10TB以下) … $0.114/GB
・上記合計の消費税
位でした。

AWSは設定を誤ったりリソースを使いすぎると青天井の請求が発生することになります。意図しない高額請求を防ぐためにも予算アラートをセットしたうえで定期的にモニタリングするなど、十分に注意してください(At your own risk!)。


AWSを構成

XXXXはご自身が識別できる任意のIDを指定してください。

xxx.xxx.xxx.xxxは、SSHやVPN接続を許可する自ホストのグローバルIPアドレスです。

yyy.yyy.yyy.yyyは、ElasticIPで割り当てられたグローバル固定IPアドレスです。

デプロイ先のリージョン設定に注意してください。どの国のIPアドレスが利用されるかだけでなく、通信速度やコストなどにも影響します。

1. EC2 SSHログイン用のキーペアの作成

AWSコンソールにログインしてサイドメニューのキーペアからキーペア作成画面を表示します。

file

キーペアの名前にはKeyPair-XXXX-MyVPNを指定、他は初期値です。

file

2. CloudFormation定義ファイルの作成

Elastic IPを定義します。
後で同じIPアドレスを再利用できるように今回は別スタックとして定義します。

XXXX-MyVPN-EIP/template.yaml

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Stack for Elastic IP

Resources:
  MyEIP:
    Type: AWS::EC2::EIP
    Properties: {}

Outputs:
  EIPAllocationId:
    Description: The allocation ID of the EIP
    Value: !GetAtt MyEIP.AllocationId
    Export:
      Name: EIPStack-EIPAllocationId-XXXX

Elastic Compute CloudやVirtual Private Cloudを定義します。
EC2のインスタンスはt3.nanoを使用します。ベースとなるAMIはAmazon Linux 2 AMI (HVM) - Kernel 5.10, SSD Volume Typeです。

XXXX-MyVPN/template.yaml

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: OpenVPN Server on EC2 with Elastic IP

Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: VPC-XXXX-MyVPN

  MySubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs ""]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: Subnet-XXXX-MyVPN

  MyInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: Gateway-XXXX-MyVPN

  GatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref MyVPC
      InternetGatewayId: !Ref MyInternetGateway

  MyRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref MyVPC
      Tags:
        - Key: Name
          Value: RouteTable-XXXX-MyVPN

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: GatewayAttachment
    Properties:
      RouteTableId: !Ref MyRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref MyInternetGateway

  SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref MySubnet
      RouteTableId: !Ref MyRouteTable

  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.nano
      ImageId: ami-03d25459ad01ac2b9
      KeyName: KeyPair-XXXX-MyVPN
      SecurityGroupIds:
        - !Ref MySecurityGroup
      SubnetId: !Ref MySubnet
      IamInstanceProfile: !Ref MyInstanceProfile
      Tags:
        - Key: Name
          Value: EC2-XXXX-MyVPN

  MyEIPAssociation:
    Type: AWS::EC2::EIPAssociation
    Properties:
      InstanceId: !Ref MyEC2Instance
      AllocationId: !ImportValue EIPStack-EIPAllocationId-XXXX

  MySecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow SSH and VPN traffic
      VpcId: !Ref MyVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: xxx.xxx.xxx.xxx/32
        - IpProtocol: udp
          FromPort: 1194
          ToPort: 1194
          CidrIp: xxx.xxx.xxx.xxx/32
      Tags:
        - Key: Name
          Value: SecurityGroup-XXXX-MyVPN

  MyInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref MyRole

  MyRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: [ec2.amazonaws.com]
            Action: ["sts:AssumeRole"]

3. AWSへのデプロイ

AWS CLIを使ってデプロイを行います。

cd XXXX-MyVPN-EIP
aws cloudformation deploy --template-file template.yaml --stack-name XXXX-MyVPN-EIP

cd XXXX-MyVPN
aws cloudformation deploy --template-file template.yaml --stack-name XXXX-MyVPN


OpenVPNの準備

EC2が起動したらSSHでログインしてOpenVPNサーバーのインストールと設定などを行います。

1. EC2にSSHでログイン

ssh -i ~/.ssh/KeyPair-XXXX-MyVPN.pem ec2-user@yyy.yyy.yyy.yyy

2. パッケージのインストール

# EPELをインストール
amazon-linux-extras install epel -y
# openvpn/easy-rsaパッケージをインストール
yum install openvpn easy-rsa -y

3. サーバー証明書の作成

cd /etc/openvpn
# 作業ディレクトリ作成
sudo mkdir -p /etc/openvpn/easy-rsa
# PKIを初期化
sudo ./easyrsa init-pki
# CA証明書の生成(パスフレーズなし)
sudo ./easyrsa build-ca nopass
# サーバーの証明書要求ファイル(CSR)と秘密鍵を生成(パスフレーズなし)
sudo ./easyrsa gen-req server nopass
# サーバー証明書に署名
sudo ./easyrsa sign-req server server
# DH鍵交換パラメータの生成
sudo ./easyrsa gen-dh

4. クライアント証明書の作成

# クライアントの証明書要求ファイル(CSR)と秘密鍵を生成(パスフレーズなし)
sudo ./easyrsa gen-req ClientHostName nopass
# クライアント証明書に署名
sudo ./easyrsa sign-req client ClientHostName

5. TLS認証鍵の作成

# TLS認証鍵の生成
sudo openvpn --genkey --secret ta.key

6. 鍵と証明書の配置

# 生成した鍵と証明書などを/etc/openvpnにコピー
sudo cp pki/ca.crt pki/private/server.key pki/issued/server.crt ta.key pki/dh.pem /etc/openvpn/

ファイアウォールの設定

EC2にNATとフィルタリングの設定を行います。

# IPマスカレード
sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/16 -o eth0 -j MASQUERADE
# ステートフルパケットインスペクション
sudo iptables -A FORWARD -s 10.0.0.0/16 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -d 10.0.0.0/16 -j ACCEPT

OpenVPNサーバーの設定

今回はクライアント証明書を使った認証で設定しています。
VPNネットワークのローカルIPアドレスは10.0.2.0/24、DNSはセキュアDNSのQuad9を指定しています。

/etc/openvpn/server.conf

port 1194
proto udp

dev tun

ca ca.crt
cert server.crt
key server.key
dh dh.pem
tls-auth ta.key 0

auth SHA512
cipher AES-256-CBC
ncp-ciphers AES-256-GCM:AES-128-GCM

user nobody
group nobody

persist-key
persist-tun

keepalive 10 120

status openvpn-status.log
log-append /var/log/openvpn.log

verb 3

tls-server
mode server

push "dhcp-option DNS 9.9.9.9"
push "redirect-gateway def1 bypass-dhcp"

server 10.0.2.0 255.255.255.0

compress

OpenVPNクライアントの設定

証明書関連はovpnファイルに埋め込んでいます。
yyy.yyy.yyy.yyyはElasticIPのアドレス、<ca>/<tls-auth>/<key>/<cert>は前手順で作成したファイルの内容に置き換えてください。

myvpn.ovpn

client
dev tun

proto udp
remote yyy.yyy.yyy.yyy 1194
resolv-retry infinite
nobind

persist-key
persist-tun

cipher AES-256-CBC
auth SHA512
key-direction 1
remote-cert-tls server

tun-mtu 1500
mssfix 1450
ping 15
ping-restart 0
reneg-sec 0

compress

verb 3
fast-io

<ca>
-----BEGIN CERTIFICATE-----
*** ca.crtの内容に置き換え ***
-----END CERTIFICATE-----
</ca>
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
*** ta.keyの内容に置き換え ***
-----END OpenVPN Static key V1-----
</tls-auth>
<key>
-----BEGIN PRIVATE KEY-----
*** ClientHostName.keyの内容に置き換え ***
-----END PRIVATE KEY-----
</key>
<cert>
-----BEGIN CERTIFICATE-----
*** ClientHostName.crtの内容に置き換え ***
-----END CERTIFICATE-----
</cert>

OpenVPNサーバー起動

# OpenVPNサービスを起動
sudo systemctl start openvpn@server
# サービスを自動起動させる場合
sudo systemctl enable openvpn@server


上記設定完了後にVPNクライアントに接続してIPinfoなどにアクセスすると、VPNの固定IPアドレスからインターネットアクセスできていることが確認できるかと思います。
ちなみにデフォルトではAWSのドメイン名が逆引き設定されていますが、独自ドメインを持っていてDNSサーバーがホスティングされていれば、自前ドメインにIP逆引き設定することも可能です。


参考WEBサイトなど

  • AWS Docs
    AWS SAM CLI のインストール


以上です。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする