Følg én forespørsel fra en telefon på et tog til en backend som bare finnes inne i et privat nettverk. Telefonen slår opp et offentlig navn, kobler til en offentlig adresse på port 443 og fullfører et normalt TLS-håndtrykk. Nginx godtar den tilkoblingen og åpner deretter en andre, helt separat, til en adresse den bare når gjennom et VPN-grensesnitt. Ingenting ved telefonen endres, og telefonen får aldri vite at en tunnel var involvert.

Følg én forespørsel gjennom to tilkoblinger

Det innkommende benet er en offentlig HTTP-transaksjon. Det har et offentlig navn, et offentlig sertifikat og en svarvei som må fungere for den adressen den besøkende tilfeldigvis har. Enhver endring som forstyrrer den veien, bryter alle besøkende på én gang. Derfor er det offentlige benet det du minst vil eksperimentere med.

Det utgående benet er privat. Nginx blir klient, slår opp et internt navn eller bruker en fast adresse, og når en tjeneste som ville avvise en tilkobling fra internett.

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

Hold dem atskilt i hodet, og konfigurasjonen blir åpenbar. Slå dem sammen, og du ender opp med å prøve å få en offentlig klient til å delta i en tunnel, og det er der det meste av forvirringen i dette designet kommer fra. Det private benet kan gjerne være skjørt. Det offentlige benet ikke.

Før du bygger noe av dette, må du bekrefte at publiseringen av applikasjonen er tilsiktet. En fungerende proxy er også en fungerende eksponering, og autentiseringsmodellen må være en beslutning og ikke en bivirkning.

Gateway-navnet må overleve tunnelen

Det ligger en subtil felle i navneoppslag. Hvis privat DNS overstyrer det samme navnet som VPN-profilen bruker for sin egen gateway, kan en gjenoppkobling ende med å prøve å nå den gatewayen gjennom tunnelen den selv skal etablere. Klienten trenger at navnet slås opp før tunnelen finnes. Når det først slås opp inne i tunnelen, kan tilkoblingen aldri bygges.

Bruk forskjellige godkjente navn for gatewayen og backenden, og avgrens resolverpolicyen slik at hvert navn slås opp til adressen brukeren trenger. Å endre en applikasjons Host-header hjelper ikke her, fordi det er VPN-klienten som gjør oppslaget.

Tenk så på omfanget. Frontend trenger en rute til backend-adressen, og den må også fortsette å svare offentlige klienter. En full tunnel på den verten kan oppfylle det første kravet og bryte det andre.

Der policyen tillater det, er en tunnel til et bestemt mål det renere designet. Der policyen krever en full tunnel, hører frontend hjemme i en separat nettverkskontekst i stedet for å lappes med ad hoc-ruter for kjente besøkende.

Skriv serverblokken slik at begge ben verifiserer

Anta at backenden presenterer et sertifikat for backend.corp.example og svarer på en privat adresse. Å koble til en adresse mens man verifiserer et navn er nettopp det proxy-modulens SNI- og navnealternativer er til for.

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;
    }
}

Hver sti og adresse ovenfor er en plassholder. De viktige delene er de som holder verifiseringen på: et navn å kontrollere, en tillitspakke å kontrollere det mot og en dybde som matcher den godkjente kjeden.

proxy_set_header Host app.example.com er bevisst. Backenden bør konfigureres til å godta det offentlige opphavet, og den bør bare stole på videresendte headere fra denne frontend. Å overskrive X-Forwarded-For med klientadressen er riktig for én proxy og galt for en kjede, så en utrulling med flere proxier trenger sin egen ordning for betrodde adresser.

Få det offentlige opphavet til å oppføre seg som et slikt

Applikasjonen bør sende absolutte URL-er, omdirigeringer og informasjonskapsler for det offentlige opphavet. Hvis den omdirigerer en besøkende til backend.corp.example, sendes den besøkende til et navn de ikke kan slå opp.

Rett det gjennom applikasjonens støttede innstilling for eksterne URL-er og en gjennomgått omdirigeringspolicy, ikke ved å skrive om vertsnavn i svartekstene. Strengerstatning i vilkårlig innhold bryter signerte payloads og skaper feil som er vanskelige å spore.

Informasjonskapsler fortjener samme omhu. En informasjonskapsel bundet til det private navnet blir aldri sendt av en nettleser som bare kjenner det offentlige.

Bekreft også at Nginx faktisk kan eie den offentlige socketen. En eksisterende webtjeneste på 443 må flytte seg, eller så må frontend bo et annet sted, fordi to prosesser ikke kan binde samme adresse og port.

Kontroller hvert ben der det faktisk kjører

Valider konfigurasjonen med den installerte parseren før hver omlasting, slik at en skrivefeil ikke velter lytteren som tjener akkurat nå.

Test deretter backend-benet fra frontend-verten selv, i samme nettverkskontekst som Nginx bruker. En ping gjennom tunnelen beviser nåbarhet og ingenting om TLS, autorisasjon eller applikasjonen.

Til slutt gjør en fersk offentlig forespørsel til det ekte vertsnavnet med normal sertifikatverifisering, og observer svarveien i stedet for bare svarteksten.

Ta vare på begge observasjonene sammen med den utrullede konfigurasjonen, og noter hva som skjer når tunnelen ikke er tilgjengelig. Frontend bør returnere en kontrollert upstream-feil, ikke stille falle tilbake til en annen backend som ingen har dokumentert. En 502 med en tydelig logglinje er et godt resultat. En bufret side fra et utilsiktet opphav er det ikke.

Relaterte artikler