さくらのVPS上にOpenVPN
サーバーを建てた奮闘記です。
OpenSSL 3.1.0
を使ってビルドし、もちろんIPv6
にも対応します。
加えてOpenVPN 2.6.0
からサポートされた高速化機能であるDCO(Data Channel Offload)
を有効にします。
きっかけ
僕は大のアニメ好きでdアニメストア
を心から愛用しています。
電車や駅、ホテルなどの公共Wi-Fiでdアニメストア
に接続することも多々ありますが、セキュリティ的にVPN
を通して接続したいと思っていました。
しかし、dアニメストア
は海外からの接続を拒否しており、一般のVPNやAWS
に建てていたOpenVPN
サーバーからでは接続できませんでした。
VPNで日本のサーバーを選択したり、AWSで東京リージョンを通して接続しても海外からのアクセスと判定されてしまいます。
そこでさくらのVPS
ならば日本からのアクセスとして認定していただけるのではと思い建設を決意した次第です。
一応結論を先に申し上げると、無事にさくらのVPS
上のOpenVPN
を通してdアニメストア
にアクセスできました。
環境
さくらのVPS 大阪
512MBプラン
Rockey LINUX 5.14.0
必要なもの
入ってるものも多いと思いますが一応。
sudo yum install wget git tar make gcc perl libnl3-devel libcap-ng-devel systemd-devel pam-devel
OpenSSL
OpenSSL 3.1.0
が正式にリリースされましたので折角ですから導入します。
標準のOpenSSL
でよい人は読み飛ばしてください。
wget https://www.openssl.org/source/openssl-3.1.0.tar.gz # 下記リンクを参照して最新版を入れてください
tar -xf openssl-3.1.0.tar.gz
cd openssl-3.1.0
./config shared --prefix=/opt/openssl # お好きなディレクトリにどうぞ
make
make test # 結構時間かかります
# PASS とでればOK
sudo make install
OpenSSL公式に最新版へのリンクがありますので必ず最新のものを引っ張ってきてください。
--prefix
を付けないと現行版と衝突します。
ライブラリを置き換えちゃったりするとsudo
やらssh
が使えなくなって死するのでお気を付けください。(経験者)
使えるように
上記手順ではopenssl version
しても既存のものが出てきます。
パッケージ管理ツールではない管理をするのは望ましくないので問題ないと思いますが、新しいものを常用するには以下の手順を踏んでください。
cd
nano .bashrc
以下を追記。
alias openssl="/opt/openssl/bin/openssl"
環境変数を設定します。
cd
nano .bash_profile
以下を追記。
export LD_LIBRARY_PATH="/opt/openssl/lib64"
環境によっては/opt/openssl/lib
に入っている場合があります。
エラーになったら確認してみてください。
その場合は以降のコマンド全てを読み替えてください。
OpenVPN
それでは本命のOpenVPN
を導入していきます。
wget https://swupdate.openvpn.org/community/releases/openvpn-2.6.3.tar.gz # 下記リンクを参照
tar -xf openvpn-2.6.3.tar.gz
cd openvpn-2.6.3
./configure --enable-systemd --disable-lz4 --disable-lzo PKG_CONFIG_PATH=/opt/openssl/lib64/pkgconfig # 環境によっては"/opt/openssl/lib/pkgconfig"
make
make check # "All * tests passed" とでればOK
sudo make install
OpenVPN公式を参照して最新のものを導入してください。
スクロールしていってSource archive file
とあるものです。
何もしないとpkg-config
がデフォルトのOpenSSL
を探しに行くのでビルドした方のパスを渡して上書きします。
ここに行きつくまで./configure
にCFLAG
やらLDFLAGS
やら渡してごにょごにょしていましたが、これで一発です。
pkg-config
に乾杯。
openvpn --version
して正しく表示されれば無事インストール完了です。
easyrsa
VPN接続用の認証局を作ります。
cd /opt # お好きなディレクトリにどうぞ
sudo git clone https://github.com/OpenVPN/easy-rsa.git
cd easy-rsa/easyrsa3
sudo ./easyrsa init-pki
sudo nano pki/vars
Easy-RSA
の設定であるvars
ファイルを編集します。
僕の設定で変更している変数だけ書き出します。
該当する箇所を探してコメントアウトを外して書き換えてください。
私的に好みな強めセキュア設定になっていますのでお好みでどうぞ。
# "openssl 3.1.0"のインストール先を指定します
set_var EASYRSA_OPENSSL "/opt/openssl/bin/openssl"
# 安全で速くてつよつよのツイステッドエドワーズ曲線を使います
set_var EASYRSA_ALGO ed
set_var EASYRSA_CURVE ed25519
# 暗号の桁数を上げます
set_var EASYRSA_DIGEST "sha512"
##
# 以下はちょくちょく見かける誤った情報の訂正です
##
# 上のEASYRSA_ALGOがrsaの場合以外は鍵長の設定は不要で変更しても無視されます
# 安全性的にはデフォルトで十分で、変更する場合も4096が多くのデバイスで使用できる現実的な最長です
#set_var EASYRSA_KEY_SIZE 2048
# EASYRSA_DNを"cn_only"に設定している場合(デフォルト)、以下の値は無視されるので設定不要です
#set_var EASYRSA_REQ_COUNTRY "US"
#set_var EASYRSA_REQ_PROVINCE "California"
#set_var EASYRSA_REQ_CITY "San Francisco"
#set_var EASYRSA_REQ_ORG "Copyleft Certificate Co"
#set_var EASYRSA_REQ_EMAIL "me@example.net"
#set_var EASYRSA_REQ_OU "My Organizational Unit"
編集が完了したら作業を続行します。
# [1] 認証局を作成します
sudo env LD_LIBRARY_PATH=/opt/openssl/lib64 ./easyrsa build-ca
# パスワードを求められるので設定します
# [2] サーバーの証明書と鍵を作ります
sudo env LD_LIBRARY_PATH=/opt/openssl/lib64 ./easyrsa build-server-full {server_name}
# サーバー用のパスワードと、先ほど設定した認証局のパスワードを入力します
# [3] クライアントの証明書と鍵を作ります
sudo env LD_LIBRARY_PATH=/opt/openssl/lib64 ./easyrsa build-client-full {client_name}
# サーバーと同様の作業をします
備考
デフォルトではないOpenSSL
を使う場合、何もしないとライブラリが衝突してエラーが出ます。
easyrsa
インストール後に設定した環境変数はsudo
には引き継がれないので、エラー対策としてenv LD_LIBRARY_PATH=/opt/openssl/lib64
で環境変数を設定しながらeasyrsa
を実行します。
ちなみに、init-pki
のときはvars
ファイルの内容が反映されずデフォルトのopenssl
コマンドの方が使われるようですので、環境変数の設定は不要です。
設定
それではOpenVPN
を設定していきます。
# 設定ファイルを補完するディレクトリを作成します
sudo mkdir -p /etc/openvpn/server
# 移動します
cd /etc/openvpn/server
# "ta.key"を生成します
sudo env LD_LIBRARY_PATH=/opt/openssl/lib64 openvpn --genkey secret ta.key
# "DH鍵"を生成します
sudo env LD_LIBRARY_PATH=/opt/openssl/lib64 /opt/openssl/bin/openssl dhparam -out dh2048.pem 2048
# サンプルファイルをコピーします
sudo cp /opt/openvpn-2.6.3/sample/sample-config-files/server.conf ./server.conf.example
# サーバーファイルを編集します
sudo nano server.conf
コピーしたサンプルを参考に、設定ファイルを編集します。
私の使用している設定を書き出します。
port 1194
proto udp6
dev tun
ca /opt/easy-rsa/easyrsa3/pki/ca.crt
cert /opt/easy-rsa/easyrsa3/pki/issued/server.crt
key /opt/easy-rsa/easyrsa3/pki/private/server.key
dh dh2048.pem
topology subnet
server 10.8.0.0 255.255.255.0
server-ipv6 fdxx:xxxx:xxxx::/64 # 下記参照
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp ipv6 block-local"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
push "dhcp-option DNS 2001:4860:4860::8888"
push "dhcp-option DNS 2001:4860:4860::8844"
keepalive 10 120
tls-auth ta.key 0
cipher AES-256-GCM
user nobody
group nobody
persist-key
persist-tun
status openvpn-status.log
log-append /var/log/openvpn.log
verb 3
explicit-exit-notify 1
auth SHA512
askpass pass.txt # パスワードを記述したファイル
OpenVPN
は起動時にサーバー用証明書のパスワードを聞かれます。
そのままだとsystemd
で自動起動する際に不便ですので回避する設定をします。
# "build-server-full"の時に入力したパスワードを記載したファイルを作成します
sudo nano /etc/openvpn/server/pass.txt
# 一応root以外が読めないようにしておきます
sudo chmod 600 /etc/openvpn/server/pass.txt
server-ipv6
このディレクティブに指定するユニークローカルアドレスは下記サイトで生成します。
https://www.jdoodle.com/a/20tR
MACアドレス
を入力するとULA Prefix
というのが生成されるので、生成されたプレフィックスから好きなサブネットを選びます。
基本的には無難にFirst Subnet
に出てくる一番最初のサブネットでよいと思います。
備考
fd00::/8
のアドレスブロックに割り当てられるアドレスはipv4
ではプライベートアドレスに相当します。
基本的にはユーザーが自由に設定できるものになりますが、プレフィックスが重複しないようにMACアドレス
と乱数から生成する方法がRFC
で定められています。
先のウェブページはその方法に則ってプレフィックスを生成してくれます。
生成されたプレフィックスから選んだサブネットが、VPNからクライアントに割り当てられるアドレスのサブネットになります。
転送
クライアントに鍵等を転送します。
私はWinSCPでコピーしてしまいますが、皆さんお好きなようにクライアント用のカギと証明書をコピーしてください。
クライアントで必要なものは以下の通りです。
ファイル名 | 場所 |
---|---|
ca.crt | {path_to_easyrsa3}/pki/ca.crt |
ta.key | 出力した場所(/etc/openvpn/server/ta.key) |
{client_name}.crt | {path_to_easyrsa3}/pki/issued/{client_name}.crt |
{client_name}.key | {path_to_easyrsa3}/pki/private/{client_name}.key |
systemd
systemd
の設定をします。
まずはユニットファイルをコピーします。
# ダウンロードしたユニットファイルをコピーします
sudo cp /opt/openvpn-2.6.3/distro/systemd/openvpn-server@.service /etc/systemd/system/
# OpenSSLライブラリの変更を反映するよう書き換えます
sudo nano /etc/systemd/system/openvpn-server@.service
ユニットファイルのExecStart
部分を書き換えます。
実行コマンドの先頭に/bin/env LD_LIBRARY_PATH=/opt/openssl/lib64
を追記します。
# |=> 追記部分 <=|
ExecStart=/bin/env LD_LIBRARY_PATH=/opt/openssl/lib64 /usr/local/sbin/openvpn (以後同)
書き換えが完了したら作業を続行します。
# 反映させます
sudo systemctl daemon-reload
# 起動します
sudo systemctl start openvpn-server@server
もしエラーが出たらcat /var/log/openvpn.log
でそれらしいメッセージを探して解決します。
DCOの有効化
ついでですので、最近サポートされた高速化機能のDCO
を有効にするためカーネルモジュールovpn-dco
を導入します。
カーネルの方でパケットの処理をするので通信速度が向上するそうです。
sudo yum install kernel-devel
git clone https://github.com/OpenVPN/ovpn-dco.git
cd ovpn-dco
make
#make tests # 以下参照: 現状では失敗します
sudo make install
sudo systemctl restart openvpn-server@server
# 無事に反映されているか確認します
sudo cat /var/log/openvpn.log | grep "DCO version"
# "DCO version: 0.2.20230426"とバージョンが表示されれば成功です
テスト
テストの実行に少なくとも以下のものが必要です。
が、これを入れても失敗します…。
試行錯誤しましたが解決できませんでした。
GitHubで開発者の方からテストコードはメンテしていないと回答がありました。
現在は動かないだろうとのことなのでこれで問題ないのでしょう。
今後も修正される予定はないそうですし、ちゃんと起動できて反映もされているのでよしとします。
#sudo yum install python3-jinja2 python-jsonschema
#git clone https://github.com/Mbed-TLS/mbedtls.git
#cd mbedtls
#make
#make check
#sudo make install
ファイアウォール
前提としてfirewalld
で管理しているものとします。
さくらのパケットフィルターは有効無効どっちでも構いません。
余談ですが僕はあれにほとんどセキュリティ上の機能を期待していません。
TCP/UDP 32768-65535番ポート、NTP UDP 123番ポート、IPv6通信、ICMP、フラグメントパケットは全て許可されます
ってやばくないですか??
あーしは専門家じゃないのでなんも言えませんが、この辺の機能はAWS
しか勝たんです。(多分)
もしさくらのパケットフィルタを有効にしている場合は1194
を許可にしておいてください。
それではfirewalld
の作業をしていきます。
sudo firewall-cmd --add-service=openvpn
# 正しく反映されているか確認
sudo firewall-cmd --list-all
# "services"に"openvpn"があればOK
sudo firewall-cmd --runtime-to-permanent
接続
ここまでの作業で接続自体は可能ですのでクライアントから接続してみます。
OpenVPN GUI
をインストールし、起動します。
コンフィグディレクトリ(デフォルト: C:\Users\{User_Name}\OpenVPN\config
)に以下の設定ファイルと転送した鍵・証明書を配置していきます。
設定ファイルは以下の通りです。
remote example.com
はご自身のドメインに変更してください。
client
dev tun
windows-driver wintun
proto udp
remote example.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
remote-cert-tls server
tls-auth ta.key 1
cipher AES-256-GCM
verb 3
topology subnet
auth SHA512
data-ciphers AES-256-GCM
配置が完了したらタスクトレイにあるOpenVPN GUI
のアイコンを右クリックしてclient
メニュー(または.ovpn
のファイル名)から接続をクリックします。
パスワードを聞かれるのでeasy-rsa
での証明書作成作業中build-client-full
の時に入力したパスワードを入力します。
割り当てられたIPアドレス
を通知するポップアップが出れば接続成功です。
接続成功してもインターネットには接続できませんが、問題ありませんので切断して作業を続けます。
接続失敗したらログなどを見ながらググって試行錯誤して下さい。
ファイアウォールやドメインなどが正しく設定されてサーバーに到達できていれば、サーバー側の(/var/log/openvpn.log
)にもログが残っているはずです。
転送設定
まずはカーネルのパケット転送を許可します。
カーネルパラメータの設定ファイルである/etc/sysctl.conf
を開いて以下を追記します。
# Forward packet for VPN
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
追記したら以下のコマンドで反映させます。
sudo sysctl -p
ファイアーウォールにもフォワードとマスカレードの設定を行います。
以下のコマンドを実行します。
さくらのRockey Linux
はデフォルトではネットワークインターフェースの名前がens3
になりますが、環境が異なる場合ip a
で調べて適切な名前に置換してください。
sudo firewall-cmd --add-masquerade
sudo firewall-cmd --direct --add-rule ipv6 filter INPUT 1 -p icmpv6 -j ACCEPT
sudo firewall-cmd --direct --add-rule ipv6 filter FORWARD 1 -i ens3 -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo firewall-cmd --direct --add-rule ipv6 filter FORWARD 1 -i tun0 -o ens3 -j ACCEPT
sudo firewall-cmd --direct --add-rule ipv6 nat POSTROUTING 0 -o ens3 -j MASQUERADE
sudo firewall-cmd --runtime-to-permanent
少しだけ解説します
-
IPv6
での通信に必須なIPMPv6
をすべて受け入れるようにして -
ens3 -> tun0(内向き通信)
では返答パケット(フラグがrelated
またはestablished
)を許可 -
tun0 -> ens3(外向き通信)
ではすべて許可 -
ens3
からの外向きはマスカレードする
というようなことをしています。
マスカレードは簡単に言うと差出人書き換えです。
tun0
配下のAというクライアントデバイスから送られたパケットをそのままVPNを通して外に送ると、帰りのパケットを返信の際にAに直接届けようとして届きません。
マスカレードすることでVPNのアドレスが送信元になりますのでVPNにちゃんと帰ってくるようになるわけです。
接続
ここまでの作業でVPNを経由してインターネットに接続できるようになっているはずです。
先の接続と同様にOpenVPN GUI
で接続してみましょう。
ブラウザなどで確認するかping
で確認してもよいでしょう。
ちなみにIPv6
で接続できているかは、IPv6テストにて確認します。
アクセスした結果のIPv6アドレス
がVPNサーバーのものになっていれば接続できています。
もし接続できない場合はVPNサーバー
やdns.google
にIPv4
やIPv6
など色々変えながらping
するとよいでしょう。
どこまで接続できていてどこで止まっているのかがわかるとトラブルシュートしやすいです。
中々解決しない場合はWireShark
での分析もおすすめです。
ping
が行ったっきり戻ってこないときはマスカレードやフォワードなどの設定が疑わしいです。
頑張ってください。
まとめ
以上、無事に接続できましたでしょうか?
僕はさんざん試行錯誤して接続しました。
特にマスカレードなど、接続した後が大変でした。
IPv6
での接続も日本語で情報が少ない気がするので参考になれば幸いです。
それでは皆様、よきセキュアな日々をお過ごし下さい!