WireGuard
WireGuard のホームページより:
- Wireguard は最先端の暗号技術を使用する非常にシンプルで高速な VPN です。IPSec よりも高速・単純・軽量・有用であることを目指しており、面倒なことを避けています。OpenVPN と比べると高いパフォーマンスを発揮します。WireGuard は組み込みインターフェイスからスーパーコンピュータまで様々な環境に対応する汎用の VPN として設計されています。最初は Linux カーネル用にリリースされましたが、現在はクロスプラットフォーム(Windows、macOS、BSD、iOS、Android)であり、広く展開できます。
この記事で使用されている主な概念の大まかな紹介は、WireGuard のプロジェクトホームページにあります。 WireGuard は、2019年後半から Linux カーネルに組み込まれています。
インストール
ユーザースペースユーティリティの wireguard-tools パッケージをインストールしてください。
または、ピアキーが使用可能な場合、さまざまなネットワークマネージャーが WireGuard のサポートを提供します。詳細については、#設定の永続化 を参照してください。
グラフィカルクライアント
- Qomui — 高度な機能と複数のプロバイダーのサポートを備えた OpenVPN GUI。
コマンドラインツール
- wg_tool — サーバーとユーザーの wireguard 設定を管理するツール。
使用方法
ここでは以下の構成でピア間のトンネルを設定する方法を説明します:
Peer A | Peer B | |
---|---|---|
外部 IP アドレス | 10.10.10.1/24 | 10.10.10.2/24 |
内部 IP アドレス | 10.0.0.1/24 | 10.0.0.2/24 |
wireguard 使用ポート | UDP/48574 | UDP/39814 |
外部アドレスはあらかじめ用意してください。例えば、ピア A からピア B に ping 10.10.10.2
で ping が通るようにする必要があります。内部アドレスは ip
コマンドで作成する新しいアドレスで、WireGuard ネットワーク内で内部的に共有します。IP アドレスの /24
は CIDR です。
鍵の生成
秘密鍵を作成するには:
$ wg genkey > privatekey
公開鍵を作成するには:
$ wg pubkey < privatekey > publickey
もしくは、秘密鍵と公開鍵を同時に作成するには:
$ wg genkey | tee privatekey | wg pubkey > publickey
量子コンピュータが実用化された場合を考慮して、既存の公開鍵暗号に対称鍵暗号のレイヤーを追加するために事前共有鍵を生成することもできます:
# wg genpsk > preshared
手動設定
Peer A の設定
このピアでは UDP ポート 48574 を開いて内部・外部 IP アドレスと公開鍵を紐づけてピア B からの接続を許可します:
# ip link add dev wg0 type wireguard # ip addr add 10.0.0.1/24 dev wg0 # wg set wg0 listen-port 48574 private-key ./privatekey # wg set wg0 peer [Peer B public key] persistent-keepalive 25 allowed-ips 10.0.0.2/32 endpoint 10.10.10.2:39814 # ip link set wg0 up
[Peer B public key]
は EsnHH9m6RthHSs sd9uM6eCHe/mMVFaRh93GYadDDnM=
という形式で指定してください。allowed-ips
はトラフィックの送信を許可するアドレスのリストを指定してください。allowed-ips 0.0.0.0/0
であらゆるアドレスにトラフィックを送信できるようになります。
Peer B の設定
ピア A とほとんど同じですが、wireguard デーモンで使用するのは UDP ポート 39814 でピア A からの接続だけを許可します:
# ip link add dev wg0 type wireguard # ip addr add 10.0.0.2/24 dev wg0 # wg set wg0 listen-port 39814 private-key ./privatekey # wg set wg0 peer [Peer A public key] persistent-keepalive 25 allowed-ips 10.0.0.1/32 endpoint 10.10.10.1:48574 # ip link set wg0 up
基本チェック
パラメータを付けずに wg コマンドを呼び出すことで現在の設定を確認できます。
例えば、ピア A で実行すると以下のように表示されます:
peer-a$ wg interface: wg0 public key: UguPyBThx/ xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8= private key: (hidden) listening port: 48574 peer: 9jalV3EEBnVXahro0pRMQ cHlmjE33Slo9tddzCVtCw= endpoint: 10.10.10.2:39814 allowed ips: 10.0.0.2/32
トンネルの末端にアクセスすることができるはずです:
peer-a$ ping 10.0.0.2
設定の永続化
showconf
を使うことで設定を保存できます:
# wg showconf wg0 > /etc/wireguard/wg0.conf # wg setconf wg0 /etc/wireguard/wg0.conf
ピア設定例
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.1/32 PrivateKey = [CLIENT PRIVATE KEY] MTU = 1420 [Peer] PublicKey = [SERVER PUBLICKEY] AllowedIPs = 10.0.0.0/24, 10.123.45.0/24, 1234:4567:89ab::/48 Endpoint = [SERVER ENDPOINT]:51820 PersistentKeepalive = 25
systemd-networkd の設定例
/etc/systemd/network/30-wg0.netdev
[NetDev] Name = wg0 Kind = wireguard Description = Wireguard [WireGuard] PrivateKey = [CLIENT PRIVATE KEY] [WireGuardPeer] PublicKey = [SERVER PUBLIC KEY] PresharedKey = [PRE SHARED KEY] AllowedIPs = 10.0.0.0/24 Endpoint = [SERVER ENDPOINT]:51820 PersistentKeepalive = 25
/etc/systemd/network/30-wg0.network
[Match] Name = wg0 [Network] Address = 10.0.0.3/32 DNS = 10.0.0.1 [Route] Gateway = 10.0.0.1 Destination = 10.0.0.0/24
特定のユースケース: VPN サーバー
このセクションでは OpenVPN などと同じように暗号化されたトンネルを使ってサーバー・ネットワークリソースにアクセスできるようにするため、WireGuard の「サーバー」と汎用的な「クライアント」を設定します。サーバーは Linux で稼働させますがクライアントのプラットフォームは複数選択できます (WireGuard プロジェクトは Linux ネイティブや macOS のソフトウェアに加えて iOS や Android プラットフォームのアプリも提供しています)。詳しくは公式プロジェクトの インストールリンク を見てください。
サーバー
サーバー側のマシンではまず IPv4 フォワーディングを有効にしてください:
# sysctl net.ipv4.ip_forward=1
変更を永続化するには /etc/sysctl.d/99-sysctl.conf
に net.ipv4.ip_forward = 1
を追加します。
インターネットに接続する場合はファイアウォールを設定することが推奨されます:
- WireGuard が動作するポートの UDP トラフィックを許可してください (例えば 51820/udp のトラフィックを許可)。
- WireGurad の設定
/etc/wireguard/wg0.conf
に転送ポリシーを記述しない場合はファイアウォールで転送ポリシーを設定してください。以下の例はそのまま動作します。
最後に、WAN からアクセスできるようにするため WireGuard のポートをルーターからサーバーの LAN の IP に転送するようにする必要があります。
鍵の生成
サーバーとクライアントの鍵を#鍵の生成で説明しているように生成してください。
サーバーの設定
サーバーの設定ファイルを作成:
/etc/wireguard/wg0.conf
[Interface] Address = 10.200.200.1/24 SaveConfig = true ListenPort = 51820 PrivateKey = [SERVER PRIVATE KEY] MTU = 1420 # note - substitute eth0 in the following lines to match the Internet-facing interface PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer] # client foo PublicKey = [FOO's PUBLIC KEY] PresharedKey = [PRE-SHARED KEY] AllowedIPs = 10.200.200.2/32 [Peer] # client bar PublicKey = [BAR's PUBLIC KEY] PresharedKey = [PRE-SHARED KEY] AllowedIPs = 10.200.200.3/32
インターフェイスは手動あるいは systemctl で制御できます。
wg-quick up wg0
でインターフェイスが立ち上がり wg-quick down wg0
で終了します。
systemctl で制御したい場合、[email protected]
を起動・有効化してください。"@" 記号の後ろにサーバーの設定の名前を入力してください。例:
# systemctl start wg-quick@wg0
クライアントの設定
クライアントの設定ファイルを作成:
foo.conf
[Interface] Address = 10.200.200.2/24 PrivateKey = [FOO's PRIVATE KEY] DNS = 10.200.200.1 MTU = 1420 [Peer] PublicKey = [SERVER PUBLICKEY] PresharedKey = [PRE-SHARED KEY] AllowedIPs = 0.0.0.0/0 Endpoint = my.ddns.address.com:51820
bar.conf
[Interface] Address = 10.200.200.3/24 PrivateKey = [BAR's PRIVATE KEY] DNS = 10.200.200.1 MTU = 1420 [Peer] PublicKey = [SERVER PUBLICKEY] PresharedKey = [PRE-SHARED KEY] AllowedIPs = 0.0.0.0/0 Endpoint = my.ddns.address.com:51820
クライアントがスマートフォンなどの場合、qrencode を使って設定を共有することができます:
$ qrencode -t ansiutf8 < foo.conf
トンネルのテスト
トンネルが確立されたら、netcatを使ってトラフィックを送り、スループットや CPU 使用率などをテストすることができます。
トンネルの片側で nc
を listen モードで実行し、もう片側で /dev/zero
から送信モードの nc
にデータをパイプします。
以下の例では、ポート 2222 がトラフィックに使用されています(ファイアウォールを使用している場合は、ポート2222のトラフィックを必ず許可してください)。
トンネルの片側で、トラフィックを確認する。
$ nc -vvlnp 2222
トンネルの向こう側では、トラフィックを送ってください。
$ dd if=/dev/zero bs=1024K count=1024 | nc -v 10.0.0.203 2222
状態の監視は wg
で直接行うことができます。
# wg
interface: wg0 public key: UguPyBThx/ xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8= private key: (hidden) listening port: 51820 peer: 9jalV3EEBnVXahro0pRMQ cHlmjE33Slo9tddzCVtCw= preshared key: (hidden) endpoint: 192.168.1.216:53207 allowed ips: 10.0.0.0/0 latest handshake: 1 minutes, 17 seconds ago transfer: 56.43 GiB received, 1.06 TiB sent
ヒントとテクニック
秘密鍵を暗号化して保存
設定ファイルの [Interface] セクションの PrivateKey 行を以下のように置き換えることで pass を使って秘密鍵を暗号化できます:
PostUp = wg set %i private-key <(su user -c "export PASSWORD_STORE_DIR=/path/to/your/store/; pass WireGuard/private-keys/%i")
user はユーザー名に置き換えてください。詳しくは wg-quick(8) を参照。
IP が変わるエンドポイント
サーバーのドメインの解決後、WireGuard は DNS で再度変更をチェックすることはありません [1]。
WireGuard サーバーの IP アドレスが DHCP, Dyndns, IPv6 などによって頻繁に変更された場合、WireGuard クライアントは接続を失います。その際 wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT"
などのようにエンドポイントを更新しなくてはなりません。
また、エンドポイントがアドレスを変更したとき (例えば新しいプロバイダ・データセンターに移行した場合)、DNS を更新するだけでは不十分となるため、DNS ベースのセットアップでは reresolve-dns を定期的に実行する必要が出てきます。
wireguard-tools には WG の設定ファイルを読み込んでエンドポイントのアドレスを自動的にリセットするスクリプト /usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh
が含まれています。
/usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh /etc/wireguard/wg.conf
を定期的に実行することで IP が変わったエンドポイントから復旧できます。
systemd タイマーを使って30秒ごとに WireGuard のエンドポイントを更新する例 [2]:
/etc/systemd/system/wireguard_reresolve-dns.timer
[Unit] Description=Periodically reresolve DNS of all WireGuard endpoints [Timer] OnCalendar=*:*:0/30 [Install] WantedBy=timers.target
/etc/systemd/system/wireguard_reresolve-dns.service
[Unit] Description=Reresolve DNS of all WireGuard endpoints Wants=network-online.target After=network-online.target [Service] Type=oneshot ExecStart=/bin/sh -c 'for i in /etc/wireguard/*.conf; do /usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh "\$i"; done'
上記ファイルを作成したら wireguard_reresolve-dns.timer
を起動・有効化してください。
QR コードを生成
クライアントが電話などのモバイル デバイスの場合、qrencode を使用してクライアントの設定 QR コードを生成し、端末に表示できます。
$ qrencode -t ansiutf8 -r client.conf
デバッグログを有効にする
ダイナミックデバッグをサポートするカーネル上で Linux カーネルモジュールを使用する場合、実行することでデバッグ情報をカーネルリングバッファ(dmesg や journalctl で表示可能)に書き込むことができます。
# modprobe wireguard # echo module wireguard p > /sys/kernel/debug/dynamic_debug/control
ピア(サーバー)設定の再読み込み
WireGuard ピア(主にサーバ)が設定から他のピアを追加または削除し、アクティブなセッションを停止せずに再読み込みしたい場合、次のコマンドを実行することができます:
# wg syncconf ${WGNET} <(wg-quick strip ${WGNET})
ここで、$WGNET
は WireGuard インターフェース名または設定ベース名です。例えば、wg0
(サーバー用) または client
です。(クライアント用には .conf という拡張子をつけません)。
トラブルシューティング
ルートが定期的にリセットされる
NetworkManager が WireGuard のインターフェイスを管理しないようにしてください:
/etc/NetworkManager/conf.d/unmanaged.conf
[keyfile] unmanaged-devices=interface-name:wg0
DNS 解析の不具合について
すべてのトラフィックを WireGuard インターフェイスでトンネリングする場合、しばらくすると、または新規接続時に接続が失われたように見えることがあります。これは、ネットワークマネージャまたは DHCP クライアントが /etc/resolv.conf
を上書きすることによって発生した可能性があります。
デフォルトでは wg-quick は新しい DNS エントリを登録するために resolvconf を使用します (設定ファイルの DNS
キーワードから).これは、resolvconf を使用しないネットワークマネージャや DHCP クライアントで、/etc/resolv.conf
を上書きし、wg-quick が追加した DNS サーバを削除するため問題が発生するでしょう。
解決策としては、resolvconf をサポートするネットワークソフトを使用することです。
NetworkManager のユーザは、デフォルトでは resolvconf を使用しないことを知っておく必要があります。systemd-resolved を使うことが推奨されています。 これが望ましくない場合は openresolv をインストールして、NetworkManager#Use openresolv. を使用するように NetworkManagerを設定してください。
低 MTU
MTU が低すぎる (1280 未満) ため、wg-quick は WireGuard インターフェイスの作成に失敗した可能性があります。これは、クライアントのインターフェイス セクションの WireGuard 設定で MTU 値を設定することで解決できます。
foo.config
[Interface] Address = 10.200.200.2/24 MTU = 1420 PrivateKey = PEER_FOO_PRIVATE_KEY DNS = 10.200.200.1
鍵の長さや形式が正しくない
以下のエラーを回避するためには、鍵ファイルのパスではなく、鍵の値を設定ファイルに記述してください。
# wg-quick up wg0
[#] ip link add wg0 type wireguard [#] wg setconf wg0 /dev/fd/63 Key is not the correct length or format: `/path/example.key' Configuration parsing error [#] ip link delete dev wg0
NAT /ファイアウォールの背後にある持続的な接続を確立することができない
デフォルトでは、WireGuard ピアは通信する必要がない間は沈黙を保つため、NAT やファイアウォールの背後にあるピアは、他のピアに自らアクセスするまで他のピアからアクセスできない場合があります(または接続がタイムアウトする場合もあります)。NAT やファイアウォールの背後にあるピアのPersistentKeepalive = 25
設定に追加することで、接続が開いたままになることを保証できます。
# Set the persistent-keepalive via command line (temporarily)
[#] wg set wg0 peer $PUBKEY persistent-keepalive 25
ループ ルーティング
エンドポイント IP を許可 IP リストに追加すると、カーネルは、元のルートを使用するのではなく、当該デバイスバインディングにハンドシェイクを送信しようとします。その結果、ハンドシェイクの試行が失敗します。
回避策として、エンドポイントへの正しいルートを、以下の方法で手動で追加する必要があります。
ip route add <endpoint ip> via <gateway> dev <network interface>
e.g. for peer B from above in a standard LAN setup:
ip route add 203.0.113.102 via 192.168.0.1 dev eth0
このルートを永続化するには、PostUp = ip route ...
というコマンドを wg0.conf
の [Interface]
セクションに追加することができます。しかし、特定のセットアップ(例えば、NetworkManagerと組み合わせて [email protected]
を使用)において、これはレジュームに失敗するかもしれません。さらに、これは静的なネットワーク設定に対してのみ機能し、ゲートウェイやデバイスが変更されると失敗します(例えば、ラップトップでイーサネットや無線 LAN を使用している場合など)。
NetworkManagerを使用する場合、より柔軟な解決策として、ディスパッチャスクリプトを使用して WireGuardを起動することができます。root として以下を作成します。
/etc/NetworkManager/dispatcher.d/50-wg0.sh
#!/bin/sh case $2 in up) wg-quick up wg0 ip route add <endpoint ip> via $IP4_GATEWAY dev $DEVICE_IP_IFACE ;; pre-down) wg-quick down wg0 ;; esac
まだ起動していない場合は、NetworkManager-dispatcher.service
を起動し、有効にしてください。
また、NetworkManager が wg0
のルートを管理していないことを確認してください。(上記参照)。
NetworkManager で切断される
デスクトップの場合、全てのトラフィックを WireGuard のインターフェイス経由にすると切断が発生することがあります。アクセスポイントに新しく接続してしばらくした後に切断が発生します。
デフォルトでは wg-quick は openresolv などの resolvconf プロバイダを使用して新しい DNS エントリを登録します (設定ファイルの DNS
キーワード)。しかしながら NetworkManager はデフォルトでは resolvconf を使用しません。新しい DHCP リースが取得されるたびに NetworkManager は DHCP によって提供されたアドレスで全体の DNS アドレスを上書きします。
resolvconf を使う
システムで resolvconf を使っていて接続が切れる場合、NetworkManager が resolvconf を使うように設定してください:
/etc/NetworkManager/conf.d/rc-manager.conf
[main] rc-manager=resolvconf
dnsmasq を使う
Dnsmasq#openresolv を見てください。
systemd-resolved を使う
2018年9月時点では、systemd-resolvconf による resolvconf 互換モードは wg-quick で機能しません。ただし PostUp
フックを使うことで wg-quick から systemd-resolved を使用することはできます。まず NetworkManager で systemd-resolved を使うように設定: NetworkManager#systemd-resolved。それからトンネルの設定を変更:
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.2/24 # The client IP from wg0server.conf with the same subnet mask PrivateKey = [CLIENT PRIVATE KEY] PostUp = resolvectl domain %i "~."; resolvectl dns %i 10.0.0.1; resolvectl dnssec %i yes MTU = 1420 [Peer] PublicKey = [SERVER PUBLICKEY] AllowedIPs = 0.0.0.0/0, ::0/0 Endpoint = [SERVER ENDPOINT]:51820 PersistentKeepalive = 25
新しく利用可能になった DNS サーバーに優先度を与えるためにドメイン名は "~."
に設定する必要があります。
wg0
が落ちたときに systemd-resolved は自動的に全てのパラメータを戻すため PostDown
キーは必要ありません。