WireGuard

提供: ArchWiki
2023年3月3日 (金) 15:54時点におけるKusanaginoturugi (トーク | 投稿記録)による版 (→‎systemd-resolved を使う: 参照を追加)
ナビゲーションに移動 検索に移動

関連記事

WireGuard のホームページより:

Wireguard は最先端の暗号技術を使用する非常にシンプルで高速な VPN です。IPSec よりも高速・単純・軽量・有用であることを目指しており、面倒なことを避けています。OpenVPN と比べると高いパフォーマンスを発揮します。WireGuard は組み込みインターフェイスからスーパーコンピュータまで様々な環境に対応する汎用の VPN として設計されています。最初は Linux カーネル用にリリースされましたが、現在はクロスプラットフォーム(Windows、macOS、BSD、iOS、Android)であり、広く展開できます。

この記事で使用されている主な概念の大まかな紹介は、WireGuard のプロジェクトホームページにあります。 WireGuard は、2019年後半から Linux カーネルに組み込まれています。

インストール

ユーザースペースユーティリティの wireguard-tools パッケージをインストールしてください。

または、ピアキーが使用可能な場合、さまざまなネットワークマネージャーが WireGuard のサポートを提供します。詳細については、#設定の永続化 を参照してください。

グラフィカルクライアント

  • Qomui — 高度な機能と複数のプロバイダーのサポートを備えた OpenVPN GUI。
https://github.com/corrad1nho/qomui || qomuiAUR

Command-line tools

  • wg_tool — Tool to manage wireguard configs for server and users.
https://github.com/gene-git/wg_tool || wg_toolAUR

使用方法

ここでは以下の構成でピア間のトンネルを設定する方法を説明します:

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 アドレスの /24CIDR です。

鍵の生成

ノート: 秘密鍵ファイルを保存するときは 600 などのように厳しいパーミッションを使うことを推奨します。

秘密鍵を作成するには:

$ 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.confnet.ipv4.ip_forward = 1 を追加します。

インターネットに接続する場合はファイアウォールを設定することが推奨されます:

  • WireGuard が動作するポートの UDP トラフィックを許可してください (例えば 51820/udp のトラフィックを許可)。
  • WireGurad の設定 /etc/wireguard/wg0.conf に転送ポリシーを記述しない場合はファイアウォールで転送ポリシーを設定してください。以下の例はそのまま動作します。

最後に、WAN からアクセスできるようにするため WireGuard のポートをルーターからサーバーの LAN の IP に転送するようにする必要があります。

鍵の生成

サーバーとクライアントの鍵を#鍵の生成で説明しているように生成してください。

サーバーの設定

サーバーの設定ファイルを作成:

ノート: PresharedKey 行は任意です。使用する場合、事前共有鍵をサーバーとクライアントの設定ファイルで設定する必要があります。詳しくは wg の man ページを参照してください。
/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 で制御したい場合、wg-quick@.service起動有効化してください。"@" 記号の後ろにサーバーの設定の名前を入力してください。例:

# 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
警告: 設定ファイルを作るときは、公開・秘密鍵と Address = の値を適当に置き換えてください。

クライアントがスマートフォンなどの場合、qrencode を使って設定を共有することができます:

$ qrencode -t ansiutf8 < foo.conf
ノート: NetworkManager を使用している場合、NetworkManager-wait-online.service を、systemd-networkd を使用している場合、systemd-networkd-wait-online.service を有効化することでネットワーク接続が有効になってからサービスが実行されるようになります。

Testing the tunnel

この記事あるいはセクションは #Basic checkups と合併することが議論されています。
ノート: Same topic. (議論: トーク:WireGuard#)

Once a tunnel has been established, one can use netcat to send traffic through it to test out throughput, CPU usage, etc. On one side of the tunnel, run nc in listen mode and on the other side, pipe some data from /dev/zero into nc in sending mode.

In the example below, port 2222 is used for the traffic (be sure to allow traffic on port 2222 if using a firewall).

On one side of the tunnel listen for traffic:

$ nc -vvlnp 2222

On the other side of the tunnel, send some traffic:

$ dd if=/dev/zero bs=1024K count=1024 | nc -v 10.0.0.203 2222

Status can be monitored using wg directly.

# 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起動有効化してください。

Generate QR code

If the client is a mobile device such as a phone, qrencode can be used to generate client's configuration QR code and display it in terminal:

$ qrencode -t ansiutf8 -r client.conf

Enable debug logs

When using the Linux kernel module on a kernel that supports dynamic debugging, debugging information can be written into the kernel ring buffer (viewable with dmesg and journalctl) by running:

# modprobe wireguard
# echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control

Reload peer (server) configuration

In case the WireGuard peer (mostly server) adding or removing another peers from its configuration and wants to reload it without stopping any active sessions, one can execute the following command to do it:

# wg syncconf ${WGNET} <(wg-quick strip ${WGNET})

Where $WGNET is WireGuard interface name or configuration base name, for example wg0 (for server) or client (without the .conf extension, for client).

この記事またはセクションは加筆を必要としています。
理由: Show how to do this with other network managers from #Persistent configuration. (議論: トーク:WireGuard#)

トラブルシューティング

ルートが定期的にリセットされる

NetworkManager が WireGuard のインターフェイスを管理しないようにしてください:

/etc/NetworkManager/conf.d/unmanaged.conf
[keyfile]
unmanaged-devices=interface-name:wg0

Broken DNS resolution

When tunneling all traffic through a WireGuard interface, the connection can become seemingly lost after a while or upon new connection. This could be caused by a network manager or DHCP client overwriting /etc/resolv.conf.

By default wg-quick uses resolvconf to register new DNS entries (from the DNS keyword in the configuration file). This will cause issues with network managers and DHCP clients that do not use resolvconf, as they will overwrite /etc/resolv.conf thus removing the DNS servers added by wg-quick.

The solution is to use networking software that supports resolvconf.

ノート: Users of systemd-resolved should make sure that systemd-resolvconf is installed.

Users of NetworkManager should know that it does not use resolvconf by default. It is recommended to use systemd-resolved. If this is undesirable, install openresolv and configure NetworkManager to use it: NetworkManager#Use openresolv.

Low MTU

Due to too low MTU (lower than 1280), wg-quick may have failed to create the WireGuard interface. This can be solved by setting the MTU value in WireGuard configuration in Interface section on client.

foo.config
[Interface]
Address = 10.200.200.2/24
MTU = 1420
PrivateKey = PEER_FOO_PRIVATE_KEY
DNS = 10.200.200.1

Key is not the correct length or format

To avoid the following error, put the key value in the configuration file and not the path to the key file.

# 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

Unable to establish a persistent connection behind NAT / firewall

By default, WireGuard peers remain silent while they do not need to communicate, so peers located behind a NAT and/or firewall may be unreachable from other peers until they reach out to other peers themselves (or the connection may time out). Adding PersistentKeepalive = 25 to the [Peer] settings of a peer located behind a NAT and/or firewall can ensure that the connection remains open.

# Set the persistent-keepalive via command line (temporarily)
[#] wg set wg0 peer $PUBKEY persistent-keepalive 25

Loop routing

Adding the endpoint IP to the allowed IPs list, the kernel will attempt to send handshakes to said device binding, rather than using the original route. This results in failed handshake attempts.

As a workaround, the correct route to the endpoint needs to be manually added using

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

To make this route persistent, the command can be added as PostUp = ip route ... to the [Interface] section of wg0.conf. However, on certain setups (e.g. using wg-quick@.service in combination with NetworkManager) this might fail on resume. Furthermore, this only works for a static network setup and fails if gateways or devices change (e.g. using ethernet or wifi on a laptop).

Using NetworkManager, a more flexible solution is to start WireGuard using a dispatcher script. As root, create

/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

If not already running, start and enable NetworkManager-dispatcher.service. Also, make sure that NetworkManager is not managing routes for wg0 (see above).

NetworkManager で切断される

デスクトップの場合、全てのトラフィックを WireGuard のインターフェイス経由にすると切断が発生することがあります。アクセスポイントに新しく接続してしばらくした後に切断が発生します。

デフォルトでは wg-quickopenresolv などの 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 キーは必要ありません。

参照