Dostęp do usługi na kliencie VPN: tunel odwrotny czy DNAT
Dostęp do usługi na kliencie OpenVPN bez przekierowania portu: porównaj tunel odwrotny SSH z DNAT po stronie serwera i trzy warunki, które decydują o wyborze.
Nawet laptop za NAT-em operatora może obsłużyć kolegę, jeśli serwer VPN pełni rolę miejsca spotkania. Prowadzą tam dwa mechanizmy: klient łączy się na zewnątrz i prosi serwer o utrzymanie portu nasłuchu, albo serwer publikuje port i tłumaczy go do tunelu. Oba rozwiązują ten sam problem osiągalności i zachowują się różnie przy awarii, nadzorze i logowaniu. Trzy warunki decydują, który pasuje do twojej konfiguracji.
Dwa kształty, jedno miejsce spotkania
W pierwszym kształcie klient otwiera sesję SSH na zewnątrz i prosi serwer o nasłuch na wybranym porcie, przekazując każde połączenie z powrotem przez tę sesję. Na serwerze nic nie jest przekazywane i nie zachodzi tłumaczenie pakietów, więc jedyne wymagania to konto SSH, dozwolone przekierowanie i reguła zapory dla portu. Usługa pozostaje przypięta do loopbacku na kliencie, co zwykle jest tym, czego chcesz.
ssh -N -R 8081:127.0.0.1:8080 -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 [email protected]
W drugim kształcie serwer posiada publiczny port i przepisuje każde połączenie w stronę adresu tunelu klienta. Wymaga to włączonego przekazywania IP, tłumaczenia celu na wejściu i tłumaczenia źródła na wyjściu, i działa dalej, gdy nie istnieje żadna sesja SSH. Port należy do serwera, a nie do sesji, i to ta właściwość rozstrzyga większość rzeczywistych przypadków.
Żaden z kształtów nie jest z natury bezpieczniejszy. Oba wystawiają jeden port usługi każdemu, kto może dotrzeć do publicznego adresu serwera, i oba nadal zależą od własnego uwierzytelniania usługi.
Warunek pierwszy: czy port musi przeżyć sesję
Przekierowanie odwrotne żyje dokładnie tyle, ile sesja SSH, która je utworzyła. Gdy łącze padnie, nasłuch znika, a kolega widzi odrzucone połączenie zamiast wolnej ścieżki. Nadzór nad poleceniem za pomocą jednostki systemd i polityki restartu to naprawia, a ExitOnForwardFailure=yes czyni nieudane przypięcie natychmiast widocznym, zamiast zostawiać sesję działającą bez przekierowania.
Przetłumaczony port przeżywa restarty, jeśli reguły są utrwalone, ale zależy od tego, czy klient zachowa ten sam adres tunelu. Dynamiczna pula, która po ponownym połączeniu daje laptopowi inny adres, po cichu kieruje regułę donikąd. Najpierw zarezerwuj adres tunelu, potem napisz regułę, i traktuj oba jako jedną zmianę.
Jeśli usługa musi odpowiadać o trzeciej nad ranem bez nikogo, kto by patrzył, kształt z portem publikowanym przez serwer ma mniej ruchomych części, bo jedynym procesem, który musi pozostać uruchomiony, jest sam tunel.
Warunek drugi: do kogo należą zapora i logi
Kształt odwrotny trzyma całą politykę w dwóch miejscach. sshd decyduje przez AllowTcpForwarding, czy zdalne przekierowania są w ogóle dozwolone, a GatewayPorts decyduje, czy nasłuch wiąże się z loopbackiem, czy z każdym adresem. Przy domyślnej wartości no kolega spoza serwera nie dotrze do portu, mimo że przekierowanie się powiodło, i wygląda to na zepsuty tunel, gdy w rzeczywistości to adres przypięcia.
sudo ss -ltn '( sport = :8081 )'
sudo grep -E '^(GatewayPorts|AllowTcpForwarding)' /etc/ssh/sshd_config
Kształt przetłumaczony wymaga włączonego przekazywania i dwóch reguł, a druga reguła to miejsce, w którym większość przepisów się myli. Ograniczenie tłumaczenia źródła do stanu conntrack DNAT oznacza, że przepisywane są tylko połączenia utworzone przez regułę celu, a nie każdy pakiet, który serwer wysyła do tunelu.
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8081 -j DNAT --to-destination 10.88.0.6:8080
sudo iptables -t nat -A POSTROUTING -o tun0 -m conntrack --ctstate DNAT -j SNAT --to-source 10.88.0.1
To przepisanie niszczy też przypisanie. Potem klient widzi każdego wywołującego jako adres tunelu serwera, co zwija każdy limit szybkości na adres do jednego wiadra i ukrywa, kto co wysłał. Jeśli przypisanie ma znaczenie, zakończ połączenie na serwerze albo zostaw tam decyzję o zgodzie i przekaż tożsamość w nagłówku, któremu usługa ufa. Wybór między tymi dwiema poprawkami zależy od tego, czy usługa w ogóle czyta nagłówek proxy.
Warunek trzeci: jeden port czy wiele, i do kogo należy nazwa
Jedna usługa na jednym porcie to przypadek, w którym przekierowanie odwrotne wygrywa nakładem pracy. Potrzebujesz jednego polecenia, jednego konta i jednej reguły zapory, a sprzątaniem jest zabicie sesji. Wiele usług na tym samym publicznym adresie popycha cię w stronę kształtu publikowanego przez serwer, bo każde przekierowanie odwrotne potrzebuje własnego portu serwera, a zbiór rośnie z każdą usługą.
Nazwy dodatkowo to komplikują. Przekierowanie odwrotne może stać za proxy TCP, które kieruje według SNI, podczas gdy przetłumaczony port to zwykle jeden port na usługę. Jeśli usługa sama kończy TLS i potrzebuje oryginalnej nazwy hosta, podejście z proxy ją zachowuje, a podejście DNAT zachowuje ją tylko wtedy, gdy usługa akceptuje tę nazwę na tym porcie.
Zapisz, który z trzech warunków zdecydował o kształcie. Inaczej następna osoba dodająca drugą usługę otworzy to samo porównanie z mniejszym kontekstem.
Zdecyduj, a potem testuj z zewnątrz
Testuj ścieżkę z sieci, która nie ma żadnej trasy do laptopa, i obserwuj liczniki na serwerze, gdy żądanie trwa. Testowanie z serwera na jego własny publiczny adres nic tu nie dowodzi, bo pakiet powstaje lokalnie i nigdy nie dociera do haka tłumaczenia wejściowego, więc test może przejść, gdy prawdziwa ścieżka jest zepsuta.
sudo iptables -t nat -L PREROUTING -n -v
sudo tcpdump -ni any 'tcp port 8081' -c 20
Liczniki, które stoją w miejscu, oznaczają, że pakiet nigdy nie dotarł do reguły, co wskazuje na dostawcę lub zaporę hosta. Liczniki, które się poruszają, gdy usługa odmawia, wskazują na własną zaporę klienta lub adres, na którym usługa nasłuchuje. Tunel, który przenosi pakiet, ale nic nie zwraca, to problem trasy lub ścieżki powrotnej, i żadnego z tych trzech wyników nie należy diagnozować przez edycję adaptera klienta. Zapisz, który licznik się przesunął, zanim cokolwiek zmienisz, bo następny test potrzebuje tej linii bazowej.
Gdy kształt zadziała, zapisz port, właściciela i metodę nadzoru obok konfiguracji tunelu. Poprawka osiągalności, która istnieje tylko w czyjejś historii powłoki, jest o jedno uruchomienie od powtórnego incydentu.