Două înregistrări A, o adresă, un daemon: indiferent ce nume tastează utilizatorul, pachetul care sosește este identic, iar procesul legat de portul 1194 nu are cu ce să le distingă. Aceasta nu este o configurație greșită care așteaptă reparare; este limita a ceea ce poate exprima o căutare de nume. Orice alege între două instanțe OpenVPN trebuie să fie o valoare pe care clientul o pune în conexiune și pe care frontendul o poate reciti, iar un client OpenVPN standard nu pune o astfel de valoare în clar. Urmează unde te lasă asta și ce aranjamente separă într-adevăr traficul.

Începe cu ce întoarce resolverul

Un client cere vpn-a.example și primește o adresă; acea adresă plus un port este tot ceea ce apelează. Numele este consumat local, în timpul căutării, și nu devine niciodată un câmp pe fir, așa că ascultătorul de la celălalt capăt nu poate vedea ce etichetă a fost folosită. Îndreaptă vpn-a.example și vpn-b.example spre aceeași gazdă și ambele căutări dau aceeași destinație, motiv pentru care daemonul absoarbe ambele conexiuni într-o singură instanță fără să înregistreze o diferență. Profilurile bazate pe adresă se comportă exact ca cele bazate pe nume, din același motiv.

Asta închide și o familie de soluții tentante: aliasuri suplimentare, alegerea unui certificat pentru fiecare nume pe un singur socket sau o regulă de firewall legată de numele interogat. Niciuna nu poate acționa pe informație care fusese deja aruncată înainte ca primul pachet să părăsească clientul. Dacă două servere trebuie să rămână separate, separarea trebuie să călătorească cu conexiunea însăși, adică o adresă, un port sau un câmp de încărcare utilă pe care protocolul îl definește.

Singurul selector care contează merge în interiorul pachetului

HTTP rezolvă asta cu un antet Host, iar TLS cu o extensie de nume de server în ClientHello, și astfel o adresă servește multe site-uri în spatele unui singur ascultător. Ambele funcționează pentru că protocolul de pe fir transportă o cerere pentru un serviciu anume. Faptul relevant despre OpenVPN este că niciunul dintre aceste câmpuri nu este prezent la nivelul pe care îl inspectează o cutie intermediară.

Într-un aranjament standard, strângerea de mână TLS care protejează canalul de control are loc după ce sesiunea exterioară este stabilită și este transportată în interiorul ei, așa că un ascultător care nu a terminat acea sesiune vede un flux opac. Poate totuși spune că este OpenVPN, pentru că opcode-ul și încadrarea din primii octeți sunt recognoscibile, dar numele de server, dacă există, stă în partea criptată. Un design care se așteaptă să citească o gazdă virtuală din pachetul exterior citește un câmp pe care protocolul nu îl scrie niciodată acolo. Asta vine din felul în care este construit tunelul, nu dintr-o lacună pe care o potrivire de tipar mai isteață ar putea-o închide.

Unde un separator de protocoale se oprește

Un multiplexor de genul celui documentat de proiectul sslh ascultă pe un port, inspectează primii octeți și predă conexiunea acelui backend care vorbește protocolul recunoscut. Aceasta este valoare reală când un singur port trebuie să servească împreună SSH, HTTPS și OpenVPN.

sslh ține o sondă separată pentru fiecare protocol, iar sonda sa TLS poate scoate un nume de server sau o valoare ALPN dintr-un ClientHello autentic. Recunoașterea OpenVPN nativ este o clasificare diferită de citirea unei extensii TLS, iar cele două nu se compun, pentru că un client care nu trimite niciodată un ClientHello către socketul de ascultare lasă sonda fără nimic de citit. De aceea o regulă care se potrivește cu OpenVPN răspunde „acesta este un client OpenVPN” și nu merge mai departe. Două backenduri OpenVPN în spatele acelei reguli sunt indistinguibile, frontendul nu are nicio bază pentru alegere, iar fiecare sesiune aterizează în același loc. Multiplexarea împarte un port între servicii diferite; nu face găzduire virtuală în interiorul unui serviciu.

Aranjamente care separă într-adevăr două servere

Cea mai ieftină separare cinstită este o a doua adresă publică, una pe instanță, iar profilurile existente poartă deja ce trebuie pentru că indică adrese diferite. Următoarea este un port diferit pe aceeași adresă, care nu costă nimic în afară de un număr în fiecare profil. TCP și UDP țin tabele de porturi separate, așa că 1194/tcp și 1194/udp sunt socketuri fără legătură și câte unul din fiecare poate coexista pe aceeași gazdă; asta este separare de transport, nu rutare după nume, și este adesea confundată cu ea. Ambele opțiuni trec de o revizuire de firewall, pentru că regula se potrivește cu ceva ce pachetul conține într-adevăr.

Dacă granița de care ai nevoie trece între grupuri de utilizatori și nu între două implementări, o instanță cu configurații de client distincte, propria gestionare a certificatelor și o politică de acces explicită o poate acoperi. Ce cumperi astfel este politică în interiorul unui server, nu izolare între servere, iar acestea sunt cerințe diferite. Izolarea care trebuie să reziste sub compromitere are în continuare nevoie de adresă sau de marginea firewallului.

Un terminator TLS plasat în fața OpenVPN poate expune un nume de server real unui frontend capabil, dar numai când și partea client este configurată pentru acel strat suplimentar. Profilurile existente nu dobândesc comportamentul doar fiind îndreptate spre aceeași adresă.

Dovedește selectorul înainte de a construi

Numește câmpul care va identifica un backend, apoi confirmă că clientul îl trimite într-adevăr; dacă răspunsul este o adresă, planul rezistă, iar dacă este un nume de server într-o strângere de mână care nu ajunge niciodată la ascultător, nicio cantitate de muncă DNS nu îl va salva. Trei comenzi lămuresc repede partea care ascultă.

ss -lntup | grep -E ':443|:1194'
openssl s_client -connect vpn-a.example:443 -servername vpn-a.example </dev/null | head -n 20
journalctl -u openvpn-server@server-a -n 20 --no-pager

Linia openssl dă un certificat doar acolo unde ceva de la acea adresă termină TLS; împotriva unui ascultător OpenVPN nativ se blochează sau eșuează, iar asta este în sine răspunsul despre ce expune stratul exterior. Linia journal, citită pe fiecare backend, arată ce instanță a acceptat sesiunea. Logurile frontendului consemnează ce a fost clasificat și niciodată ce era intenționat, așa că backendul rămâne singura autoritate cu privire la locul unde a aterizat un utilizator.

Încheie cu două profiluri menite să ajungă la servere diferite, conectează-le pe rând și notează logul backendului pentru fiecare. Dacă ambele sesiuni apar în același journal, selectorul lipsește, nu este configurat greșit, iar corectarea este o adresă sau un port pe care clientul îl poate viza. Editarea regulii de rutare nu va ajuta, pentru că regulii nu i s-a dat niciodată ceva pe care să ruteze. Odată ce separarea este reală, scrie-o lângă profiluri, ca următoarea persoană să nu adauge un al doilea alias și să se aștepte ca acela să facă treaba.

Articole similare