OpenVPN を用いた VPN 構築メモ

スポンサーリンク

OpenVPN で VPN 環境を構築する目的

  1. Android スマートフォンからのインターネットアクセスをどこに居ても自宅 LAN 経由としてセキュリティーを確保する。
  2. セキュアに LAN 内端末のデータへアクセス可能とする。

仕様

 ドコモの Xi と言ったキャリア回線や公衆無線 LAN からのアクセスしてきたクライアントに対し 10.8.0.0/16 の範囲で IP を割り当て、192.168.1.0/24 への接続を許可する。
 10.8.0.0/16 から 192.168.1.0/24 へのアクセスはルーティング (tun モード) で実現させる。
 サーバーの OS は CentOS 7 だが firewalld ではなく、スクリプトで管理している関係上 iptables を用いた環境とする。

使用ソフト

 OpenVPN 2.3.x / 2.4.0 (自ビルドする場合)
 EasyRSA3

下準備

 root 作業。ソース展開用のディレクトリを作成し、カレントを移して EasyRSA3 をダウンロード。

mkdir ~/src
cd ~/src
wget https://github.com/OpenVPN/easy-rsa/archive/master.zip -O easyrsa3.zip

OpenVPN のインストール

yum でインストールする場合

 yum で epel のリポジトリからインストール。

yum install epel-release.noarch
yum --enablerepo=epel install openvpn.x86_64

自前で RPM パッケージを作成する場合

 root で rpmbuild を用いたパッケージ作成は危険なので、慣例的に rpmbuilder ユーザを作成してパッケージをビルド、作成する。
 ソースは ダウンロード元 から 2.4 以降の最新版を用いる。2.3 系ならわざわざここで作る意味があまり無いので yum で一発の方が良い。

yum install openssl-devel lzo-devel pam-devel
useradd rpmbuilder
su - rpmbuilder
wget https://swupdate.openvpn.org/community/releases/openvpn-2.4.0.tar.gz
rpmbuild -tb --clean openvpn-2.4.0.tar.gz
exit
yum localinstall /home/rpmbuilder/rpmbuild/RPMS/x86_64/openvpn-2.4.0-1.x86_64.rpm

 インストール後のパッケージやソースは不要であれば任意で削除する。

EasyRSA3 のインストール

 ダウンロードしたアーカイブを展開してコピーする。

cd ~/src
unzip easyrsa3.zip
cp -r ./easy-rsa-master/easyrsa3/ /etc/openvpn/

 不要になったソースとアーカイブは任意で削除する。

EasyRSA3 を用いた証明書の作成

認証局作成 (CA)

カレントを移して CA を作る

cd /etc/openvpn/easyrsa3
./easyrsa init-pki

次のコマンドでは PEM pass phrase と Common Name を任意に設定する事。

./easyrsa build-ca

CA の証明書をコピー。

cp ./pki/ca.crt /etc/openvpn/

サーバー証明書の作成

パスワード無しのサーバー用証明書を作成。

./easyrsa build-server-full server nopass

サーバー証明書の設置

cp ./pki/issued/server.crt /etc/openvpn/
cp ./pki/private/server.key /etc/openvpn/

DH パラメータの作成と設置

マシンスペックによって時間が掛かる。

./easyrsa gen-dh
cp ./pki/dh.pem /etc/openvpn/

クライアント証明書廃止リスト作成

一度ダミーの証明書を作成して revoke したあとに crl.pem を作成する。

./easyrsa build-client-full dmy nopass
./easyrsa revoke dmy
./easyrsa gen-crl
cp ./pki/crl.pem /etc/openvpn/
chmod o+r /etc/openvpn/crl.pem

設定を終えたらカレントをホームにでも移しておく

cd

OpenVPN の設定

TLS 認証キー作成と設定ファイルの設置

TLS 認証キー作成

openvpn --genkey --secret /etc/openvpn/ta.key

OpenVPN サーバー設定ファイルのコピー

cp /usr/share/doc/openvpn-*/sample/sample-config-files/server.conf /etc/openvpn/

設定ファイルの編集

server.conf が OpenVPN サーバーとしての設定ファイルになるので編集する。

vi /etc/openvpn/server.conf

内容は次に編集した箇所のみ抜粋する。プライベートアドレスは適時合わせて編集する。

# DH パラメータのファイル名を作成する物に合わせる
dh dh.pem
# OpenVPN が動作しているホストをクライアントのゲートウェイにする
push "redirect-gateway def1 bypass-dhcp"
# クライアントが使う DNS サーバーを指定する
push "dhcp-option DNS 192.168.1.xx"
# 圧縮を有効化する
comp-lzo
# OpenVPN のログファイルを指定する
log-append  /var/log/openvpn.log
# OpenVPN が再起動した事を通知して自動的に再接続するようにする。
# OpenVPN 2.3 ではコメントアウトして無効化しないと起動不可。
explicit-exit-notify 1

# 以下追記していく
# 接続クライアントのマネージメントを使えるようにする。
management localhost 7505

# クライアント証明書の廃止リストを指定する
crl-verify crl.pem

# Samba に接続時の速度低下を防止する為の調整
fragment 1280
mssfix 1280
link-mtu 1400

以下サンプルの設定ファイルと編集後の設定ファイルの差分。

# diff -u /usr/share/doc/openvpn-*/sample/sample-config-files/server.conf /etc/openv
pn/server.conf
--- /usr/share/doc/openvpn-2.4.0/sample/sample-config-files/server.conf 2017-03-18 00:22:10.385182731 +0900
+++ /etc/openvpn/server.conf    2017-03-18 00:26:55.926314349 +0900
@@ -82,7 +82,7 @@
# Diffie hellman parameters.
# Generate your own with:
#   openssl dhparam -out dh2048.pem 2048
-dh dh2048.pem
+dh dh.pem
 
# Network topology
# Should be subnet (addressing via IP)
@@ -189,7 +189,7 @@
# (The OpenVPN server machine may need to NAT
# or bridge the TUN/TAP interface to the internet
# in order for this to work properly).
-;push "redirect-gateway def1 bypass-dhcp"
+push "redirect-gateway def1 bypass-dhcp"
 
# Certain Windows-specific network settings
# can be pushed to clients, such as DNS
@@ -197,7 +197,7 @@
# http://openvpn.net/faq.html#dhcpcaveats
# The addresses below refer to the public
# DNS servers provided by opendns.com.
-;push "dhcp-option DNS 208.67.222.222"
+push "dhcp-option DNS 192.168.1.8"
 ;push "dhcp-option DNS 208.67.220.220"
 
# Uncomment this directive to allow different
@@ -260,7 +260,7 @@
# For compression compatible with older clients use comp-lzo
# If you enable it here, you must also
# enable it in the client config file.
-;comp-lzo
+comp-lzo
 
# The maximum number of concurrently connected
# clients we want to allow.
@@ -294,7 +294,7 @@
# while "log-append" will append to it.  Use one
# or the other (but not both).
 ;log         openvpn.log
-;log-append  openvpn.log
+log-append  /var/log/openvpn.log
 
# Set the appropriate level of log
# file verbosity.
@@ -312,4 +312,13 @@
 
# Notify the client that when the server restarts so it
# can automatically reconnect.
-explicit-exit-notify 1
+;explicit-exit-notify 1
+
+# Additional Settings
+management localhost 7505
+
+crl-verify crl.pem
+
+fragment 1280
+mssfix 1280
+link-mtu 1400

Firewall 関連の設定

net.ipv4.ip_forward の値を 1 に変更して IP フォワードを有効化して反映させる。

vi /etc/sysctl.conf
net.ipv4.ip_forward=1
sysctl -p

場合に応じて次の通りになるような設定を行う。NIC のデバイス名は適時変更すること。

コマンドラインから追加する場合。

iptables -I INPUT -p udp --dport 1194 -j ACCEPT
iptables -I FORWARD -i tun+ -j ACCEPT
iptables -I FORWARD -o tun+ -j ACCEPT
iptables -I INPUT -i tun+ -j ACCEPT
iptables -I OUTPUT -o tun+ -j ACCEPT
iptables -t nat -I POSTROUTING -s 10.8.0.0/16 -o ens33 -j MASQUERADE

以下 /etc/sysconfig/iptables に書いておく場合。

vi /etc/sysconfig/iptables
*filter
-A INPUT -p udp --dport 1194 -j ACCEPT
-A INPUT -i tun+ -j ACCEPT
-A OUTPUT -o tun+ -j ACCEPT
-A FORWARD -o tun+ -j ACCEPT
-A FORWARD -i tun+ -j ACCEPT
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A POSTROUTING -s 10.8.0.0/16 -o ens33 -j MASQUERADE
COMMIT

ブロードバンドルーター側の設定

 我が家は Aterm WG1800HP2 を使用しているので、ポートマッピング設定より 1194/UDP を OpenVPN が動作しているホストにマッピングするだけの設定だった。
 L2TP/IPsec とは違い、幾つもポートを開けずに済むし IPsec パススルー設定も不要。ESP プロトコルのマッピングも不要だから最小限の設定で済む感じだ。

OpenVPN の起動

yum でインストールした場合。

 次の通り systemd を用いて起動する。

systemctl start openvpn@server.service

自ビルドパッケージをインストールした場合。

 ソースからインストールした場合、systemd のユニットファイルが無いので作り、PID ファイルを置くディレクトリを掘っておく。

vi /usr/lib/systemd/system/openvpn@.service
[Unit]
Description=OpenVPN Robust And Highly Flexible Tunneling Application On %I
After=network.target

[Service]
PrivateTmp=true
Type=forking
PIDFile=/var/run/openvpn/%i.pid
ExecStart=/usr/sbin/openvpn --daemon --writepid /var/run/%i.pid --cd /etc/openvpn/ --config %i.conf

[Install]
WantedBy=multi-user.target

 作成したユニットを認識させて起動する。

systemctl daemon-reload
systemctl start openvpn@server

クライアントで接続する為に必要な証明書の作成

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

 サーバー側で root ユーザーにて作業を行う。
 証明書はクライアント毎に作るので分かりやすい様にしておくと良い。今回は Android 端末で使用するので android と名付けた。パスワード入力も面倒臭そうなので nopass を付加してパスワード無しとした。

cd /etc/openvpn/easyrsa3/
./easyrsa build-client-full android nopass

接続に必要なプロファイルの作成

 Android のアプリは OpenVPN for Android を用いる。
 接続する為には予め拡張子「.ovpn」となるプロファイルを作っておく必要がある
 プロファイル作成にあたっては予め作成しておいた次の証明書関連ファイルが必要。

/etc/openvpn/ca.crt
/etc/openvpn/ta.key
/etc/openvpn/easyrsa3/pki/issued/android.crt
/etc/openvpn/easyrsa3/pki/private/android.key

 以下プロファイルのひな形のような物。仮に sample.ovpn としておく。
 このひな形に対してやるべき事は次の 7 こ。

  • VPN_SERVER_ADDRESS を自分の持つグローバル IP アドレス、若しくは正しく IP アドレスを引けるドメイン名に書き換えておく。
  • <ca></ca> の間には ca.crt の内容をまるごとコピペ。
  • <key></key> の間には android.key (クライアント秘密鍵) の内容をまるごとコピペ。
  • <cert></cert> の間には android.crt (クライアント証明書) の内容をまるごとコピペ。
  • 完成した sample.ovpn ファイルをなるべくセキュアな経路を用いて Android 端末にコピーする。
  • OpenVPN for Android からプロファイルをインポートし、設定内容を確認した後に接続を行う。
client
dev tun
remote VPN_SERVER_ADDRESS 1194 udp
key-direction 1
route 0.0.0.0 0.0.0.0 vpn_gateway
remote-cert-tls server
persist-tun
management-query-proxy
ncp-ciphers AES-256-GCM
link-mtu 1400 
fragment 1280
mssfix
resolv-retry infinite 
comp-lzo

<ca>
ここに ca.crt の内容をコピペ
</ca>
<key>
ここに android.key (クライアントの秘密鍵) の内容をコピペ
</key>
<cert>
ここに android.crt (クライアント証明書) に内容をコピペ
</cert>
<tls-auth>
ここに ta.key の内容をコピペ
</tls-auth>

その他場合に応じて必要な作業

DNS サーバーが LAN 内に存在する場合

 LAN 内に DNS サーバーを立てている時、10.8.0.0/16 からのクエリーや再帰クエリーを許可しなくては名前が引けない。
 192.168.1.0/24 内で動作している場合、localnets から外れてしまうのでクエリーは破棄されてしまう。

以下参考。

allow-query     { localhost; localnets; 10.8.0.0/16; };

view internal {
        match-clients { localnets; 10.8.0.0/16; };
        allow-recursion { 127.0.0.1; 192.168.1.0/24; 10.8.0.0/16; };

Samba の設定変更

 許可したホストのみアクセス出来る様な設定にしている為、新たに 10.8.0.0/16 のセグメントを許可して上げる。

 参考。

hosts allow = 127.0.0.1, 192.168.1.0/24, 10.8.0.0/16

 これでもアクセス出来ない場合、iptables など Firewall の設定を見なおす。(137/UDP, 138/UDP, 139/TCP, 445/TCP のマッピング等)

Web サーバーなど

 192.168.1.0/24 等と指定してアクセス制限を掛けているパスに対して 10.8.0.0/16 も追加して上げると VPN を活かせる。

参考 (Nginx)

location /wp-admin {
    allow 192.168.1.0/24;
    allow 10.8.0.0/16;
    deny all;
}

おわりに

 VPN には以前より興味こそあったものの「うわー面倒臭いわー」で敬遠してきたが、公衆無線 LAN に繋いでデータを垂れ流すことに抵抗を憶えてきたので重い腰を上げて実装に乗り出した。
 いざやってみると中々楽しい部分が多かったが、ルーティング周りでトラブったりと正常動作するまでに相当の時間を要してしまった。
 実はこの OpenVPN を試す前に L2TP/IPsec も試したりしたが、一部 Android アプリで正常な通信が出来なかったりで常用は取りやめた経緯がある。機能的にはどっちもどっちだけど、今回の OpenVPN の方が多少楽に使えるようになったから採用するに至った。
 今回の VPN 実装で自宅内の無線 LAN 以外のキャリア回線や公衆無線 LAN から自宅内の LAN へ TLS を用いた暗号化経路でセキュアな通信を確保しつつも Samba や Windows の共有フォルダへのアクセスまで出来るようになったのでやって良かったと久々に思える作業だった。

参考にさせて頂いたサイト

VPNサーバー構築(OpenVPN) - CentOSで自宅サーバー構築
VPNサーバー構築(OpenVPN)
How To | OpenVPN.JP

Revision

2017/03/18 14:15
 OpenVPN の設定 server.conf にて push “route 192.168.1.0 255.255.255.0” の記述を削除。デフォルトのままのコメントアウトに修正。
 これは OpenVPN サーバーとは別セグメントへの経路を確保する場合にのみ用いる物だとの事で。参考 URL
 接続用プロファイルとした sample.ovpn の内容で重複した項目があったのとパラメータ変更をした。

2017/04/01 22:20
 コマンドラインの表記を prism.js でハイライトするように全般的な修正を行った。

2017/05/18 3:10
 記事中の誤字修正

2017/09/15 21:38
 クライアントプロファイル内には crl.pem を記述しない方が良いので、該当部分を削除した。

2017/12/31 13:11
 「自ビルドパッケージをインストールした場合。」内の Unit ファイルを記述したうち、引数 --writepid /var/run/openvpn/%i.pid--writepid /var/run/%i.pid に修正した。
 これは /var/run/openvpn とディレクトリを掘っても気がつくと消されている為で、OpenVPN の起動に失敗する原因になっていた為。

スポンサーリンク