Perché Port-Share fa apparire tutti i visitatori del sito come localhost
Il backend vede il salto di inoltro, non il browser. Verificate dove si perde l'indirizzo di origine, poi decidete quale componente può garantirlo.
Ogni riga del log di accesso mostra lo stesso indirizzo di loopback, mentre la pagina stessa si carica e il certificato viene verificato correttamente. Nulla è rotto nel senso di irraggiungibile, ed è per questo che il caso sopravvive per mesi. Ciò che si è rotto è l'attribuzione: il backend web registra l'indirizzo del salto che ha inoltrato la connessione, e ogni decisione successiva che si fidava del log ha ereditato la stessa risposta sbagliata.
I controlli seguenti vanno dal cavo verso l'interno. Fermatevi al primo che spiega il valore che vedete, perché ogni passo successivo presuppone che i precedenti siano già veri. Nessuno di essi richiede di indovinare la configurazione del front-end.
Seguite le due connessioni, non la riga del log
Port-Share multiplexa due protocolli su un unico listener TCP. OpenVPN ispeziona i primi byte di una connessione in entrata, la trattiene quando sembra del proprio protocollo e consegna tutto il resto a una seconda destinazione. Quella destinazione è di solito un server web sullo stesso host, quindi il socket accettato dal server web ha il processo OpenVPN come pari.
ss -ltnp 'sport = :443'
ss -tnp 'dport = :8080'
Il primo comando mostra chi possiede il listener pubblico. Il secondo mostra le connessioni che arrivano alla porta del backend, e l'indirizzo del loro pari è quello che il log di accesso stamperà. Se quel pari è loopback, il log è esatto e l'informazione si è persa uno strato prima. Rinominare il campo del log o attivare un modulo per l'IP del client non recupererà un indirizzo che la connessione non ha mai portato.
È questo il controllo che decide tutto il resto. Se il pari del backend è l'indirizzo del browser, la condivisione della porta non è il vostro problema e lo è il formato del log.
L'inoltro del trasporto non è iniezione di intestazioni
L'inoltro sposta byte. Non analizza HTTP, quindi non può inserire un'intestazione in una richiesta che non legge mai come richiesta, e non può aggiungere nulla a un flusso TLS che lascia passare intatto. Un modulo che attende un'intestazione di proxy continuerà ad aspettarne una che nessun componente produce.
Due meccanismi possono portare l'indirizzo originale, ed entrambi richiedono un accordo su entrambe le estremità. Il protocollo PROXY antepone una piccola intestazione alla connessione, e il backend deve essere configurato per aspettarsela; un backend che non se l'aspetta tratterà quei byte come l'inizio della richiesta e fallirà in modo confuso. Le intestazioni di proxy affidabili come X-Forwarded-For funzionano quando un proxy che comprende HTTP le imposta e al backend viene detto quali pari possono affermarle.
Nessuno dei due è automatico, e nessuno dei due è sicuro per impostazione predefinita. Un backend che crede a ogni intestazione inoltrata in entrata permette a un client di scegliere il proprio indirizzo, il che trasforma un'imprecisione del log in un aggiramento del controllo di accesso. Eseguite la dimostrazione una volta su un host di prova prima di fidarvi di qualsiasi intestazione su un percorso di produzione.
curl -sS -H 'X-Forwarded-For: 127.0.0.1' https://site.example.com/health
grep -F '127.0.0.1' /var/log/nginx/access.log | tail -n 3
La directory opzionale di mappatura delle origini
La condivisione della porta ha un argomento di directory opzionale che registra una mappatura tra l'indirizzo di origine originale e la connessione di inoltro, sulle piattaforme in cui la funzione è implementata. Ci si aspetta che il lato web consulti quella mappatura; non è un'intestazione e non viene iniettata nella richiesta.
Vale la pena conoscere quel progetto perché spiega perché alcune installazioni riportano indirizzi reali e altre no, con una configurazione del front-end apparentemente identica. La differenza è sul lato ricevente e di solito vive in un modulo o in una patch che la maggior parte dei server web pacchettizzati non abilita per impostazione predefinita. Leggete la documentazione del vostro server web per conoscere l'esatto hook che offre e confermate che il modulo sia caricato invece di darlo per scontato.
Se seguite questa strada, trattatela come un'integrazione in due metà: la mappatura scritta dall'inoltro e la ricerca eseguita dal backend. Verificate entrambe e confermate che la directory sopravviva a un riavvio e non cresca senza limiti su un listener occupato.
Decidete quale componente garantisce l'indirizzo
Prima di cambiare la configurazione, nominate il componente a cui è consentito affermare un indirizzo client e i componenti a cui è consentito crederci. Un'unica risposta scritta evita la deriva abituale, in cui tre strati diversi si fidano ciascuno di una fonte diversa.
Tre progetti coprono la maggior parte delle esigenze. Tenete separati il listener pubblico e il listener web, così che il server web veda pari reali e non esista alcun problema di attribuzione. Mettete davanti un proxy inverso che comprende HTTP, terminate o analizzate la richiesta lì, e lasciategli impostare un'intestazione inoltrata per un backend che si fida solo di quel proxy. Oppure mantenete la condivisione della porta e accettate che i log mostrino il salto, con regole di accesso scritte contro l'identità dell'applicazione invece che contro un indirizzo.
Ciò che non funziona è trattare un indirizzo di loopback inoltrato come prova che la richiesta abbia avuto origine su questa macchina. Quell'inferenza è esattamente al contrario: l'indirizzo è presente proprio perché un componente locale ha stabilito la connessione. Una regola scritta così ammette chiunque possa raggiungere il listener.
Provate la regola, non la pagina
Una pagina che si carica dimostra che il percorso di inoltro funziona e non dice nulla sull'attribuzione. Provate il consumatore dell'indirizzo: la regola di accesso, il limite di velocità, la voce di audit, la ricerca geografica.
curl -sS -o /dev/null -w '%{http_code}\n' https://site.example.com/
tail -n 5 /var/log/nginx/access.log
grep -c '' /var/log/nginx/access.log
Confrontate una richiesta esterna autorizzata con i registri sia del front-end sia del backend, e confermate che una regola che dovrebbe negare neghi ancora e una che dovrebbe ammettere ammetta ancora. Se la riga del log è corretta ma la regola si comporta ancora come se tutti fossero locali, la regola legge un campo diverso da quello che avete corretto.
Concludete scrivendo la catena di attribuzione nelle note di distribuzione: quale listener, quale inoltro, quale intestazione o mappatura e quale backend è configurato per fidarsene. La prossima persona che leggerà una riga di log avrà bisogno di tutte e quattro, e l'assenza di quella nota è il modo in cui lo stesso ticket si riapre un anno dopo. Tenetela accanto alla configurazione e non in un thread di chat.