2 つの拠点、1 つのサブネット、1 つの WireGuard ハブ: 動かす方法
両方の LAN が 10.10.7.0/24 にあるため、ハブは宛先で拠点を選べません。サービスごとにエイリアスを与え、そのゲートウェイで変換します。
両方の拠点が同じ LAN レンジを使っていて、重複そのものが設計を壊すわけではありません。ハブは宛先アドレスだけで拠点を選ばなければならず、同一の宛先が二つあると選ぶ手がかりが何もありません。動いているオフィスをトンネルに合わせて採番し直すのは、通常、公開するサービスごとにトンネルで運べる別のアドレスを与えるより悪い取引です。以下の設計は拠点ごとに HTTPS サービスを一つだけ公開し、それ以外は何も公開しません。
重複が本当の問題ではない理由
WireGuard は宛先で転送します:peer の AllowedIPs がどの peer にパケットが届くかを決めます。二つの peer が同時に 10.10.7.0/24 を広告すると、どちらかがすべての照会に勝つことになります。これは peer テーブルの性質でありトンネルの性質ではないので、ここでの解決策はアドレス計画であってルーティングの小細工ではありません。
計画は、LAN の広告を完全にやめることです。代わりにサービスごとのエイリアスを広告し、拠点ごとに一つのアドレスを割り当て、各拠点のゲートウェイがそのエイリアスを実際のアプリケーションに変換します。
利用者は二つの一意なアドレスをルーティングし、曖昧なプレフィックスを見ることはなく、どちらのオフィスでも何も変わりません。これは境界も正直に示します:各拠点から HTTPS サービスを一つ公開するのであって、二つのネットワークを統合するのではありません。続くルールが小さいままでいられるのは、その表明が狭いからです。より広い表明にはより広いルールが必要で、こうした設計が複雑になるのはそのためです。
各拠点に利用者がルーティングできるエイリアスを与える
利用者の端末、ハブ、どちらの LAN とも衝突しないレンジからアドレスを選びます。ここではハブが 10.66.0.1、利用者が 10.66.0.10、ゲートウェイが 10.66.0.21 と 10.66.0.22、二つのエイリアスが 10.77.1.20 と 10.77.2.20 です。ハブは各エイリアスをそれを所有する peer 経由で公開するので、あるエイリアス宛ての外向きパケットは対応する拠点からしか出られません:
[Interface]
Address = 10.66.0.1/32
ListenPort = 51820
PrivateKey = HUB_KEY
[Peer]
PublicKey = USER_PUBLIC_KEY
AllowedIPs = 10.66.0.10/32
[Peer]
PublicKey = SITE_A_PUBLIC_KEY
AllowedIPs = 10.66.0.21/32, 10.77.1.20/32
[Peer]
PublicKey = SITE_B_PUBLIC_KEY
AllowedIPs = 10.66.0.22/32, 10.77.2.20/32
利用者側に必要なのは二つのエイリアスだけなので、クライアント設定は二つの LAN プレフィックスから自由でいられます。その設定には実際の LAN のどちらも出てきません:
[Interface]
Address = 10.66.0.10/32
PrivateKey = USER_KEY
[Peer]
PublicKey = HUB_PUBLIC_KEY
Endpoint = hub.example.net:51820
AllowedIPs = 10.77.1.20/32, 10.77.2.20/32
PersistentKeepalive = 25
各ゲートウェイはハブと利用者の送信元だけを広告し、それ以外は広告しないので、ある拠点がもう一方の LAN を知ることはありません。Keepalive は拠点のアップリンクで NAT マッピングを維持し、トラフィックを許可するものではなく、何を通すかは依然としてファイアウォールが決めます。片方のゲートウェイ設定をもう片方にコピーするのは、秘密鍵、インターフェースアドレス、エイリアスがすべて変わる限り問題ありません。
ハブが二つの peer 間で許可すべきもの
ハブは自身の二つの peer 間でパケットを転送しますが、これは forward チェーンの判断であり、入力の判断ではありません。プラットフォームの通常の仕組みで IPv4 転送を有効にし、そのうえで設計が必要とする組だけを許可します。
以下のルールは利用者に一つのエイリアスと一つのポートを許可し、接続追跡を通じて戻りのトラフィックを許可します。forward 経路上の他のすべてを落とすのが要点です:
nft add table inet hub_transit
nft add chain inet hub_transit forward '{ type filter hook forward priority 0 ; policy drop ; }'
nft add rule inet hub_transit forward ct state established,related accept
nft add rule inet hub_transit forward iifname wg0 oifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 accept
二つの点は静かな失敗を招くので述べておきます。ある基本チェーンの accept は別のチェーンの drop を打ち消さないため、既存のポリシーに統合し、並べて読み込まないでください。また送信元アドレスは人ではなく端末を識別するので、アプリケーションの認証はネットワークの許可と分けてください。
エイリアスが実際のアドレスになる場所
拠点 A は 10.77.1.20 への要求を受け取り、宛先を実際のアプリケーションに書き換え、送信元を自分の LAN アドレスに書き換えるので、トンネルへの経路なしに応答が戻せます。両方の変換を一か所で行うことで、ネットワークの他の部分はエイリアスを知りません。以下のルールが仕組みのすべてです:
nft add table ip site_a_nat
nft add chain ip site_a_nat pre '{ type nat hook prerouting priority -100 ; policy accept ; }'
nft add chain ip site_a_nat post '{ type nat hook postrouting priority 100 ; policy accept ; }'
nft add rule ip site_a_nat pre iifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 dnat to 10.10.7.20:443
nft add rule ip site_a_nat post iifname wg0 oifname lan0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.10.7.20 snat to 10.10.7.2
次に拠点 A の forward ポリシーが、変換されたフローをトンネルインターフェースから LAN インターフェースへ、さらに戻り方向も許可する必要があります。forward フックは宛先変換の後、送信元書き換えの前に宛先を見るため、ルールは実際のアプリケーションのアドレスを名指しします。ルールが何にも一致しないように見えるときは、この二つのフックをこの順に読んでください。エイリアスに対して書かれた forward ルールは、そのフックではエイリアスがもう存在しないため決して一致しません。
拠点 B は自分のエイリアスと自分の鍵でこれを繰り返します。二つの peer が一つの識別子を共有するのは見つけにくく、ファイルのコピーで簡単に作れてしまう設定ミスなので、拠点 A の秘密鍵を再利用してはいけません。二つのゲートウェイ文書は、変えるべき値以外は同一に保ち、レビューで違いが目立つようにします。コピーしたファイルがその不具合の通常の原因です。
送信元の書き換えには代償があります。アプリケーションはゲートウェイを自分のクライアントと見なすので、ログには誰が接続したかが出なくなります。ゲートウェイの監査証跡は残し、変換が消したネットワーク上の識別子を補うためにアプリケーションのログインを弱めないでください。
公開した二つの名前が応答することを証明する方法
各エイリアスに DNS 名を与え、変換はリダイレクトや埋め込まれた絶対 URL を書き換えないため、その名前でアプリケーションと証明書を設定します。拠点ごとに一つの名前を使えば、証明書の不一致がルーティングの不具合と取り違えられることはありません。
実際のクライアントから試し、どの拠点が応答したかを確認し、許可されていないポートも試します。NAT を変更した後は、確立済みの状態が古いマッピングを保持するため、新しい接続を使ってください:
wg show wg0 allowed-ips
sudo nft list ruleset
curl -sS -o /dev/null -w "%{http_code}\n" https://site-a.example.net/
最初のコマンドでエイリアスが空か想定外なら、ファイアウォールのルールが問題になる前に peer の選択が誤っています。エイリアスが正しくても名前が解決しないなら、問題は DNS と証明書に移っています。両方の名前が応答し、三番目のポートが閉じたままなら、設計は主張どおりに働きます:狭く公開された二つのサービスであり、統合された二つの LAN ではありません。