Ciò che si trova davanti a quasi ogni servizio web
Benvenuti
Se digiti example.com in un browser, quasi mai raggiungi il computer che esegue effettivamente l'applicazione. Raggiungi un computer che inoltro la richiesta a quello che lo fa. Quel computer di inoltro ha un nome: un reverse proxy.
Questa lezione insegna cosa fa un reverse proxy, perché quasi ogni servizio web pubblico si nasconde dietro uno di questi e quali sono i tre compiti che il livello di edge gestisce contemporaneamente.
Alla fine avrai compreso:
- La differenza tra un client, un proxy e un origin
- Perché un proxy davanti a un origin protegge, scala e permette di sostituire componenti senza che nessuno se ne accorga
- I tre compiti che un reverse proxy gestisce contemporaneamente: nascondere l'origin, terminare TLS e distribuire il carico tra le repliche
- Come una richiesta viaggia dal browser al proxy, all'upstream e di nuovo indietro, hop dopo hop
Entro la fine sarai in grado di ragionare con sicurezza sulla collocazione dei proxy, sulla separazione delle responsabilità al bordo e sul motivo per cui un livello di proxy stateless si moltiplica a basso costo, mentre un singolo origin non lo fa.
Proxy Forward vs Proxy Reverse
Due direzioni dei proxy
Entrambi i tipi di proxy si trovano tra due parti e inoltrano il traffico. Differiscono per quale parte rappresentano.
Proxy in avanti: si trova davanti a un gruppo di client. I client sono a conoscenza dell'esistenza del proxy; un server esterno vede l'indirizzo del proxy, non l'indirizzo del client. I proxy di uscita aziendali, i filtri di contenuto e i proxy SOCKS rientrano in questo schema.
Proxy inverso: si trova davanti a un gruppo di server. Il mondo esterno (i client) comunica con l'indirizzo del proxy; i client non hanno idea che un server reale si nasconda dietro di esso. Quasi ogni servizio web pubblico ne utilizza uno.
Mnemonico: un proxy in avanti nasconde i client dai server. Un proxy inverso nasconde i server dai client.
Perché è importante sapere in quale direzione? Il compito, le modalità di guasto e il confine di sicurezza sono tutti diversi. Un proxy in avanti si preoccupa di chi i suoi utenti contattano; un proxy inverso si preoccupa di chi contatta i suoi server.
Un client che invia traffico attraverso entrambi i tipi contemporaneamente percorre il percorso: client -> forward_proxy -> internet -> reverse_proxy -> origin.
Perché così tanto vive nella periferia
Il livello di periferia giustifica il suo costo
Un proxy inverso svolge tre compiti contemporaneamente. Qualsiasi di essi da solo giustifica il livello; il fatto di svolgere tutti e tre allo stesso indirizzo spiega perché quasi ogni architettura web di produzione abbia la stessa forma in testa.
Compito 1: Nascondere l'origine. Il proxy risponde su un IP pubblico. I backend si trovano su IP privati a cui Internet non può accedere. Un attaccante che vuole colpire l'origine deve prima compromettere il proxy.
Compito 2: Terminare TLS. Il proxy detiene il certificato per example.com e decifra le richieste HTTPS in ingresso. I backend comunicano con il proxy tramite HTTP semplice (o TLS interno più semplice) attraverso un segmento di rete fidato. La rotazione, il rinnovo dei certificati e la politica dei cifrari sono gestiti tutti in un unico punto.
Compito 3: Distribuire il carico. Il proxy sceglie quale backend gestisce ciascuna richiesta. I backend dietro un unico proxy formano un pool; il proxy ne seleziona uno per ogni richiesta utilizzando una strategia (round-robin, meno connessioni, hash su un header). Aggiungere capacità significa aggiungere un backend al pool, non comunicare a ogni client un nuovo indirizzo.
Ogni compito è un piccolo programma. Insieme spiegano perché un livello semplice come 'Caddy davanti a un'app Python' porta più peso progettuale dell'app Python stessa.
Progettare per tutti e tre i compiti
Il tuo team gestisce una piccola API su un singolo processo Python che ascolta sulla porta 8000 su una singola VM. Il traffico è cresciuto al punto che una sola VM non riesce a stare al passo, e una revisione di sicurezza ha segnalato che la VM ha un IP pubblico e gestisce il proprio certificato TLS.
Decidi di posizionare un reverse proxy davanti. Schizza la disposizione: a cosa punta il DNS, dove risiede il certificato, come raggiunge i backend il carico e cosa cambia nella VM originale?
Sostituire un componente senza che nessuno se ne accorga
L'indirezione compra libertà
Un vecchio adagio dell'informatica recita: ogni problema può essere risolto aggiungendo un livello di indirezione (tranne il problema di troppi livelli di indirezione). Il reverse proxy è una delle indirezioni più utili nei sistemi distribuiti.
Cosa ti offre:
- Backend sostituibili. Sposti l'applicazione da Python a Go? Migri da un data center a un altro? Rilasci una nuova versione con zero downtime? Ciascuna di queste operazioni avviene dietro un indirizzo pubblico stabile. Per gli utenti non cambia nulla.
- Scalabilità indipendente. Il livello proxy scala in base alla banda e alla CPU al livello TLS. Il livello backend scala in base al lavoro applicativo. Ciascuno cresce lungo il proprio asse perché risiede su macchine diverse.
- Contenimento dei guasti. Un deploy errato sul backend non fa cadere l'indirizzo pubblico. Il proxy resta attivo; applichi una correzione o esegui un rollback; il mondo si ricollega quando il backend si riprende.
- Preoccupazioni trasversali in un unico punto. Limitazione delle richieste (rate limiting), blocco geografico, logging delle richieste, riscrittura degli header, caching, compressione delle risposte: tutto risiede sul proxy. Il codice del backend resta focalizzato sull'applicazione.
Senza il proxy ciascuno di questi problemi deve risiedere all'interno del processo applicativo. Con il proxy risiedono in un unico livello gestito da un unico team.
Il costo: un ulteriore livello da gestire. I team maturi accettano questo costo perché il livello proxy stesso è stateless e scala in orizzontale; sostituire un proxy con due non richiede coordinazione.
Una distribuzione Blue/Green tramite proxy
Il tuo team esegue la versione 1 dell'API su tre VM di backend (pool blu) dietro un proxy inverso. Desideri distribuire la versione 2 con la possibilità di effettuare un rollback in meno di trenta secondi se qualcosa va storto.
Avvii tre nuove VM di backend (pool verde) che eseguono la versione 2, affiancate al pool blu, ma non instradi ancora traffico verso di esse.
Dal Browser al Backend e Indietro
Segui una Richiesta dall'Inizio alla Fine
Traccia una singola richiesta HTTPS GET di https://api.example.com/users/42 attraverso un proxy inverso posto davanti a un pool di backend.
Hop 1: Risoluzione DNS. Il browser chiede a un resolver l'indirizzo per api.example.com. Il resolver restituisce l'IP pubblico del proxy (ad esempio, 203.0.113.10). Il browser apre una connessione TCP a 203.0.113.10:443.
Hop 2: Handshake TLS. Il proxy presenta il suo certificato per api.example.com. Il browser valida il certificato, le due parti concordano una chiave di sessione e il canale cifrato viene aperto.
Hop 3: Richiesta HTTP all'interno di TLS. Il browser invia GET /users/42 HTTP/1.1\nHost: api.example.com\n.... Il proxy decifra i byte della richiesta.
Hop 4: Selezione del backend. Il proxy consulta il suo pool di upstream per api.example.com e sceglie un backend (ad esempio 10.0.0.21:8000) utilizzando la sua strategia di bilanciamento del carico.
Hop 5: Richiesta upstream. Il proxy apre (o riutilizza) una connessione HTTP semplice verso 10.0.0.21:8000 e inoltra la richiesta. Il proxy può riscrivere gli header lungo il percorso: aggiungere X-Forwarded-For: <client-ip>, impostare correttamente Host: e rimuovere gli header hop-by-hop come Connection.
Hop 6: Elaborazione del backend. L'applicazione backend legge la richiesta, interroga il suo database e costruisce una risposta JSON.
Hop 7: Risposta upstream. Il backend invia la risposta di nuovo al proxy come HTTP semplice.
Hop 8: Risposta edge. Il proxy può riscrivere o comprimere la risposta, la crittografa di nuovo attraverso la sessione TLS e la invia al browser.
Hop 9: Ciclo di vita della connessione. La sessione TLS tipicamente rimane aperta per la richiesta successiva (HTTP/2 multiplexa molte richieste su una sola connessione). La connessione dal proxy al backend viene spesso messa in pool per il riutilizzo.
Ogni servizio web pubblico segue una variante di questa struttura. Conoscere gli hop consente di ragionare su dove si accumula la latenza, dove appartiene il logging e dove un guasto può nascondersi.
Dove è andato il tempo?
Un utente si lamenta che l'API sembra lenta. Misuri e scopri che la richiesta richiede 850 ms dall'inizio alla fine. I log del server sul backend mostrano che l'applicazione ha gestito la richiesta in 40 ms. I log del proxy mostrano che il proxy ha impiegato 50 ms per la sua parte del lavoro (handshake TLS + instradamento + scrittura della risposta).
Progetta un Edge minimale per un nuovo servizio
Sintesi
Hai imparato la differenza tra un proxy forward e un reverse proxy, i tre compiti che un reverse proxy gestisce simultaneamente, perché nascondere l'origine genera vantaggi ogni volta che è necessario apportare modifiche e come una richiesta fluisce hop per hop attraverso l'edge.
Ora applica quanto appreso.
Un piccolo team prevede di lanciare un nuovo servizio chiamato notes.example.com. Gli utenti leggeranno e scriveranno note personali. Il team eseguirà due VM di backend al lancio e prevede di scalare a dieci nel prossimo anno. Desiderano HTTPS per gli utenti, un rollout graduale per le nuove versioni e nessuna esposizione pubblica degli IP dei backend.
Dove va questo corso da qui in avanti
Dove va questo corso da qui in avanti
Questa lezione ha stabilito la forma dello strato di edge. Altre quattro lezioni in questo corso si basano su di essa:
- Scalabilità orizzontale senza stato: perché un livello di proxy (e i backend dietro di esso) si moltiplica in modo economico, e la matematica per dimensionare il numero di repliche in caso di picchi.
- Separazione Ingresso / Uscita: perché un singolo server proxy che gestisce sia il traffico in entrata che in uscita alla fine fallisce in modi sorprendenti, e come separare gli strati.
- Modalità di fallimento e raggio d'impatto: come un singolo cambiamento di configurazione possa causare un'interruzione del servizio e come scrivere azioni correttive senza attribuire colpe che prevengano la ricorrenza.
- Osservabilità e capacità: cosa misurare al perimetro per scoprire che qualcosa è rotto prima che lo facciano gli utenti.
Ogni lezione è autonoma. Insieme, ti forniscono un modello mentale operativo di una flotta su scala web.
Lezione complementare: geometry_of_proxies_and_origins riscrive tutto il contenuto di questa lezione come un grafo orientato ed esplora cosa la teoria dei grafi ti dice su un percorso di richiesta.
Ben fatto. Avanti.