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コンソールにログインしてサイドメニューのキーペア
からキーペア作成画面を表示します。
キーペアの名前
にはKeyPair-XXXX-MyVPN
を指定、他は初期値です。
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 のインストール
以上です。