Обидва сайти використовують однаковий діапазон LAN, і дизайн насправді ламає не перекриття. Концентратор має вибирати сайт лише за адресою призначення, а два однакові призначення не дають йому нічого для вибору. Перенумерування працюючого офісу заради тунелю зазвичай гірша угода, ніж надання кожній опублікованій службі окремої адреси, яку тунель може пронести. Дизайн нижче публікує одну службу HTTPS на сайт і нічого більше.

Чому перекриття не є справжньою проблемою

WireGuard пересилає за призначенням: AllowedIPs піра визначають, який пір отримає пакет. Два піри не можуть одночасно оголошувати 10.10.7.0/24, якщо один із них не виграє кожен пошук. Це властивість таблиці пірів, а не тунелю, тому рішення тут — план адрес, а не трюк із маршрутизацією.

План — зовсім перестати оголошувати 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. Концентратор публікує кожен псевдонім через піра, якому він належить, тому вихідний пакет, адресований одному псевдоніму, може вийти лише через відповідний сайт:

[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 на висхідному каналі сайту; він не дає дозволу на трафік, і міжмережевий екран досі вирішує, що допускається. Копіювати конфігурацію одного шлюзу в інший можна, якщо закритий ключ, адреса інтерфейсу й псевдонім усі змінюються.

Що концентратор має дозволяти між двома своїми пірами

Концентратор пересилає пакети між двома своїми пірами, а це рішення в ланцюжку 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

Далі політика forward сайту A має допустити перекладений потік з інтерфейсу тунелю до інтерфейсу LAN, плюс зворотний напрямок. Хук forward бачить призначення після перекладу призначення і до перезапису джерела, тому правило називає адресу реального застосунку. Читайте ці два хуки в такому порядку, коли правило ніби нічому не відповідає. Правило forward, написане проти псевдоніма, ніколи не може збігтися, бо псевдоніма на цьому хуку вже немає.

Сайт B повторює це зі своїм псевдонімом і своїм ключем. Він не повинен повторно використовувати закритий ключ сайту 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/

Порожній або неочікуваний псевдонім у першій команді означає, що вибір піра неправильний ще до того, як будь-яке правило міжмережевого екрана почне мати значення. Якщо псевдонім правильний, а ім'я все одно не працює, проблема перемістилася до DNS і сертифікатів. Щойно обидва імена відповідають, а третій порт лишається закритим, дизайн робить те, що заявляє: дві вузько опубліковані служби, а не дві об'єднані мережі LAN.

Схожі статті