Følg én anmodning fra en telefon i et tog til en backend, der kun findes inde i et privat netværk. Telefonen slår et offentligt navn op, forbinder til en offentlig adresse på port 443 og gennemfører et normalt TLS-håndtryk. Nginx accepterer den forbindelse og åbner derefter en anden, helt separat forbindelse til en adresse, som den kun når gennem en VPN-grænseflade. Intet ved telefonen ændres, og telefonen opdager aldrig, at en tunnel var involveret.

Følg én anmodning gennem to forbindelser

Det indgående ben er en offentlig HTTP-transaktion. Det har et offentligt navn, et offentligt certifikat og en svarvej, der skal virke for den adresse, den besøgende tilfældigvis har. Enhver ændring, der forstyrrer den vej, ødelægger alle besøgende på én gang. Derfor er det offentlige ben det, du mindst vil eksperimentere med.

Det udgående ben er privat. Nginx bliver klient, slår et internt navn op eller bruger en fast adresse og når en tjeneste, der ville afvise en forbindelse fra internettet.

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

Hold dem adskilt i hovedet, og konfigurationen bliver indlysende. Smelt dem sammen, og du ender med at prøve at få en offentlig klient til at deltage i en tunnel, og det er der, det meste af forvirringen i dette design kommer fra. Det private ben må gerne være skrøbeligt. Det offentlige må ikke.

Før du bygger noget af det, skal du bekræfte, at offentliggørelsen af applikationen er tilsigtet. En fungerende proxy er også en fungerende eksponering, og godkendelsesmodellen skal være en beslutning og ikke en bivirkning.

Gateway-navnet skal overleve tunnelen

Der ligger en subtil fælde i navneopslag. Hvis privat DNS tilsidesætter det samme navn, som VPN-profilen bruger til sin egen gateway, kan en genopkobling ende med at forsøge at nå den gateway gennem den tunnel, den selv skal etablere. Klienten har brug for, at navnet slås op, før tunnelen findes. Når det først slås op inde i tunnelen, kan forbindelsen aldrig bygges.

Brug forskellige godkendte navne til gatewayen og backenden, og afgræns resolverpolitikken, så hvert navn slås op til den adresse, dets bruger har brug for. At ændre en applikations Host-header hjælper intet her, fordi det er VPN-klienten, der laver opslaget.

Tænk derefter på omfanget. Frontenden har brug for en rute til backend-adressen, og den skal også blive ved med at svare offentlige klienter. En fuld tunnel på den vært kan opfylde det første krav og ødelægge det andet.

Hvor politikken tillader det, er en tunnel til en bestemt destination det renere design. Hvor politikken kræver en fuld tunnel, hører frontenden hjemme i en separat netværkskontekst i stedet for at blive lappet sammen med ad hoc-ruter for kendte besøgende.

Skriv serverblokken, så begge ben verificerer

Antag, at backenden præsenterer et certifikat for backend.corp.example og svarer på en privat adresse. At forbinde til en adresse, mens man verificerer et navn, er netop hvad proxy-modulets SNI- og navnemuligheder er til.

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 pladsholder. De vigtige dele er dem, der holder verifikationen slået til: et navn at kontrollere, et tillidsbundt at kontrollere det imod og en dybde, der matcher den godkendte kæde.

proxy_set_header Host app.example.com er bevidst. Backenden bør konfigureres til at acceptere den offentlige oprindelse, og den bør kun stole på videresendte headers fra denne frontend. At overskrive X-Forwarded-For med klientadressen er rigtigt for én proxy og forkert for en kæde, så en udrulning med flere proxies har brug for sin egen ordning med betroede adresser.

Få den offentlige oprindelse til at opføre sig som sådan

Applikationen bør udsende absolutte URL'er, omdirigeringer og cookies for den offentlige oprindelse. Hvis den omdirigerer en besøgende til backend.corp.example, sendes den besøgende til et navn, de ikke kan slå op.

Ret det gennem applikationens understøttede indstilling for eksterne URL'er og en gennemgået omdirigeringspolitik, ikke ved at omskrive værtsnavne i svarlegemer. Strengudskiftning i vilkårligt indhold ødelægger signerede payloads og skaber fejl, der er svære at spore.

Cookies fortjener samme omhu. En cookie, der er bundet til det private navn, bliver aldrig sendt af en browser, der kun kender det offentlige.

Bekræft også, at Nginx faktisk kan eje den offentlige socket. En eksisterende webtjeneste på 443 skal flytte sig, eller frontenden skal bo et andet sted, fordi to processer ikke kan binde samme adresse og port.

Kontroller hvert ben, hvor det faktisk kører

Validér konfigurationen med den installerede parser før enhver genindlæsning, så en tastefejl ikke vælter den listener, der tjener lige nu.

Test derefter backend-benet fra frontend-værten selv, i samme netværkskontekst som Nginx bruger. En ping gennem tunnelen beviser nåbarhed og intet om TLS, autorisation eller applikationen.

Lav til sidst en frisk offentlig anmodning til det rigtige værtsnavn med normal certifikatverifikation, og observer svarvejen i stedet for kun svarlegemet.

Gem begge observationer sammen med den udrullede konfiguration, og notér, hvad der sker, når tunnelen ikke er tilgængelig. Frontenden bør returnere en kontrolleret upstream-fejl, ikke stille falde tilbage til en anden backend, som ingen har dokumenteret. En 502 med en klar loglinje er et godt resultat. En cachet side fra en utilsigtet oprindelse er det ikke.

Relaterede artikler