Dwie lokalizacje, jedna podsieć, jeden koncentrator WireGuard: uruchomcie to
Oba LAN-y są w 10.10.7.0/24, więc koncentrator nie może wybrać lokalizacji według celu. Dajcie każdej usłudze alias i tłumaczcie na jej bramie.
Obie lokalizacje używają tego samego zakresu LAN, a projektu nie psuje nakładanie się adresów. Koncentrator musi wybierać lokalizację wyłącznie na podstawie adresu docelowego, a dwa identyczne cele nie dają mu niczego do wyboru. Przenumerowanie działającego biura, aby zadowolić tunel, jest zwykle gorszą wymianą niż danie każdej publikowanej usłudze odrębnego adresu, który tunel może przenieść. Poniższy projekt publikuje jedną usługę HTTPS na lokalizację i nic więcej.
Dlaczego nakładanie się nie jest prawdziwym problemem
WireGuard przekazuje według celu: AllowedIPs peera decydują, który peer otrzyma pakiet. Dwa peery nie mogą oba ogłaszać 10.10.7.0/24 bez tego, by jeden z nich wygrywał każde wyszukiwanie. To właściwość tabeli peerów, a nie tunelu, dlatego rozwiązaniem jest tutaj plan adresów, a nie sztuczka z routingiem.
Plan polega na całkowitym zaprzestaniu ogłaszania LAN. Ogłaszajcie zamiast tego alias na usługę, jeden adres na lokalizację, i pozwólcie bramie każdej lokalizacji tłumaczyć ten alias na swoją rzeczywistą aplikację.
Użytkownik trasuje dwa unikalne adresy, nigdy nie widzi niejednoznacznego prefiksu, i nic nie zmienia się w żadnym z dwóch biur. To uczciwie nazywa też granicę: publikujecie jedną usługę HTTPS z każdej lokalizacji, nie łączycie dwóch sieci. Poniższe reguły pozostają małe, bo stwierdzenie jest wąskie. Szersze stwierdzenie wymagałoby szerszych reguł, i właśnie tak te projekty się komplikują.
Dajcie każdej lokalizacji alias, który użytkownik może trasować
Wybierzcie adresy z zakresu, który nie koliduje z niczym na komputerze użytkownika, koncentratorze ani w żadnym z dwóch LAN-ów. Tutaj koncentrator to 10.66.0.1, użytkownik to 10.66.0.10, bramy to 10.66.0.21 i 10.66.0.22, a dwa aliasy to 10.77.1.20 i 10.77.2.20. Koncentrator publikuje każdy alias przez peera, który go posiada, więc pakiet wychodzący zaadresowany do jednego aliasu może wyjść tylko przez pasującą lokalizację:
[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
Strona użytkownika potrzebuje tylko dwóch aliasów, co utrzymuje konfigurację klienta wolną od obu prefiksów LAN. Nic w tej konfiguracji nie wspomina żadnego z prawdziwych LAN-ów:
[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
Każda brama ogłasza koncentrator i źródło użytkownika, nic więcej, więc lokalizacja nigdy nie poznaje LAN-u drugiej. Keepalive utrzymuje mapowanie NAT na uplinku lokalizacji; nie autoryzuje ruchu, a zapora wciąż decyduje, co jest dopuszczane. Kopiowanie konfiguracji jednej bramy do drugiej jest w porządku, o ile klucz prywatny, adres interfejsu i alias wszystkie się zmieniają.
Co koncentrator musi dopuścić między dwoma swoimi peerami
Koncentrator przekazuje pakiety między dwoma własnymi peerami, co jest decyzją w łańcuchu forward, a nie decyzją wejściową. Włącz przekazywanie IPv4 zwykłym mechanizmem platformy, a następnie dopuść dokładnie te pary, których wymaga projekt.
Poniższa reguła pozwala użytkownikowi na jeden alias i jeden port oraz dopuszcza ruch powrotny przez śledzenie połączeń. Odrzuca wszystko inne na ścieżce forward, i o to chodzi:
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
Dwa szczegóły warto wymienić, bo powodują ciche awarie. Accept w jednym łańcuchu bazowym nie unieważnia drop w innym, więc scal to z istniejącą polityką, a nie ładuj obok. A adres źródłowy identyfikuje urządzenie, nie osobę; trzymajcie uwierzytelnianie aplikacji oddzielnie od dopuszczania sieciowego.
Gdzie alias staje się prawdziwym adresem
Lokalizacja A otrzymuje żądanie do 10.77.1.20, przepisuje cel na rzeczywistą aplikację i przepisuje źródło na własny adres LAN, aby odpowiedź mogła wrócić bez trasy do tunelu. Wykonanie obu tłumaczeń w jednym miejscu utrzymuje resztę sieci w nieświadomości o aliasie. Poniższe reguły to cały mechanizm:
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
Polityka forward lokalizacji A musi wtedy dopuścić przetłumaczony przepływ z interfejsu tunelu do interfejsu LAN, plus kierunek powrotny. Hook forward widzi cel po tłumaczeniu celu i przed przepisaniem źródła, dlatego reguła wymienia adres rzeczywistej aplikacji. Czytajcie te dwa hooki w tej kolejności, ilekroć reguła wydaje się do niczego nie pasować. Reguła forward napisana przeciw aliasowi nigdy nie może pasować, bo alias już nie istnieje w tym hooku.
Lokalizacja B powtarza to ze swoim aliasem i własnym kluczem. Nie wolno jej ponownie użyć klucza prywatnego lokalizacji A, bo dwa peery dzielące jedną tożsamość to błąd konfiguracji, który trudno zauważyć i łatwo stworzyć, kopiując plik. Utrzymujcie oba dokumenty bramy identyczne poza wartościami, które muszą się różnić, aby różnica rzucała się w oczy przy przeglądzie. Skopiowany plik jest zwykłym źródłem tej usterki.
Przepisanie źródła ma cenę. Aplikacja widzi bramę jako swojego klienta, więc jej logi nie pokazują już, który użytkownik się połączył. Zachowajcie ścieżkę audytu bramy i nie osłabiajcie logowania do aplikacji, aby zrekompensować tożsamość sieciową, którą usunęło tłumaczenie.
Jak udowodnić, że obie opublikowane nazwy odpowiadają
Dajcie każdemu aliasowi nazwę DNS i skonfigurujcie aplikację oraz certyfikat dla tej nazwy, bo tłumaczenie nie przepisuje przekierowań ani osadzonych bezwzględnych URL-i. Używajcie jednej nazwy na lokalizację, aby niezgodność certyfikatu nigdy nie została wzięta za usterkę routingu.
Testujcie z prawdziwego klienta, potwierdźcie, która lokalizacja odpowiedziała, i przetestujcie także nieautoryzowany port. Po każdej zmianie NAT używajcie nowych połączeń, bo ustalony stan zachowuje stare mapowanie:
wg show wg0 allowed-ips
sudo nft list ruleset
curl -sS -o /dev/null -w "%{http_code}\n" https://site-a.example.net/
Pusty lub nieoczekiwany alias w pierwszym poleceniu oznacza, że wybór peera jest błędny, zanim jakakolwiek reguła zapory zacznie mieć znaczenie. Jeśli alias jest poprawny, a nazwa nadal zawodzi, problem przeniósł się do DNS i certyfikatów. Gdy obie nazwy odpowiadają, a trzeci port pozostaje zamknięty, projekt robi to, co deklaruje: dwie wąsko opublikowane usługi, a nie dwa połączone LAN-y.