Zapora VPS: otwórz tylko port VPN, a potem to udowodnij
Jeden port musi pozostać publiczny, inaczej żaden klient się nie połączy. Odrzuć resztę, trzymaj przekazywanie osobno od wejścia i zostaw przetestowaną wcześniej ścieżkę odzyskiwania.
Zapora, która przepuszcza tylko port VPN, to nie jedna reguła. To trzy osobne decyzje, które przypadkiem dotyczą tego samego numeru portu: łańcuch wejściowy decyduje, co może dotrzeć do lokalnego procesu, łańcuch przekazywania decyduje, co może przejść przez hosta w imieniu klientów tunelu, a tabela NAT przepisuje adres źródłowy na wyjściu. Pomylisz jedną z nich, a wynik rzadko jest czystą awarią. Dostajesz hosta, który przyjmuje klientów, ale nic nie ładuje, albo hosta, który wygląda na zamknięty, dopóki ktoś nie przeczyta kolejności łańcuchów.
Jedyny port, którego nie można zamknąć
Nasłuch VPN musi przyjmować połączenia z adresów, których nie da się przewidzieć, więc z definicji jest usługą publiczną. To jedyny wyjątek, na którym opiera się projekt: jeden port UDP dla OpenVPN, jeden port UDP dla WireGuard, jeden port TCP dla VPN SSL. Wszystko inne należy za tunel, co oznacza, że usługi aplikacyjne powinny wiązać się z adresem tunelu albo z loopback, a nie ze wszystkimi interfejsami.
Wiązanie nie jest jednak egzekwowaniem. Proces związany z 0.0.0.0 jest osiągalny tylko wtedy, gdy reguła go przepuści, a polityka domyślna jest zapasem dla ruchu, którego nie dopasowała żadna reguła, nie regułą rządzącą portem. Akceptacja umieszczona nad twoim dropem nadal jest akceptacją, a przeniesienie usługi z adresu publicznego to niezależne ulepszenie, nie zamiennik łańcucha.
Wejście, przekazywanie i NAT odpowiadają na różne pytania
Ruch wejściowy jest adresowany do samego hosta, więc tam mieszkają nasłuch VPN i ścieżka administracyjna. Ruch przekazywania przechodzi przez hosta, a klienci tunelu potrzebują go razem z net.ipv4.ip_forward=1. Klasyczna na wpół zepsuta konfiguracja pozwala na przepływ wychodzący i zapomina o kierunku powrotnym, więc klient kończy uzgadnianie i potem nic się nie ładuje; reguła conntrack dla ruchu ustanowionego i powiązanego pokrywa ten kierunek.
NAT to trzecie pytanie. Bez przepisania w postroutingu przekazywane pakiety wychodzą z prywatnym źródłem tunelu i są odrzucane wyżej, bo żadna sieć poza hostem nie wie, jak skierować pulę z powrotem. Prefiks źródłowy w tej regule musi pasować do puli VPN, a nie do własnego adresu hosta, i to samo dotyczy reguły przekazywania, która nazywa podsieć klientów.
IPv6 to druga polityka, nie myśl po fakcie. Host z surowym łańcuchem IPv4 i otwartą polityką na ip6tables niczego nie zamknął; usługi wciąż są osiągalne przez drugą rodzinę. Albo odwzoruj zestaw reguł za pomocą ip6tables, albo świadomie wyłącz IPv6 na publicznym interfejsie, i zapisz, co wybrałeś.
Linia bazowa do przeczytania w jednym przejściu
Zacznij od odrzucania, a potem dodawaj tylko to, czego host potrzebuje. Najpierw loopback i odpowiedzi, potem ścieżka administracyjna, potem nasłuch tunelu, potem polityka przekazywania dla klientów:
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p udp --dport 1194 -m conntrack --ctstate NEW -j ACCEPT
sysctl -w net.ipv4.ip_forward=1
iptables -A FORWARD -i tun0 -o eth0 -s 10.8.0.0/24 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADENazwy interfejsów, port i pula to miejsca zastępcze; czytaj je z serwera zamiast kopiować. Zapisanie wyniku jest tak samo ważne jak jego napisanie, bo zestaw reguł żyjący tylko w pamięci znika przy następnym restarcie i po cichu otwiera hosta ponownie. Uczyń go trwałym mechanizmem dystrybucji i trzymaj kopię poza maszyną na dzień, w którym maszyna nie wystartuje.
Zamknięcie ostatniego portu bez utraty hosta
W projekcie jest haczyk. Jeśli SSH istnieje tylko przez tunel, awaria usługi VPN zabiera ze sobą SSH, a jedyną drogą powrotu może być konsola, której nigdy nie otworzyłeś. Zanim zamkniesz ostatni publiczny port, potwierdź, że ta konsola istnieje i że naprawdę możesz jej użyć, albo zostaw jedną wąską ścieżkę administracyjną niezależną od tunelu: SSH ze stałego adresu, tylko klucze, uwierzytelnianie hasłem wyłączone.
Zastosuj zmianę z już ustanowionej sesji, a nie przez połączenie, które zamierzasz filtrować. Zaplanuj wycofanie, aby błąd wygasł, zamiast stać się trwały, na przykład zadanie systemd-run --on-active=10min, które przywraca poprzedni zestaw reguł, i trzymaj otwartą drugą sesję SSH, gdy testujesz pierwszą. Potem sprawdź, czy zadanie wycofania naprawdę się uruchamia, bo niesprawdzone odzyskiwanie to to samo co brak odzyskiwania.
Sprawdź ścieżkę, nie skrypt
Czytaj wczytane reguły, a nie plik, który miał je wczytać. Z upoważnionego hosta zewnętrznego potwierdź, że odpowiadają tylko zamierzone porty; z wnętrza tunelu potwierdź, że usługi, które chciałeś opublikować, są osiągalne. Domyślna polityka odrzucania, która blokuje też ruch tunelu, wygląda identycznie jak działająca blokada, dopóki ktoś nie spróbuje jej użyć.
iptables -S
iptables -t nat -S
ss -lntup
ip -4 addr showZapisz dozwolony port, pulę klientów, interfejs tunelu, źródło administracyjne i procedurę konsoli obok konfiguracji. Następna zmiana puli albo nazwy interfejsu musi zostać odzwierciedlona zarówno w filtrze, jak i w regule NAT, inaczej host wróci do na wpół otwartego stanu, a nikt tego nie zauważy.
Jeden nawyk jest wart więcej niż zestaw reguł: po każdej zmianie udowodnij ścieżkę przekazywania żądaniem klienta, a ścieżkę odzyskiwania drugą sesją. Blokada, której nie użyłeś, to tylko hipoteza.