Nginx spredaj, zasebni backend za VPN
Brskalnik govori z Nginxom, Nginx pa odpre drugo povezavo v tunel. Usmeri obe, preveri oba certifikata in ohrani javne preusmeritve javne.
Sledi eni zahtevi s telefona na vlaku do backenda, ki obstaja samo v zasebnem omrežju. Telefon razreši javno ime, se poveže z javnim naslovom na vratih 443 in opravi običajno rokovanje TLS. Nginx to povezavo sprejme in nato odpre drugo, povsem ločeno, na naslov, ki ga doseže le prek vmesnika VPN. Na telefonu se nič ne spremeni in telefon nikoli ne izve, da je bil vpleten tunel.
Slediti eni zahtevi skozi dve povezavi
Vhodni krak je javna transakcija HTTP. Ima javno ime, javni certifikat in pot odgovora, ki mora delovati za kateri koli naslov, ki ga ima obiskovalec v tistem trenutku. Vsaka sprememba, ki to pot zmoti, zlomi vse obiskovalce hkrati. Zato je javni krak tisti, na katerem najmanj želiš eksperimentirati.
Izhodni krak je zaseben. Nginx postane odjemalec, razreši interno ime ali uporabi fiksni naslov in doseže storitev, ki bi povezavo iz interneta zavrnila.
Public client -> frontend public address:443 (TLS, public name)
Frontend -> VPN private backend 10.40.0.20:8443 (TLS, private name)
Drži ju ločeno v glavi in konfiguracija postane očitna. Združi ju in na koncu boš poskušal doseči, da javni odjemalec sodeluje v tunelu, in od tod prihaja večina zmede v tej zasnovi. Zasebni krak je lahko krhek. Javni ne.
Preden karkoli od tega zgradiš, potrdi, da je objava aplikacije namerna. Delujoč proxy je tudi delujoča izpostavitev, model preverjanja pristnosti pa mora biti odločitev in ne stranski učinek.
Ime prehoda mora preživeti tunel
V razreševanju imen se skriva subtilna past. Če zasebni DNS prepiše isto ime, ki ga profil VPN uporablja za svoj lastni prehod, lahko ponovna povezava na koncu poskuša doseči ta prehod skozi tunel, ki naj bi ga šele vzpostavila. Odjemalec potrebuje to ime razrešeno, preden tunel obstaja. Ko se razreši znotraj tunela, povezave ni več mogoče zgraditi.
Uporabi ločena odobrena imena za prehod in backend ter omej razreševalno politiko tako, da se vsako ime razreši na naslov, ki ga potrebuje njegov uporabnik. Spreminjanje glave Host v aplikaciji tu ne pomaga, ker poizvedbo opravi odjemalec VPN.
Nato pomisli na obseg. Vmesnik potrebuje pot do naslova backenda in mora tudi naprej odgovarjati javnim odjemalcem. Polni tunel na tem gostitelju lahko izpolni prvo zahtevo in zlomi drugo.
Kjer politika to dovoljuje, je tunel do določenega cilja čistejša zasnova. Kjer politika zahteva polni tunel, spada vmesnik v ločen omrežni kontekst, namesto da bi ga krpali z ad hoc potmi za znane obiskovalce.
Napisati strežniški blok tako, da oba kraka preverjata
Predpostavi, da backend predloži certifikat za backend.corp.example in odgovori na zasebnem naslovu. Povezovanje z naslovom ob preverjanju imena je točno tisto, čemur so namenjene možnosti SNI in imena v modulu proxy.
upstream private_app {
server 10.40.0.20:8443;
}
server {
listen 443 ssl;
server_name app.example.com;
ssl_certificate /etc/nginx/tls/app-fullchain.pem;
ssl_certificate_key /etc/nginx/tls/app-key.pem;
location / {
proxy_pass https://private_app;
proxy_ssl_server_name on;
proxy_ssl_name backend.corp.example;
proxy_ssl_trusted_certificate /etc/nginx/trust/backend-ca.pem;
proxy_ssl_verify on;
proxy_ssl_verify_depth 3;
proxy_set_header Host app.example.com;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Vsaka pot in naslov zgoraj je nadomestni znak. Pomembni so deli, ki ohranjajo preverjanje vklopljeno: ime za preverjanje, paket zaupanja, s katerim ga preveriti, in globina, ki ustreza odobreni verigi.
proxy_set_header Host app.example.com je namerno. Backend bi moral biti nastavljen tako, da sprejme ta javni izvor, in moral bi zaupati posredovanim glavam samo s tega vmesnika. Prepisovati X-Forwarded-For z naslovom odjemalca je pravilno za en proxy in napačno za verigo, zato uvedba z več proxyji potrebuje lastno ureditev zaupanja vrednih naslovov.
Poskrbeti, da se javni izvor obnaša kot javni
Aplikacija bi morala oddajati absolutne URL-je, preusmeritve in piškotke za javni izvor. Če obiskovalca preusmeri na backend.corp.example, je ta obiskovalec poslan na ime, ki ga ne more razrešiti.
Popravi to z nastavitvijo zunanjega URL-ja, ki jo aplikacija podpira, in pregledano politiko preusmerjanja, ne s prepisovanjem imen gostiteljev v telesih odgovorov. Zamenjava nizov v poljubni vsebini zlomi podpisane nosilne podatke in ustvari napake, ki jih je težko izslediti.
Piškotki si zaslužijo enako skrbnost. Piškotek, vezan na zasebno ime, brskalnik, ki pozna samo javno, ne bo nikoli poslal.
Potrdi tudi, da lahko Nginx resnično poseduje javno vtičnico. Obstoječa spletna storitev na 443 se mora premakniti ali pa mora vmesnik živeti drugje, ker dva procesa ne moreta vezati istega naslova in vrat.
Preveriti vsak krak tam, kjer dejansko teče
Preveri konfiguracijo z nameščenim razčlenjevalnikom pred vsakim ponovnim nalaganjem, da tipkarska napaka ne podre poslušalca, ki trenutno streže.
Nato preizkusi krak backenda z gostitelja vmesnika samega, v istem omrežnem kontekstu, kot ga uporablja Nginx. Ping skozi tunel dokaže dosegljivost in nič o TLS, avtorizaciji ali aplikaciji.
Nazadnje opravi svežo javno zahtevo na pravo ime gostitelja z običajnim preverjanjem certifikata in opazuj pot odgovora, ne le telesa.
Ohrani obe opažanji skupaj z nameščeno konfiguracijo in zapiši, kaj se zgodi, ko tunel ni na voljo. Vmesnik bi moral vrniti nadzorovano napako upstreama, ne pa tiho preklopiti na drug backend, ki ga nihče ni dokumentiral. 502 z jasno vrstico v dnevniku je dober izid. Predpomnjena stran z neželenega izvora ni.