Два сайта, една подмрежа, един WireGuard хъб: как да го накараме да работи
Двете LAN мрежи са на 10.10.7.0/24, така че хъбът не може да избере сайт по местоназначение. Дайте на всяка услуга псевдоним и превеждайте на нейния шлюз.
Двата сайта използват един и същ LAN диапазон и точно припокриването не е това, което чупи архитектурата. Хъбът трябва да избира сайт само по адреса на местоназначението, а две еднакви местоназначения не му дават нищо, по което да избира. Преномерирането на работещ офис, за да пасне на тунел, обикновено е по-лоша сделка от това да дадете на всяка публикувана услуга отделен адрес, който тунелът може да пренесе. Архитектурата по-долу публикува една HTTPS услуга на сайт и нищо друго.
Защо припокриването не е истинският проблем
WireGuard препраща по местоназначение: AllowedIPs на един peer решават кой 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
Forward политиката на сайт A трябва след това да допусне преведения поток от интерфейса на тунела към LAN интерфейса, плюс обратната посока. Forward hook-ът вижда местоназначението след транслацията на местоназначението и преди пренаписването на източника, затова правилото посочва адреса на истинското приложение. Четете тези два hook-а в този ред, когато правилото изглежда, че не съвпада с нищо. Forward правило, написано срещу псевдонима, никога не може да съвпадне, защото псевдонимът вече не съществува в този hook.
Сайт B повтаря това със свой псевдоним и свой ключ. Той не трябва да използва повторно частния ключ на сайт A, защото два peer-а, споделящи една идентичност, са конфигурационна грешка, която е трудна за виждане и лесна за създаване чрез копиране на файл. Дръжте двата документа на шлюзовете идентични, с изключение на стойностите, които трябва да се различават, за да изпъква разликата при преглед. Копиран файл е обичайният източник на тази повреда.
Пренаписването на източника има цена. Приложението вижда шлюза като свой клиент, затова журналите му вече не показват кой потребител се е свързал. Пазете одиторската следа на шлюза и не отслабвайте входа на приложението, за да компенсирате мрежова идентичност, която преводът е премахнал.
Как да докажете, че и двете публикувани имена отговарят
Дайте на всеки псевдоним 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 мрежи.