Firewall pe VPS: deschide doar portul VPN, apoi dovedește-o
Un port trebuie să rămână public, altfel niciun client nu se conectează. Respinge restul, ține redirecționarea separată de intrare și lasă o cale de recuperare pe care ai testat-o dinainte.
Un firewall care permite doar portul VPN nu este o singură regulă. Sunt trei decizii separate care, din întâmplare, privesc același număr de port: lanțul de intrare decide ce poate ajunge la un proces local, lanțul de redirecționare decide ce poate trece prin gazdă în numele clienților tunelului, iar tabela NAT rescrie adresa sursă la ieșire. Greșești una dintre ele și rezultatul este rareori o întrerupere curată. Obții o gazdă care acceptă clienți dar nu încarcă nimic, sau o gazdă care pare închisă până când cineva citește ordinea lanțurilor.
Singurul port care nu poate fi închis
Ascultătorul VPN trebuie să accepte conexiuni de la adrese pe care nu le poți prevedea, deci este prin definiție un serviciu public. Aceasta este singura excepție pe care este construit designul: un port UDP pentru OpenVPN, un port UDP pentru WireGuard, un port TCP pentru un VPN SSL. Tot restul aparține în spatele tunelului, ceea ce înseamnă că serviciile aplicațiilor ar trebui să se lege de adresa tunelului sau de loopback, nu de toate interfețele.
Legarea, însă, nu este aplicare. Un proces legat de 0.0.0.0 este accesibil doar dacă o regulă îl permite, iar politica implicită este rezerva pentru traficul pe care nicio regulă nu l-a prins, nu regula care guvernează portul. O acceptare plasată deasupra respingerii tale rămâne o acceptare, iar mutarea unui serviciu de pe adresa publică este o îmbunătățire independentă, nu un substitut pentru lanț.
Intrarea, redirecționarea și NAT răspund la întrebări diferite
Traficul de intrare este destinat gazdei înseși, așa că acolo locuiesc ascultătorul VPN și calea administrativă. Traficul de redirecționare trece prin gazdă, iar clienții tunelului au nevoie de el împreună cu net.ipv4.ip_forward=1. Configurația clasică pe jumătate stricată permite fluxul de ieșire și uită direcția de retur, așa că clientul încheie negocierea și apoi nu se încarcă nimic; o regulă conntrack pentru traficul stabilit și înrudit acoperă acea direcție.
NAT este a treia întrebare. Fără rescriere în postrouting, pachetele redirecționate pleacă cu sursa privată a tunelului și sunt aruncate mai sus, pentru că nicio rețea dincolo de gazdă nu știe să ruteze pool-ul înapoi. Prefixul sursă din acea regulă trebuie să corespundă pool-ului VPN, nu adresei proprii a gazdei, și același lucru este valabil pentru regula de redirecționare care numește subrețeaua clienților.
IPv6 este o a doua politică, nu o idee ulterioară. O gazdă cu lanț IPv4 strict și politică deschisă pe ip6tables nu a închis nimic; serviciile rămân accesibile prin cealaltă familie. Fie oglindești setul de reguli cu ip6tables, fie dezactivezi IPv6 intenționat pe interfața publică, și notezi pe care ai ales-o.
O bază care se citește dintr-o singură trecere
Începe cu respingerea, apoi adaugă doar ce are nevoie gazda. Întâi loopback și răspunsuri, apoi calea administrativă, apoi ascultătorul tunelului, apoi politica de redirecționare pentru clienți:
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 MASQUERADENumele interfețelor, portul și pool-ul sunt substituenți; citește-le de pe server în loc să le copiezi. Salvarea rezultatului este la fel de importantă ca scrierea lui, pentru că un set de reguli care trăiește doar în memorie dispare la următoarea repornire și redeschide gazda în liniște. Fă-l persistent cu mecanismul distribuției și păstrează o copie în afara mașinii pentru ziua în care mașina nu va porni.
Închiderea ultimului port fără a pierde gazda
Există o capcană în design. Dacă SSH există doar prin tunel, un serviciu VPN căzut ia SSH cu el, iar singura cale de întoarcere poate fi o consolă pe care nu ai deschis-o niciodată. Înainte să închizi ultimul port public, confirmă că acea consolă există și că o poți folosi cu adevărat, sau păstrează o cale administrativă îngustă care nu depinde de tunel: SSH de la o adresă fixă, doar chei, autentificare prin parolă oprită.
Aplică schimbarea dintr-o sesiune deja stabilită, nu prin conexiunea pe care urmează să o filtrezi. Programează o revenire ca o greșeală să expire în loc să devină permanentă, de exemplu o sarcină systemd-run --on-active=10min care restaurează setul anterior de reguli, și ține o a doua sesiune SSH deschisă cât timp o testezi pe prima. Apoi verifică dacă sarcina de revenire chiar se declanșează, pentru că o recuperare netestată este același lucru cu nicio recuperare.
Verifică traseul, nu scriptul
Citește regulile încărcate, nu fișierul care ar fi trebuit să le încarce. De pe o gazdă externă autorizată, confirmă că răspund doar porturile prevăzute; din interiorul tunelului, confirmă că serviciile pe care voiai să le publici sunt accesibile. O politică implicită de respingere care blochează și traficul tunelului arată identic cu o blocare funcțională până când cineva încearcă să o folosească.
iptables -S
iptables -t nat -S
ss -lntup
ip -4 addr showNotează portul permis, pool-ul de clienți, interfața tunelului, sursa administrativă și procedura de consolă lângă configurație. Următoarea modificare a pool-ului sau a numelui interfeței trebuie reflectată atât în filtru, cât și în regula NAT, altfel gazda revine la o stare pe jumătate deschisă fără ca nimeni să observe.
Un obicei valorează mai mult decât setul de reguli: după fiecare modificare, dovedește calea de redirecționare cu o cerere de la client și calea de recuperare cu o a doua sesiune. O blocare pe care nu ai folosit-o este doar o ipoteză.