はじめに
実家のVPN環境を刷新したくてモダンなVPNソリューションを模索していました。
その中で、WireGuardこそが本命だと感じ構築検証してみたので、同じようにVPNのソリューションを探している方の参考になればと思いこの記事を掲載します。
VPNソリューション色々
一口にVPNと言っても、数多くのソリューション(ソフトウェア)があります。
一例を上げると
- OpenVPN
- SoftEther
- L2TP/IPSec
- IKEv2/IPSec
等。
ここでは、下記を選択の優先度として上げておきます。
- パフォーマンス(通信速度)や安定性
- 設定や運用の簡単さ(サーバサイド)
- クライアントからの接続の容易さ(クライアントサイド)
- マルチプラットフォーム対応(Linux, MacOS, Windows, Android, iOS etc...)
各種VPNソフトウェアの通信速度については、色々なサイトで比較記事がありますが、その中でもよく言われているのが、OpenVPNは遅い、L2TP/IPSecは遅いという点です。
私は過去に両方使ってみたことがありますが、確かにどちらも遅くもう少し物理回線の速度に近づけないかなと思っていました。
IKEv2/IPSecは、通信速度も速く安定していると思いますが、構築するためにはStrongSwanを用いてかなり複雑な設定をしなければならないのと、クライアント側にVPNサーバの証明書をインポートする必要性があり、構築と運用両面から見て厳しいと考え断念しました。
SoftEtherについては、速度が速く取扱いも簡単な部類に入り非常に良いソリューションなので長く使い続けてきた経緯があります。
しかし、MacOSやAndroid端末から接続する際にL2TP/IPSecでの接続とせざるを得ず通信速度が落ちてしまう点と、サーバサイドの構築の煩雑さからもう少し良いソリューションはないものかと別のソリューションを探していました。
そこで見つけたのが WireGuard
です。
WireGuard
WireGuardは、現在まだ安定版が存在しない開発途上ではありますが、
- パフォーマンス(通信速度)が非常に速くて安定
- 設定や運用が簡単(サーバサイド)
- クライアントからの接続が簡単(クライアントサイド)
- マルチプラットフォーム対応(Linux, MacOS, Windows, Android, iOS etc...)
という状況で、まさに探していたVPNソリューションかなと思い検証しました。
結果的に非常に良く出来ていた為、実家のVPN環境として本番運用を開始しました。
WireGuardの実際の使い勝手について
まず、私が検証した限りで出来なかった(未実装 or 私の調査不足)事を先に記載します。
- mDNSやnmb lookup等のLAN内での名前解決は不可能(IPアドレスでアクセスしています)
- ブリッジ接続は不可能(代わりにルーティングでアクセスしています)
- DHCPでのIP割り当ては不可能(固定IPアドレスをクライアント毎に手動で振っています)
という感じで、このあたりもう少し機能追加されるといいなぁと思っていたりはするのですが、上記を差し引いても、高速かつ構築や運用が非常に楽です。
WireGuardのインストール
https://www.wireguard.com/install/
こちらに従えばOKです。
WireGuardの設定
本エントリーの本命はここ。かなり設定を試行錯誤してようやく自分のニーズに合うVPN構築が出来ました。
最初に設定を公開します。
Linux VPNサーバ側
VPN空間のプライベートネットワークサブセグメントを適当に決めます。私は 10.10.0.1/24
にしました。
自由に決めて構いませんが、実際の接続元LAN、接続先LANそれぞれのセグメントと同じにはしないほうが良いと思います。
おそらくトラブります、というかやっちゃだめです。
今回の環境だと、サーバが属する接続先LANは 192.168.11.0/24
で(一般的なBuffaloの家庭用ルータのデフォルトセグメント)クライアント側は 192.168.14.0/24
と、接続元と先で異なるセグメントに設定してあります。
このあたりは同じセグメントだとVPNサーバ側のLANへの通信が通らなくなる(接続元LANと区別がつかずルーティングが上手く行かない)と思います。
実際の設定例です。
[Interface]
Address = 10.10.0.1/24
# SaveConfig = true
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820
PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[Peer]
# client01
PublicKey = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
AllowedIPs = 10.10.0.2/32
PersistentKeepalive = 25
[Peer]
# client02
PublicKey = zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
AllowedIPs = 10.10.0.3/32
PersistentKeepalive = 25
[Peer]
# client03
PublicKey = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
AllowedIPs = 10.10.0.4/32
PersistentKeepalive = 25
[Interface]セクション
- Address
VPNサーバ側の仮想IPを指定します。適当にスタートのIPにしました。
- SaveConfig
この設定 true
にすると、通信中にWireGuardが認識した値を随時設定ファイルに反映してくれるようになります。ただし、自分でわかりやすく設定ファイルに #
から始まるコメント等を記載していても、それらは上書きにより消失してしまうため、私はコメントアウトして false
にしています(何も記載しなければデフォルトで false
)
- PostUp, PostDown
WireGuardを起動する直前に実行するシェルコマンド及びWireGuardを終了した後実行するシェルコマンドを指定するようです。
iptablesにあまり詳しくなく、なんとなくしか設定値の意味を理解していないのですが、ここが肝でこの設定を入れなければVPNクライアントからVPNサーバ内の別のホストへアクセスすることが出来ません。この設定により仮想LAN -> 物理LANへのルーティングを設定しています。
注意事項として、 -o eth0
の箇所を、実際の物理NICのデバイス名に置き換えてください。(例:enp4s0 等)
- ListenPort
特にポート番号は決まっていないみたいですが、 man wg-quick
を実行した際に表示されるマニュアルには 51820
が例として記載されていた為そのまま用いています。
ここで指定したポート番号をルータの設定にてUDPでNATしてやる必要があります。
- PrivateKey
wg genkey | tee privatekey | wg pubkey > publickey
このようなコマンドで秘密鍵と公開鍵を生成し、privatekeyの内容をサーバ側の設定に記載します。
[Peer]セクション
接続してくるクライアント毎に設定を追記していきます。 #
から始まる行はコメント行として使えるため、分かりやすいようメモしておくと良いかもです。
- PublicKey
クライアントの公開鍵を指定します。
wg genkey | tee privatekey | wg pubkey > publickey
上記のコマンドをもう一度別のディレクトリ等で実行しクライアント毎にKey Pairを生成するか、クライアント側にて生成するかで対応します。
- AllowedIPs
このクライアントが使うIPアドレスの許可リストです。ここで許可したIPアドレス以外のIPアドレスをクライアントが申告してきた場合、その通信はシンプルにDropされて通信できません。
- PersistentKeepalive
KeepAliveの設定です。デフォルトだとOFFですが、私は25秒で一応設定しておきました。
VPNクライアント側(Linux, MacOS, Windows 共通)
サーバ側の設定とかなり似ています。実は、便宜上サーバ側クライアント側と記載してきましたが、WireGuardにおいてはそれらの区別はなく、どちらも対等の扱いです。故にPeerと表記されています。
[Interface]
PrivateKey = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
Address = 10.10.0.2/24
DNS = 8.8.8.8
[Peer]
PublicKey = cccccccccccccccccccccccccccccccccccccccccccc
AllowedIPs = 10.10.0.0/24, 192.168.11.0/24
Endpoint = サーバのグローバルIPアドレス or ドメイン名:51820
[Interface]セクション
- PrivateKey
クライアントの秘密鍵を指定します。サーバ側で予め生成しておいたものを用いるか、MacOSやWindowsのWireGuard GUIアプリケーションでは起動して空の接続設定を作成した段階で生成されるのでそれを用いることも出来ます。
- Address
クライアントが使用する仮想IPアドレスを指定します。サーバ側の AllowedIPs
で許可されたIPアドレスしか使用できません。
[Peer]セクション
- PublicKey
サーバ側の公開鍵を指定します。各クライアント毎にここは同一のサーバに繋ぐのであれば常に同じ鍵を指定することになります。
- AllowedIPs
ここが肝です。ここで指定するIPレンジに合致した通信のみがVPNトンネル内を流れる形となります。逆に、ここで指定したIPアドレス以外への通信はVPNを通さず直接WANへ流れます。
私の場合、VPNサーバ側LAN内のみへVPNを通して通信し、通常のWANアクセスについてはVPNサーバを通さず直接アクセスとしたかったので、仮想LANのセグメントとVPNサーバ側のセグメントの2つのセグメントを ,
区切りで指定しています。
サーバ側のLAN内へ通信を通したい場合、サーバ側のセグメントを指定する必要があります。
AllowedIPs = 0.0.0.0/0
等と指定すると、全ての通信をVPN経由に出来ると思ったのですが、これをするとWANへのアクセスすら通らなくなりインターネットに接続できなくなりました。公衆Wi-Fi等で通信を安全にするために全ての通信をVPN経由としたい場合については、どのように設定すれば良いのか未だに分かっていません。もしご存じの方いらっしゃいましたらコメント欄にてご教示頂ければ嬉しいです。
AllowedIPs = 0.0.0.0
DNS = 8.8.8.8
と設定することにより、無事に全ての通信をVPNサーバ経由とすることが出来ました。
DNSの設定が無かったことにより名前解決出来ていなかった事が原因のようでした。
余談ですが、通常のVPNでは全ての通信をVPNサーバ経由で通し、上記のようなVPNサーバ側のセグメントのみ
VPNサーバ経由、それ以外の通信はVPNサーバを経由せず直接通信する通信の仕方を Split Tunneling
と言います。
- Endpoint
接続先のVPNサーバのグローバルIPアドレスまたはドメイン名を指定します。DDNS等でサーバを識別できるように設定している場合はそのDDNS名を指定します。 :
に続けてサーバ側の設定で ListenPort
で指定した番号を指定します。
終わりに
以上でVPNサーバとVPNクライアントで接続が可能となります。
サーバ側の設定ファイルやクライアント側の設定ファイルが非常に短くシンプルで、OpenVPNやStrongSwanの設定と比較すると圧倒的に簡単に思えます。
MacOS, Windowsに関してはGUIのStrongSwanアプリを用いて接続、Linuxクライアントに関しては、 /etc/wireguard/wg0.conf
にクライアント側の接続設定を記載して
sudo wg-quick up wg0
のように接続しています。MacOS, WindowsのGUIアプリでは、同時に複数のWireGuard VPNサーバへの接続は現時点では不可能のようです(同時に接続しようとすると既に接続しているコネクションがDeactivate(切断)される)。
Linuxのコマンドラインからの接続においては、 /etc/wireguard/wg1.conf
のように別の設定ファイルを作成し、
sudo wg-quick up wg1
のようにすることで、複数のWireGuard VPNサーバへ同時接続が実現できています。
切断する時は
sudo wg-quick down wg0
のように実行します。
また、Linux OS起動時に自動的に接続するには
sudo systemctl enable wg-quick@wg0.service
等と設定することで、自動接続が可能です。
LinuxにおいてもNetwork-Managerに統合されたGUI接続が可能なのですが、 Ubuntu 18.04 LTSのNetwork-ManagerにおいてはまだWireGuardのサポートが追加されておらず、2020年4月頃リリース予定の Ubuntu 20.04 LTSでこれが可能になる見込みです。
そうなれば、コマンドラインだけでなくGUIからの接続も試してみたいなと思っています。
以上、快適なVPNライフをお過ごしください。
参考
本記事のWireGuardを用いた簡単なSaaS「tailscale」
https://internet.watch.impress.co.jp/docs/column/shimizu/1303751.html