HAProxy 302 verso un’app privata: chi apre il secondo salto?
Un redirect restituisce la seconda connessione al browser. Invia invece la richiesta a un backend, poi correggi i redirect assoluti e i cookie dell’app.
Qualcuno punta un host HAProxy pubblico su un’applicazione interna e chiede perché il browser non riesca a seguire. Il proxy raggiunge l’app tramite la sua VPN, il redirect restituisce un header Location e il browser prova allora un indirizzo che esiste solo dentro il tunnel. Dall’esterno la pagina resta semplicemente bloccata. La decisione riguarda quale parte apre la seconda connessione, ed è questo che separa un redirect da un backend.
Due percorsi che nella configurazione si somigliano
Un redirect chiude lo scambio con una risposta. Il client legge Location e avvia una nuova richiesta da dove si trova, cioè dalla rete che non hai mai controllato. Il proxy non è più coinvolto. Tutto ciò che segue dipende dal DNS, dalla rotta e dalla fiducia del client, quindi l’esito cambia a seconda di dove l’utente ha aperto il browser:
GET /app client -> proxy
302 Location proxy -> client (http://10.40.0.20:8080/)
GET /app client -> 10.40.0.20:8080 client network, no route
Un backend del proxy tiene la seconda tratta sul lato server. Il proxy la apre lungo il percorso che già possiede, e il client continua a parlare con un solo nome pubblico. Se il tunnel cade, il client riceve un errore invece di un URL che non può seguire. Questa differenza è anche ciò che rende diagnosticabile il guasto, perché l’errore compare dove sono i log:
GET /app client -> proxy
GET /app proxy -> 10.40.0.20:8080 over the VPN
response proxy -> client
La documentazione sui redirect di HAProxy traccia esattamente questa linea: rispondere al client con un redirect è un’azione diversa dall’inoltro della richiesta a un backend. Le due direttive stanno a poche righe di distanza in un file di configurazione e si comportano in modo del tutto diverso. Una chiude la richiesta, l’altra ne apre una seconda che appartiene al proxy.
Ciò che serve al browser e che la VPN del server non gli dà
La richiesta del browser ha bisogno di quattro cose che potrebbe non avere: una risposta DNS per il nome privato, una rotta verso quell’indirizzo, il permesso di raggiungere il servizio in ascolto e la fiducia nel certificato che quel servizio presenta. L’host del proxy le possiede tutte e quattro grazie al suo tunnel. Nessuna di esse si trasferisce a un client che non è mai stato su quel tunnel, perché il tunnel è una proprietà dell’host, non dell’URL.
Questo divario spiega il sintomo del quasi funziona. La prima richiesta riesce, la barra degli indirizzi cambia, poi la connessione si blocca o fallisce mentre il proxy è sano per tutto il tempo. Nella configurazione del proxy non c’è nulla di rotto, e ritoccarla non aiuta un client che non ha alcun percorso verso 10.40.0.20. O il client ottiene una rotta, oppure il proxy deve fare la connessione al posto suo.
Quando solo il proxy può raggiungere l’app
Rimuovi l’azione di redirect e invia quelle richieste a un backend che punta all’indirizzo privato. Il frontend mantiene il suo nome pubblico mentre il backend decide dove va davvero la richiesta. Nulla cambia nel percorso del client, perché il proxy smette di descrivere una destinazione e comincia a esserlo. Per un’applicazione che ascolta di proposito sulla porta interna 8080, il blocco server è breve:
backend private_app
mode http
option httpchk GET /health
server app1 10.40.0.20:8080 check
Leggi quel blocco come un’affermazione sulla tabella di routing del proxy: 10.40.0.20 deve essere raggiungibile dall’host del proxy stesso, il che qui significa attraverso l’interfaccia VPN e non la rotta predefinita. La parola chiave check riporta solo ciò che fa quella rotta, e il percorso di health deve esistere sull’applicazione, altrimenti ogni sonda segna il server come inattivo. Un controllo superato non dimostra nulla sul client e non sostituisce la policy che decide chi può usare il backend.
Il frammento non è un frontend completo. Mantieni il listener, l’autenticazione, la selezione di host e percorsi consentiti e la regola che decide chi può raggiungere l’applicazione. Allinea anche il protocollo del backend, perché un backend HTTPS richiede la verifica del certificato e una configurazione dell’identità del server, e saltare quel controllo trasforma una connessione privata in una non verificata.
Conferma il percorso di ritorno in entrambe le direzioni prima di dichiarare vittoria. L’applicazione ora vede una connessione dal proxy, quindi i suoi log e qualsiasi metadato dell’indirizzo client descrivono il proxy, a meno che tu non disponga altrimenti. Decidi come vengono gestite l’identità e gli indirizzi inoltrati, e verifica la decisione invece di darla per scontata.
I redirect dell’app puntano ancora all’interno
Inoltrare la prima richiesta è solo metà dell’integrazione. L’applicazione può emettere redirect assoluti, URL di risorse codificati a mano o cookie limitati al nome che conosce internamente, e ognuno di questi rimanda il browser a un indirizzo che non può raggiungere. Un header Location che punta al nome interno è identico al problema originale, ed è per questo che viene diagnosticato male come guasto del proxy.
Imposta l’URL esterno documentato dell’applicazione e le sue opzioni proxy, poi fai coincidere l’header Host con l’host virtuale e con le aspettative del certificato. Un cookie limitato al nome interno non tornerà attraverso il nome pubblico, e il ciclo di accesso che ne segue si legge come un bug di autenticazione. Cambia prima l’URL esterno, riprova da un profilo browser pulito e aspettati che impostazioni migrate a metà producano un accesso che riesce e una sessione che muore subito.
Fidati dei metadati inoltrati solo dal proxy designato. Un header che qualsiasi client può impostare non deve mai diventare un valore di autorizzazione, altrimenti il proxy diventa un modo per chi chiama di rivendicare l’identità di qualcun altro. Questa regola è indipendente dalla questione del redirect e sopravvive a ogni riprogettazione successiva.
Decidi quale progetto hai davvero
Se ogni utente ha già un accesso VPN autorizzato, un redirect verso un URL privato può essere una scelta deliberata. Conferma esplicitamente quel requisito invece di darlo per scontato, perché i due progetti servono popolazioni completamente diverse. Uno dei due non funziona affatto da una rete d’albergo, e l’altro espone l’applicazione a chiunque possa caricare l’URL pubblico. Quella distinzione va nella nota di progetto.
Esegui il controllo da una macchina sulla rete degli utenti e segui ogni salto che fa il browser, non solo la prima risposta. Tieni d’occhio la barra degli indirizzi e ogni richiesta successiva, perché un solo URL assoluto in un tag di risorsa basta a rompere un flusso che il primo salto aveva superato. L’accesso deve funzionare attraverso il nome pubblico, e le risorse che devono essere negate devono restare negate.
Pubblicare un reverse proxy è una decisione di accesso separata, non un’estensione trasparente della VPN del proxy a chiunque possa caricare il suo URL pubblico. I due si somigliano in un diagramma, e differiscono in chi è ammesso. Decidere quella questione dopo il deployment è il modo in cui un’applicazione interna diventa pubblica per caso.
Scrivi quale delle due hai costruito e perché. La prossima persona che toccherà la configurazione presumerà l’altra. Un solo redirect aggiunto per comodità basta a ricreare il guasto originale, e il sintomo sarà identico a quello che hai appena corretto.