WireGuard

提供: ArchWiki
2024年8月14日 (水) 23:09時点におけるKusanaginoturugi (トーク | 投稿記録)による版 (Category:仮想プライベートネットワーク)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
ナビゲーションに移動 検索に移動

関連記事

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

コマンドラインツール

  • wg_tool — サーバーとユーザーの wireguard 設定を管理するツール。
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 を有効化することでネットワーク接続が有効になってからサービスが実行されるようになります。

トンネルのテスト

トンネルが確立されたら、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 カーネルモジュールを使用する場合、実行することでデバッグ情報をカーネルリングバッファ(dmesgjournalctl で表示可能)に書き込むことができます。

# 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 をサポートするネットワークソフトを使用することです。

ノート: systemd-resolved のユーザは、systemd-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と組み合わせて wg-quick@.service を使用)において、これはレジュームに失敗するかもしれません。さらに、これは静的なネットワーク設定に対してのみ機能し、ゲートウェイやデバイスが変更されると失敗します(例えば、ラップトップでイーサネットや無線 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-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 キーは必要ありません。

参照