Sleduj jednu požiadavku z telefónu vo vlaku až k backendu, ktorý existuje len v privátnej sieti. Telefón preloží verejné meno, pripojí sa k verejnej adrese na porte 443 a dokončí bežný TLS handshake. Nginx to spojenie prijme a potom otvorí druhé, úplne oddelené, k adrese, ktorú dosiahne len cez sieťové rozhranie VPN. Na telefóne sa nič nemení a telefón sa nikdy nedozvie, že v tom bol tunel.

Sledovať jednu požiadavku cez dve spojenia

Vstupný úsek je verejná transakcia HTTP. Má verejné meno, verejný certifikát a cestu odpovede, ktorá musí fungovať pre akúkoľvek adresu, ktorú návštevník práve má. Akákoľvek zmena, ktorá túto cestu naruší, rozbije všetkých návštevníkov naraz. Preto je verejný úsek ten, na ktorom chceš experimentovať najmenej.

Výstupný úsek je privátny. Nginx sa stane klientom, preloží interné meno alebo použije pevnú adresu a dosiahne službu, ktorá by spojenie z internetu odmietla.

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

Drž ich v hlave oddelené a konfigurácia sa stane samozrejmou. Zlej ich a skončíš tým, že sa snažíš prinútiť verejného klienta zúčastniť sa tunela, a odtiaľ pochádza väčšina zmätku v tomto návrhu. Privátny úsek môže byť krehký. Verejný nie.

Skôr než čokoľvek z toho postavíš, potvrď, že zverejnenie aplikácie je zamýšľané. Fungujúci proxy je aj fungujúce vystavenie a model autentifikácie musí byť rozhodnutie, nie vedľajší efekt.

Meno brány musí tunel prežiť

V preklade mien je nenápadná pasca. Ak privátny DNS prepíše to isté meno, ktoré profil VPN používa pre svoju vlastnú bránu, opätovné pripojenie môže nakoniec skúšať dosiahnuť tú bránu tunelom, ktorý má sám vytvoriť. Klient potrebuje toto meno preložené skôr, než tunel existuje. Keď sa preloží vo vnútri tunela, spojenie už nemožno vôbec zostaviť.

Použi odlišné schválené mená pre bránu a backend a obmedz politiku resolvera tak, aby každé meno preložilo na adresu, ktorú jeho používateľ potrebuje. Zmena hlavičky Host aplikácie tu nepomôže, pretože dopyt robí klient VPN.

Potom mysli na rozsah. Frontend potrebuje trasu k adrese backendu a tiež musí ďalej odpovedať verejným klientom. Plný tunel na tomto hostiteľovi môže splniť prvú požiadavku a rozbiť druhú.

Kde to politika dovoľuje, je tunel ku konkrétnemu cieľu čistejší návrh. Kde politika nariaďuje plný tunel, patrí frontend do samostatného sieťového kontextu, namiesto aby bol flikovaný ad hoc trasami pre známych návštevníkov.

Napísať blok servera tak, aby oba úseky overovali

Predpokladaj, že backend predkladá certifikát pre backend.corp.example a odpovedá na privátnej adrese. Pripájať sa k adrese a pritom overovať meno je presne to, na čo slúžia voľby SNI a mena v module 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;
    }
}

Každá cesta a adresa vyššie je zástupný symbol. Dôležité sú časti, ktoré držia overovanie zapnuté: meno na kontrolu, zväzok dôvery, proti ktorému ho kontrolovať, a hĺbka zodpovedajúca schválenému reťazu.

proxy_set_header Host app.example.com je zámerné. Backend by mal byť nastavený tak, aby prijímal tento verejný pôvod, a mal by dôverovať odovzdávaným hlavičkám len z tohto frontendu. Prepisovať X-Forwarded-For adresou klienta je správne pre jediný proxy a nesprávne pre reťaz, takže nasadenie s viacerými proxy potrebuje vlastné usporiadanie dôveryhodných adries.

Prinútiť verejný pôvod, aby sa správal ako verejný

Aplikácia by mala vydávať absolútne URL, presmerovania a cookies pre verejný pôvod. Ak presmeruje návštevníka na backend.corp.example, je tento návštevník poslaný na meno, ktoré nedokáže preložiť.

Oprav to pomocou podporovaného nastavenia externej URL v aplikácii a preverenej politiky presmerovania, nie prepisovaním mien hostiteľov v telách odpovedí. Nahrádzanie reťazcov v ľubovoľnom obsahu rozbíja podpísané dátové časti a vytvára chyby, ktoré sa ťažko dohľadávajú.

Cookies si zaslúžia rovnakú starostlivosť. Cookie viazaná na privátne meno nebude nikdy odoslaná prehliadačom, ktorý pozná len verejné.

Potvrď aj, že Nginx môže skutočne vlastniť verejný socket. Existujúca webová služba na 443 sa musí presunúť, alebo musí frontend žiť inde, pretože dva procesy nemôžu zviazať rovnakú adresu a port.

Skontrolovať každý úsek tam, kde skutočne beží

Over konfiguráciu nainštalovaným parserom pred každým reloadom, aby preklep nezosypal listener, ktorý práve obsluhuje.

Potom otestuj backendový úsek z hostiteľa frontendu samotného, v rovnakom sieťovom kontexte, ktorý používa Nginx. Ping tunelom dokazuje dosiahnuteľnosť a nič o TLS, autorizácii alebo aplikácii.

Nakoniec urob novú verejnú požiadavku na skutočné meno hostiteľa s bežným overením certifikátu a sleduj cestu odpovede, nie len telo.

Ulož obe pozorovania spolu s nasadenou konfiguráciou a zapíš, čo sa stane, keď tunel nie je dostupný. Frontend by mal vrátiť riadenú chybu upstreamu, nie ticho prejsť na iný backend, ktorý nikto nedokumentoval. 502 s jasným riadkom v logu je dobrý výsledok. Stránka z vyrovnávacej pamäte z nechceného pôvodu nie je.

Súvisiace články