Dvě jména DNS, jeden port OpenVPN: co skutečně vybírá
Dvě jména hostitelů mířící na jednu adresu stále dorazí k jednomu posluchači. Backend může vybrat jen pole, které klient pošle, a nativní OpenVPN neposílá žádné.
Dva záznamy A, jedna adresa, jeden démon: ať už uživatel napíše kterékoli jméno, doručený paket je totožný a proces vázaný na port 1194 nemá čím oba rozlišit. To není chybná konfigurace čekající na opravu; je to hranice toho, co umí vyjádřit vyhledávání podle jména. Cokoli, co vybírá mezi dvěma instancemi OpenVPN, musí být hodnota, kterou klient vloží do spojení a kterou frontend dokáže přečíst zpět, a běžný klient OpenVPN takovou hodnotu neposílá v otevřené podobě. Následuje, kam vás to dostane a která uspořádání provoz skutečně rozdělují.
Začněte tím, co resolver vrací
Klient se zeptá na vpn-a.example a dostane adresu; tato adresa plus port je vše, k čemu se připojuje. Jméno se spotřebuje lokálně při vyhledávání a nikdy se nestane polem na drátě, takže posluchač na druhém konci nemůže vidět, která značka byla použita. Namiřte vpn-a.example a vpn-b.example na jeden hostitel a obě vyhledávání dají stejné cílové místo, a proto démon obě spojení pohltí do jedné instance, aniž by zaznamenal rozdíl. Profily založené na adrese se chovají přesně jako profily založené na jménu, ze stejného důvodu.
Tím se také uzavírá rodina lákavých obejití: další aliasy, výběr certifikátu pro každé jméno na jednom socketu nebo pravidlo firewallu vázané na dotazované jméno. Žádné z nich nemůže jednat podle informace, která byla už zahozena předtím, než první paket opustil klienta. Pokud dva servery musí zůstat oddělené, rozdělení musí cestovat se samotným spojením, což znamená adresu, port nebo pole užitečného zatížení, které protokol definuje.
Jediný selektor, který se počítá, jede uvnitř paketu
HTTP to zvládá hlavičkou Host a TLS rozšířením o jméno serveru v ClientHello, a tak jedna adresa obsluhuje mnoho webů za jedním posluchačem. Obě fungují proto, že protokol na drátě nese požadavek na konkrétní službu. Podstatný fakt o OpenVPN je, že ani jedno z těchto polí není přítomno ve vrstvě, kterou prostřední box zkoumá.
V běžném uspořádání se TLS handshake chránící řídicí kanál odehrává po navázání vnější relace a je přenášen uvnitř ní, takže posluchač, který tuto relaci neukončil, vidí neprůhledný tok. Stále pozná, že jde o OpenVPN, protože opcode a rámování v úvodních bajtech jsou rozpoznatelné, ale jméno serveru, pokud existuje, sedí v šifrované části. Návrh, který očekává, že přečte virtuální hostitele z vnějšího paketu, čte pole, které tam protokol nikdy nezapisuje. To vyplývá z toho, jak je tunel postaven, ne z mezery, kterou by mohlo uzavřít chytřejší porovnávání vzorů.
Kde se rozdělovač protokolů zastaví
Multiplexor toho druhu, který dokumentuje projekt sslh, naslouchá na jednom portu, zkoumá úvodní bajty a předá spojení tomu backendu, který mluví rozpoznaným protokolem. To má skutečnou hodnotu, když jeden port musí obsloužit SSH, HTTPS a OpenVPN současně.
sslh drží samostatnou sondu pro každý protokol a jeho TLS sonda umí vytáhnout jméno serveru nebo hodnotu ALPN ze skutečného ClientHello. Rozpoznání nativního OpenVPN je jiná klasifikace než čtení rozšíření TLS a obojí se neskládá, protože klient, který nikdy nepošle ClientHello na naslouchající socket, nechává sondu bez čehokoli ke čtení. Pravidlo odpovídající OpenVPN proto odpoví „tohle je klient OpenVPN“ a dál nejde. Dva backendy OpenVPN za tímto pravidlem jsou nerozlišitelné, frontend nemá žádný základ pro volbu a každá relace skončí na stejném místě. Multiplexování sdílí jeden port mezi různými službami; neprovádí virtuální hosting uvnitř jedné služby.
Uspořádání, která dva servery opravdu oddělují
Nejlevnější poctivé rozdělení je druhá veřejná adresa, jedna na instanci, a stávající profily už nesou, co je potřeba, protože míří na různé adresy. Další je jiný port na stejné adrese, což nestojí nic než číslo v každém profilu. TCP a UDP drží oddělené tabulky portů, takže 1194/tcp a 1194/udp jsou nesouvisející sockety a jeden od každého může na jednom hostiteli existovat vedle sebe; to je oddělení transportu, ne směrování podle jména, a často se s ním plete. Obě možnosti projdou revizí firewallu, protože pravidlo odpovídá něčemu, co paket skutečně obsahuje.
Pokud hranice, kterou potřebujete, vede mezi skupinami uživatelů místo mezi dvěma implementacemi, může ji pokrýt jedna instance s odlišnými konfiguracemi klientů, vlastním zacházením s certifikáty a výslovnou přístupovou politikou. To kupuje politiku uvnitř serveru, ne izolaci mezi servery, a to jsou různé požadavky. Izolace, která musí vydržet i při kompromitaci, stále potřebuje adresu nebo okraj firewallu.
TLS terminátor postavený před OpenVPN může schopnému frontendu vystavit skutečné jméno serveru, ale jen tehdy, když je klientská strana také nakonfigurována pro tuto další vrstvu. Stávající profily toto chování nezískají tím, že se namíří na stejnou adresu.
Dokažte selektor, než začnete stavět
Pojmenujte pole, které bude identifikovat backend, a pak potvrďte, že ho klient skutečně posílá; pokud je odpovědí adresa, plán drží, a pokud jméno serveru uvnitř handshake, který se k posluchači nikdy nedostane, žádná práce s DNS to nezachrání. Tři příkazy rychle vyřeší stranu naslouchání.
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
Řádek openssl dá certifikát jen tam, kde něco na této adrese ukončuje TLS; proti nativnímu posluchači OpenVPN se zasekne nebo selže, což je samo o sobě odpověď na to, co vnější vrstva odhaluje. Řádek journal, přečtený na každém backendu, ukáže, která instance relaci přijala. Frontendové logy zaznamenávají, co bylo klasifikováno, a nikdy to, co bylo zamýšleno, takže backend zůstává jedinou autoritou v tom, kam uživatel přistál.
Skončete dvěma profily určenými k dosažení různých serverů, připojte je jeden po druhém a poznamenejte si log backendu pro každý. Pokud se obě relace objeví ve stejném žurnálu, selektor chybí, ne že by byl špatně nastavený, a opravou je adresa nebo port, který klient může cílit. Úprava směrovacího pravidla nepomůže, protože pravidlu nikdy nebylo dáno nic, podle čeho směrovat. Jakmile je rozdělení skutečné, napište ho vedle profilů, aby příští člověk nepřidal druhý alias a nečekal, že práci udělá on.