Czy klienci na dwóch serwerach OpenVPN mogą się wzajemnie osiągnąć?
Dwa serwery OpenVPN tworzą dwie pule klientów, a nie jedną sieć. Trasuj między nimi za pomocą odrębnych podsieci, wzajemnych tras i wyraźnej granicy zaufania.
Postawienie drugiego OpenVPN serwera daje ci drugie miejsce, do którego klienci mogą się łączyć, i nic więcej. Nie umieszcza tych klientów w sieci pierwszego serwera, a opcja o nazwie client-to-client zmienia tylko przekazywanie wewnątrz jednego procesu serwera. Obie pule stają się jedną siecią, gdy świadomie trasujesz między nimi, z właścicielem dla każdego kierunku. Wszystko poniżej zakłada tryb TUN w przestrzeni użytkownika z wyłączonym tym wewnętrznym przekazywaniem, więc decyzję podejmuje jądro.
Mit: jedna lista kont, jedna sieć
Uwierzytelnianie i osiągalność są mylone, bo oba mieszkają w konfiguracji serwera. Użytkownik, który może zalogować się do dowolnej z dwóch bram, wygląda z zewnątrz jak użytkownik jednego systemu z dwojgiem drzwi. W środku każdy serwer rozdaje adresy z własnej puli i instaluje trasy tylko dla klientów, których obsługuje. Więc klient na bramie A, który wysyła pakiet do klienta na bramie B, prosi o miejsce docelowe, o którym jego własny serwer nigdy nie słyszał. Pakiet trafia na trasę domyślną A, opuszcza tunel i dociera do firewalla, którego nigdy nie poproszono o jego przepuszczenie.
Dodanie drugiego serwera nie dodaje więc nadmiarowości, wykrywania ani wspólnej domeny rozgłoszeniowej. Dodaje sieć trasowaną, która wymaga planu, a plan zaczyna się od adresacji.
Daj każdej bramie własną pulę i adres tranzytowy
Dwa zakresy, które nie mogą kolidować z niczym innym, plus małe łącze tranzytowe między hostami, to cały plan adresacji. Trzymaj tranzyt w prywatnym segmencie, który kontrolujesz, i zapisz liczby, zanim którykolwiek serwer wyda dzierżawę.
| Gateway | Client pool | Transit address |
|---|---|---|
| gateway-a | 10.64.10.0/24 | 172.28.44.1/30 |
| gateway-b | 10.64.20.0/24 | 172.28.44.2/30 |
Oprzyj się pokusie, by dać obu serwerom tę samą pulę, aby profile pozostały identyczne. Trasa jądra nie potrafi powiedzieć, który z dwóch hostów aktualnie posiada dowolny adres w obrębie współdzielonego zakresu, więc tablica routingu wskazywałaby na jedną bramę, a klient może być podłączony do drugiej. Nazwy interfejsów to lokalne konwencje, nie współdzielony stan. Oba hosty nazywają tutaj urządzenie tunelu tun0, a łącze tranzytowe transit0, co jest w porządku, bo żaden pakiet nie niesie tych nazw.
Zainstaluj trasę po obu stronach
Każda brama potrzebuje trasy do puli drugiej przez adres tranzytowy, a przekazywanie musi być włączone, by któraś mogła działać jako hop. Najpierw potwierdź bieżącą tablicę, potem dodaj wpis i utrwal go przez menedżera sieci hosta, a nie przez hak ponownego połączenia.
sysctl net.ipv4.ip_forward
ip route add 10.64.20.0/24 via 172.28.44.2 dev transit0
ip route get 10.64.20.37
Odbij to na drugim hoście z zamienionymi pulami. Wielokrotne dodawanie tej samej trasy z niepowiązanego skryptu to sposób, w jaki host kończy z kilkoma kopiami i tajemniczą zmianą, gdy ktoś następnym razem czyta tablicę. Jeśli łącze tranzytowe samo jest tunelem, trasa wskazuje na topologię tego tunelu, a hop musi przetrwać jego ponowne połączenie. Adres tranzytowy, który znika na trzydzieści sekund, zabiera ze sobą ścieżkę między pulami, co jest właściwością projektu wartą ogłoszenia, a nie odkrycia.
Wypchnij trasę klienta bez udawania własności
Klienci potrzebują trasy do zdalnej puli, inaczej ich własny system operacyjny wyśle pakiet do domyślnej bramy i tunel nigdy go nie zobaczy. Konfiguracja serwera to naturalne miejsce, by ją dostarczyć.
push "route 10.64.20.0 255.255.255.0"
Umieść lustrzaną linię w konfiguracji drugiego serwera, następnie połącz ponownie klienta testowego i odczytaj jego tablicę. Klient, który ignoruje wypchnięte trasy, potrzebuje własnej zatwierdzonej konfiguracji, a trasa, która nigdy nie przychodzi, nie jest kontrolą dostępu. Nie dawaj klientowi iroute dla całej puli drugiej bramy. Ta dyrektywa istnieje dla podsieci za jednym połączonym klientem, a użycie jej do zakrycia brakującej trasy między bramami daje serwer, który wierzy, że posiada adresy, których nie może osiągnąć.
Udowodnij jedno żądanie i odmów drugiego
Wybierz realną operację, na przykład HTTPS od klienta na 10.64.10.21 do usługi na 10.64.20.37, i zezwól dokładnie na to na obu hostach. Każdy firewall przepuszcza żądanie po stronie wejściowej i śledzoną odpowiedź po stronie powrotnej; polityka samej usługi docelowej nadal musi je zaakceptować.
iptables -A FORWARD -i tun0 -o transit0 -s 10.64.10.21 -d 10.64.20.37 -p tcp --dport 443 -j ACCEPT
iptables -A FORWARD -i transit0 -o tun0 -d 10.64.10.21 -s 10.64.20.37 -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT
Przy wzajemnych trasach źródłowy NAT jest tu niepotrzebny i wręcz szkodliwy: tłumaczenie źródła ukrywa, który klient wysłał żądanie, i niweczy politykę opartą na źródle po stronie celu. Sprawdź, czy istniejąca reguła masquerade dla wyjścia do internetu nie łapie także tej ścieżki. Potem przetestuj odmowę. Usługa, która powinna pozostać lokalna w puli B, musi pozostać nieosiągalna z puli A, a pary klientów na tej samej bramie też trzeba przetestować, bo właśnie zmieniona polityka przekazywania dotyczy także ich.
Jeszcze jedna korekta modelu mentalnego: łącze tranzytowe przenosi odszyfrowane pakiety wewnętrzne, więc jest granicą zaufania, a nie prywatną gwarancją. Jeśli przecina sieć, której nie kontrolujesz, chroń ten hop zatwierdzonym szyfrowanym tunelem i trasuj przez jego rzeczywistą topologię. TLS od końca do końca nadal sam uwierzytelnia aplikację, dlatego usługa wewnętrzna powinna go dalej używać.