Prati jedan zahtjev od telefona u vlaku do backenda koji postoji samo unutar privatne mreže. Telefon razrješava javno ime, spaja se na javnu adresu na portu 443 i dovršava uobičajeni TLS rukovanje. Nginx prihvaća tu vezu i zatim otvara drugu, potpuno odvojenu, prema adresi do koje dolazi samo kroz VPN sučelje. Ništa se na telefonu ne mijenja i telefon nikada ne sazna da je tunel bio uključen.

Pratiti jedan zahtjev kroz dvije veze

Dolazni krak je javna HTTP transakcija. Ima javno ime, javni certifikat i povratni put koji mora raditi za bilo koju adresu koju posjetitelj upravo ima. Svaka promjena koja poremeti taj put odjednom kvari sve posjetitelje. Zato je javni krak onaj na kojem najmanje želiš eksperimentirati.

Odlazni krak je privatni. Nginx postaje klijent, razrješava interno ime ili koristi fiksnu adresu i dolazi do usluge koja bi odbila vezu iz interneta.

Public client  -> frontend public address:443   (TLS, public name)
Frontend       -> VPN private backend 10.40.0.20:8443  (TLS, private name)

Drži ih odvojeno u glavi i konfiguracija postaje očita. Spoji ih i na kraju ćeš pokušavati natjerati javnog klijenta da sudjeluje u tunelu, a odatle dolazi većina zabune u ovom dizajnu. Privatni krak smije biti krhak. Javni ne.

Prije nego što bilo što od toga izgradiš, potvrdi da je objavljivanje aplikacije namjerno. Proxy koji radi ujedno je i izlaganje koje radi, a model autentifikacije mora biti odluka, a ne nuspojava.

Ime pristupnika mora preživjeti tunel

U razrješavanju imena leži suptilna zamka. Ako privatni DNS prepiše isto ime koje VPN profil koristi za vlastiti pristupnik, ponovno povezivanje može na kraju pokušati dosegnuti taj pristupnik kroz tunel koji tek treba uspostaviti. Klijent treba to ime razriješeno prije nego tunel postoji. Kad se razriješi unutar tunela, veza se više nikada ne može uspostaviti.

Koristi različita odobrena imena za pristupnik i backend te ograniči politiku razrješivača tako da se svako ime razriješi na adresu koja treba njegovu korisniku. Mijenjanje Host zaglavlja aplikacije ovdje ne pomaže jer pretragu obavlja VPN klijent.

Zatim razmisli o dosegu. Frontend treba rutu do adrese backenda i mora nastaviti odgovarati javnim klijentima. Puni tunel na tom hostu može zadovoljiti prvi uvjet i slomiti drugi.

Gdje politika to dopušta, tunel do određenog odredišta je čišći dizajn. Gdje politika zahtijeva puni tunel, frontend pripada zasebnom mrežnom kontekstu umjesto da se krpa ad hoc rutama za poznate posjetitelje.

Napisati blok poslužitelja tako da oba kraka provjeravaju

Pretpostavi da backend predstavlja certifikat za backend.corp.example i odgovara na privatnoj adresi. Povezivanje s adresom uz provjeru imena upravo je ono čemu služe SNI i imenske opcije modula 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;
    }
}

Svaki put i adresa gore je zamjenski znak. Važni su dijelovi koji drže provjeru uključenom: ime koje treba provjeriti, paket povjerenja prema kojem ga provjeriti i dubina koja odgovara odobrenom lancu.

proxy_set_header Host app.example.com je namjerno. Backend bi trebao biti konfiguriran da prihvati to javno podrijetlo i trebao bi vjerovati proslijeđenim zaglavljima samo od ovog frontenda. Prepisivanje X-Forwarded-For adresom klijenta ispravno je za jedan proxy, a pogrešno za lanac, pa implementacija s više proxyja treba vlastito uređenje pouzdanih adresa.

Natjerati javno podrijetlo da se ponaša kao takvo

Aplikacija bi trebala ispisivati apsolutne URL-ove, preusmjeravanja i kolačiće za javno podrijetlo. Ako posjetitelja preusmjeri na backend.corp.example, taj posjetitelj odlazi na ime koje ne može razriješiti.

Ispravi to kroz podržanu postavku vanjskog URL-a u aplikaciji i pregledanu politiku preusmjeravanja, a ne prepisivanjem imena hostova u tijelima odgovora. Zamjena nizova u proizvoljnom sadržaju kvari potpisane korisne terete i stvara pogreške koje je teško pratiti.

Kolačići zaslužuju istu pažnju. Kolačić ograničen na privatno ime nikada neće poslati preglednik koji poznaje samo javno.

Potvrdi i da Nginx može doista posjedovati javni socket. Postojeća web usluga na 443 mora se premjestiti ili frontend mora živjeti negdje drugdje, jer dva procesa ne mogu vezati istu adresu i isti port.

Provjeriti svaki krak tamo gdje se doista izvršava

Validiraj konfiguraciju instaliranim parserom prije svakog ponovnog učitavanja, da tipfeler ne sruši slušatelja koji upravo poslužuje.

Zatim testiraj krak backenda s hosta frontenda samog, u istom mrežnom kontekstu koji koristi Nginx. Ping kroz tunel dokazuje dostupnost i ništa o TLS-u, autorizaciji ili aplikaciji.

Na kraju uputi svježi javni zahtjev na stvarno ime hosta s normalnom provjerom certifikata i promatraj povratni put, a ne samo tijelo odgovora.

Sačuvaj oba opažanja uz implementiranu konfiguraciju i zapiši što se događa kad tunel nije dostupan. Frontend bi trebao vratiti kontroliranu upstream pogrešku, a ne tiho prijeći na drugi backend koji nitko nije dokumentirao. 502 s jasnom linijom u dnevniku dobar je ishod. Predmemorirana stranica s neželjenog podrijetla nije.

Povezani članci