Ajunge la un serviciu pe un client VPN: tunel invers sau DNAT
Ajunge la un serviciu pe un client OpenVPN fără redirecționare de port: compară un tunel SSH invers cu DNAT pe server și cele trei condiții care aleg unul.
Chiar și un laptop aflat în spatele NAT-ului operatorului poate servi un coleg, atât timp cât serverul VPN acționează ca punct de întâlnire. Două mecanisme ajung acolo: clientul se conectează spre exterior și cere serverului să țină un port de ascultare, sau serverul publică un port și îl traduce în tunel. Ambele rezolvă aceeași problemă de accesibilitate și se comportă diferit la defecțiune, supraveghere și jurnalizare. Trei condiții decid care se potrivește configurației tale.
Două forme, un punct de întâlnire
În prima formă clientul deschide o sesiune SSH spre exterior și cere serverului să asculte pe un port ales, trimițând fiecare conexiune înapoi prin acea sesiune. Pe server nu se redirecționează nimic și nu are loc nicio traducere de pachete, așa că singurele cerințe sunt un cont SSH, o redirecționare permisă și o regulă de firewall pentru port. Serviciul rămâne legat de loopback pe client, ceea ce de obicei este ceea ce vrei.
ssh -N -R 8081:127.0.0.1:8080 -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 [email protected]
În a doua formă serverul deține portul public și rescrie fiecare conexiune spre adresa tunelului clientului. Asta cere redirecționare IP activată, o traducere de destinație la intrare și o traducere de sursă la ieșire, și continuă să funcționeze când nu există nicio sesiune SSH. Portul aparține serverului, nu unei sesiuni, și această proprietate decide majoritatea cazurilor reale.
Niciuna dintre forme nu este mai sigură prin construcție. Ambele ajung să expună un port de serviciu oricui poate ajunge la adresa publică a serverului, și ambele depind în continuare de autentificarea serviciului însuși.
Condiția unu: trebuie portul să supraviețuiască sesiunii
O redirecționare inversă trăiește exact cât sesiunea SSH care a creat-o. Când legătura cade, ascultătorul dispare și colegul vede o conexiune refuzată în loc de o cale lentă. Supravegherea comenzii cu o unitate systemd și o politică de repornire rezolvă asta, iar ExitOnForwardFailure=yes face imediat vizibilă o legare eșuată în loc să lase o sesiune care rulează fără redirecționare.
Un port tradus supraviețuiește repornirilor dacă regulile sunt persistate, dar depinde de client să păstreze aceeași adresă de tunel. Un pool dinamic care îi dă laptopului altă adresă după reconectare îndreaptă regula în tăcere spre nimic. Rezervă mai întâi adresa tunelului, apoi scrie regula, și tratează ambele ca o singură schimbare.
Dacă serviciul trebuie să răspundă la trei dimineața fără nimeni care să privească, forma cu portul publicat de server are mai puține piese mobile, pentru că singurul proces care trebuie să rămână în funcțiune este tunelul însuși.
Condiția doi: cui aparțin firewallul și jurnalele
Forma inversă ține toată politica în două locuri. sshd decide prin AllowTcpForwarding dacă redirecționările la distanță sunt permise deloc, iar GatewayPorts decide dacă ascultătorul se leagă de loopback sau de fiecare adresă. Cu valoarea implicită no un coleg din afara serverului nu poate ajunge la port chiar dacă redirecționarea a reușit, și asta arată ca un tunel stricat când de fapt este o adresă de legare.
sudo ss -ltn '( sport = :8081 )'
sudo grep -E '^(GatewayPorts|AllowTcpForwarding)' /etc/ssh/sshd_config
Forma tradusă cere redirecționare activată și două reguli, iar a doua regulă este locul unde majoritatea rețetelor greșesc. Limitarea traducerii de sursă la starea conntrack DNAT înseamnă că sunt rescrise doar conexiunile create de regula de destinație, nu fiecare pachet pe care serverul îl trimite în tunel.
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
Rescrierea aceea distruge și atribuirea. După ea clientul vede fiecare apelant ca adresa tunelului serverului, ceea ce prăbușește orice limită de rată pe adresă într-o singură găleată și ascunde cine a trimis ce. Dacă atribuirea contează, termină conexiunea pe server sau păstrează acolo decizia de permisiune și transmite o identitate într-un antet în care serviciul are încredere. Alegerea între aceste două corecturi depinde de dacă serviciul citește deloc un antet de proxy.
Condiția trei: un port sau multe, și cui aparține numele
Un singur serviciu pe un singur port este cazul în care redirecționarea inversă câștigă la efort. Ai nevoie de o comandă, un cont și o regulă de firewall, iar curățarea este oprirea sesiunii. Mai multe servicii pe aceeași adresă publică te împing spre forma publicată de server, pentru că fiecare redirecționare inversă are nevoie de propriul port de server și mulțimea crește cu fiecare serviciu.
Numele complică lucrurile. O redirecționare inversă poate sta în spatele unui proxy TCP care rutează după SNI, în timp ce un port tradus este de obicei un port pe serviciu. Dacă serviciul termină singur TLS și are nevoie de numele de gazdă original, abordarea cu proxy îl păstrează, iar abordarea DNAT îl păstrează doar dacă serviciul acceptă acel nume pe acel port.
Notează care dintre cele trei condiții a decis forma. Altfel următoarea persoană care adaugă un al doilea serviciu va redeschide aceeași comparație cu mai puțin context.
Decide, apoi testează din exterior
Testează calea dintr-o rețea care nu are nicio rută către laptop, și urmărește contoarele de pe server cât timp cererea rulează. Testarea de pe server către propria adresă publică nu demonstrează nimic aici, pentru că pachetul este creat local și nu ajunge niciodată la cârligul de traducere de intrare, așa că testul poate trece în timp ce calea reală este stricată.
sudo iptables -t nat -L PREROUTING -n -v
sudo tcpdump -ni any 'tcp port 8081' -c 20
Contoarele care rămân plate înseamnă că pachetul nu a ajuns niciodată la regulă, ceea ce indică furnizorul sau firewallul gazdei. Contoarele care se mișcă în timp ce serviciul refuză indică firewallul propriu al clientului sau adresa pe care serviciul ascultă. Un tunel care transportă pachetul dar nu întoarce nimic este o problemă de rută sau de cale inversă, și niciunul dintre aceste trei rezultate nu ar trebui depanat editând adaptorul clientului. Notează care contor s-a mișcat înainte de a schimba ceva, pentru că testul următor are nevoie de acea linie de bază.
Când forma funcționează, notează portul, proprietarul și metoda de supraveghere lângă configurația tunelului. O corectură de accesibilitate care există doar în istoricul de shell al cuiva este la o repornire de un incident repetat.