OpenVPN と tap インターフェイスを使って、自宅に接続できるレイヤー2 (ブリッジモード) VPNを作成する。Layer2モードだと、自宅外から VPN 接続したときに bonjour や Windows ネットワーク検索のようなサービスが、自宅内と同様に使えるのがメリット。
自宅内サーバ: Raspberry Pi 2 (Raspbian 9.x stretch)
環境は以下の図の通り。
この文書の手順以外に別途、インターネット接続ルータでサービスポートを外部公開 (スタティック NAT) しておく必要がある。
クライアント側の要件として、Apple iOS 系機器は tap デバイスに対応していないため、Layer2 VPN を利用できないので本稿のターゲットから外れる。Android 系も標準 API と標準クライアントでは tap に対応していない(端末の root 権限があれば対応可能。また有料ソフトウェアの OpenVPN Client は tap に対応している)。Windows 用の OpenVPN GUI、Mac の Tunnelblick などは tap デバイスに対応している。
1. OpenVPN パッケージインストール
OpenVPN 本体と、ブリッジ設定に必要な bridge-utils をインストールする。
$ sudo apt install openvpn bridge-utils
2. Raspbian のネットワークインターフェイスを bridge 設定にする
サーバ側の eth0 デバイスを直接使わず、ブリッジデバイス br0 を使い eth0 をそのメンバーとするように設定する。OpenVPNサーバプログラムの使う tap0 デバイスも br0 のメンバーとして、ブリッジ接続できるようにする。
サーバの IP アドレスとしては、固定アドレスを設定する(自宅内のIPアドレスをルータのDHCPに任せているなら、DHCP配布範囲外のアドレスで固定する)。
マシン起動時に自動的にブリッジデバイスが有効になるよう、interfaces ファイルを編集する。
$ sudo vi /etc/network/interfaces
auto br0 iface br0 inet static address 192.168.100.20 netmask 255.255.255.0 network 192.168.100.0 broadcast 192.168.100.255 gateway 192.168.100.1 dns-nameservers 192.168.100.1 dns-search example.com bridge_ports eth0
もともと eth0 だったところを br0 にして、bridge_ports eth0 を追加するように編集する。
ここで一度再起動して、br0 に IP アドレスが付くことを確認する。
$ sudo shutdown -r now
起動したら IP アドレスの状況を確認する。br0 に IP アドレスが付いていれば OK。
$ ip a 1: lo: <loopback,up,lower_up> mtu 65536 qdisc noqueue state UNKNOWN group defaul t qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: eth0: <broadcast,multicast,up,lower_up> mtu 1500 qdisc pfifo_fast master br0 state UP group default qlen 1000 link/ether 00:00:5e:00:53:11 brd ff:ff:ff:ff:ff:ff 3: br0: <broadcast,multicast,up,lower_up> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:00:5e:00:53:fe brd ff:ff:ff:ff:ff:ff inet 192.168.100.20/24 brd 192.168.100.255 scope global br0 valid_lft forever preferred_lft forever</broadcast,multicast,up,lower_up></broadcast,multicast,up,lower_up></loopback,up,lower_up>
3. OpenVPN サーバ設定
OpenVPN サーバの設定ファイルを作成する。サンプル設定ファイルをコピーして、それをベースに編集する。
$ sudo mkdir -p /var/log/openvpn /etc/openvpn/ccd
$ sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/server/
$ sudo gzip -d /etc/openvpn/server/server.conf.gz
$ sudo mv /etc/openvpn/server/{server,udp7231}.conf
$ sudo vi /etc/openvpn/server/udp7231.conf
port 7231 proto udp dev tap ca ca.crt cert server.crt key server.key dh dh2048.pem server-bridge 192.168.100.0 255.255.255.0 192.168.100.192 192.168.100.223 push "dhcp-option DNS 192.168.100.1" push "dhcp-option DOMAIN example.com" client-to-client keepalive 10 120 tls-auth ta.key 0 cipher AES-256-CBC user nobody group nogroup persist-key persist-tun status /var/log/openvpn/openvpn-status.log log-append /var/log/openvpn/openvpn.log verb 3 explicit-exit-notify 1 crl-verify crl.pem
dev tap 設定にするところがブリッジ方式の要になる。server-bridge 設定には、VPN クライアントに配布する IP アドレスの範囲を指定する。自宅内ルータの DHCP では、この範囲を配布対象外にしておくこと。
トランスポート層プロトコルは UDP を利用する(TCP over TCP 問題を避けるため)。利用するポートは念のため標準の 1194 から変えておくこととして、適当にランダムで決める。今回は 7231 とした。
4. サーバ証明書の準備
easy-rsa パッケージを利用して CA を作成し、サーバ証明書・鍵を作成する。CA 作業用ディレクトリとして、/etc/openvpn/easy-rsa を作成する。
$ sudo make-cadir /etc/openvpn/easy-rsa
$ sudo -i
# cd /etc/openvpn/easy-rsa
# ln -s openssl-1.0.0.cnf openssl.cnf
# vi vars
以下のような設定をvarファイルに記述する。
export KEY_SIZE=2048 export KEY_COUNTRY="JP" export KEY_PROVINCE="Aichi" export KEY_CITY="Nagoya" export KEY_ORG="Home" export KEY_EMAIL="root@raspberrypi.example.com" export KEY_OU="Server"
CA を作成し、サーバ鍵・証明書を作成する。
# . vars
# ./clean-all
# ./build-ca
# ./build-key-server server
TLS Static Key と DH Keyを作成する。DH Keyの生成にはかなりの時間がかかる(Raspberry Piでは10分以上)
# openvpn --genkey --secret /etc/openvpn/server/ta.key
# ./build-dh
# cp -p keys/ca.crt keys/server.crt keys/server.key keys/dh2048.pem /etc/openvpn/server/
# exit
5. OpenVPN サービスの有効化と起動
サーバ側 OpenVPN サービス用の systemd ユニットファイルは /lib/systemd/system/openvpn-server@.service である。@の後に、サーバ設定ファイルのドットより前の名前(今回の場合は “udp7231″)を指定して有効化・起動する。
サービスを有効化し、起動する。
$ sudo systemctl enable openvpn-server@udp7231
Created symlink /etc/systemd/system/multi-user.target.wants/openvpn-server@udp7231.service → /lib/systemd/system/openvpn-server@.service.
$ sudo systemctl start openvpn-server@udp7231
これだけだと、ブリッジデバイス br0 に tap0 デバイスが組み込まれず、VPN クライアントと LAN との相互通信ができない。/etc/systemd 以下に追加の systemd ユニットファイルを作成して、その中で tap0 を br0 に追加する処理を行う。
$ sudo vi /etc/systemd/system/openvpn-bridge.service
[Unit] Description=OpenVPN bridge service Requires=openvpn-server@udp7231.service After=openvpn-server@udp7231.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/bin/sh -c '/sbin/brctl addbr br0 || /bin/true' ExecStartPost=/bin/sh -c '/sbin/brctl addif br0 tap0 || /bin/true' ExecStartPost=/sbin/ip link set tap0 up ExecReload=/bin/true ExecStop=/sbin/brctl delif br0 tap0 [Install] WantedBy=multi-user.target
brctl addbr br0 の行は本来必要ないはず(br0 の立ち上げは /etc/network/interfaces に書いてあれば自動的に実行される)なのだが、タイミングの問題で openvpn サービス起動時にまだ br0 が無い場合があり、次の行の brctl addif br0 tap0 に失敗することがあるため、念のため加えている。
上記で作成した自作サービスを起動する。
$ sudo systemctl enable openvpn-bridge
Created symlink /etc/systemd/system/multi-user.target.wants/openvpn-bridge.service → /etc/systemd/system/openvpn-bridge.service.
$ sudo systemctl start openvpn-bridge
6. iptables 設定
ローカルファイアウォール設定で、OpenVPN の利用するポートを開けておく。
iptables の設定に iptables-persistent パッケージを利用している場合は、/etc/iptables/rules.v4 を編集して以下の行を加える。
-A INPUT -p udp -m udp --dport 7231 -j ACCEPT
設定を再読み込みする。
$ sudo netfilter-persistent reload
もしiptables直接ではなくufwを使っているのであれば、以下のコマンドでサービスポートを開ける。
$ sudo ufw allow 7231/udp
$ sudo ufw reload
ブリッジ設定の場合、パケットフォワーディングの設定(sysctl -w net.ipv4.ip_forward=1)は不要。
7. クライアント側設定テンプレートの作成
設定を複数のクライアントに配布するため、元となるテンプレートファイルを作成する。
$ sudo cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/client/client.template
$ sudo vi /etc/openvpn/client/client.template
client dev tap proto udp remote 203.0.113.10 7231 resolv-retry infinite nobind persist-key persist-tun remote-cert-tls server key-direction 1 cipher AES-256-CBC verb 3 <tls-auth> ここに /etc/openvpn/server/ta.key ファイルの内容をペーストする。 </tls-auth> <ca> ここに /etc/openvpn/server/ca.crt ファイルの内容をペーストする。 </ca> <key> </key> <cert> </cert>
証明書・鍵ファイル等を別ファイルの形で配布しても良いが、設定ファイルの中に取り込む形にしてみる。設定を単一ファイルで配布できれば取り回しが良いため。
8. クライアント証明書の発行と設定ファイルの作成
テストクライアント用の設定を作成して、動作検証してみる。
まず、1番目のクライアント鍵・証明書 (client1と命名) を発行する。
$ sudo -i
# cd /etc/openvpn/easy-rsa
# . vars
# ./build-key client1
# exit
クライアント1のための設定ファイル (client1.ovpn) をテンプレートから作成する。
$ sudo cp /etc/openvpn/client/{client.template,client1.ovpn}
$ sudo vi /etc/openvpn/client/client1.ovpn
client1.ovpn ファイルの中の <cert>, <key> 各セクションの中に、作成したクライアント証明書 (client1.crt) と鍵 (client1.key) ファイルの内容をコピー&ペーストする。
作成した /etc/openvpn/client/client1.ovpn ファイルを配布して、クライアントデバイスにインストールして接続確認する。
接続成功するようなら、client2、client3、…と設定ファイルを同様に作成していく。
9. クライアント証明書の失効手続き
クライアントを使わなくなったら、証明書を失効させておく。client1を失効させるためには、以下のコマンドを実行する。
$ sudo -i
# cd /etc/openvpn/easy-rsa
# . vars
# ./revoke-all client1