Conserva o applica SNAT agli IP dei client VPN al confine del cloud
Conservare l’origine mantiene l’identità del client in ogni registro, SNAT mantiene piccola la tabella di routing. Tre condizioni dicono quale serve all’applicazione.
Conservare l’indirizzo del client VPN fino all’applicazione fa sì che ogni riga di registro e ogni voce della lista consentita significhino la stessa cosa. Riscriverlo al bordo del cloud rende la tabella di routing più semplice e i registri meno utili. Nessuna delle due scelte è sbagliata di per sé, e l’argomento che la decide raramente riguarda le prestazioni. Tre condizioni la risolvono: se l’applicazione deve sapere quale persona si è connessa, se la tessitura del cloud accetterà l’origine che intendi inviare e chi accetterà di farsi carico della rotta di ritorno dopo.
Tre condizioni lo decidono
Parti dal requisito dell’applicazione, non dallo schema di rete. Se l’autorizzazione o l’audit dipendono dall’indirizzo individuale del client, conservarlo è un requisito funzionale e tradurlo è una regressione. Se all’applicazione basta sapere che il traffico è arrivato dal percorso di accesso remoto, un indirizzo tradotto è sufficiente ed è molto più economico da gestire.
La seconda condizione è meccanica. Una rete virtuale non si fida automaticamente di un pacchetto che dichiara un indirizzo che non è stato assegnato all’interfaccia di invio. La maggior parte delle tessiture cloud lo impone, in modi e con nomi diversi, e un progetto che lo ignora sembrerà corretto in uno schema e cadrà in silenzio in produzione.
La terza è organizzativa. Conservare le origini significa che la tabella di routing della sottorete dell’applicazione deve puntare indietro al gateway per il prefisso del client, e ogni team che aggiunge una sottorete in seguito deve mantenere quella rotta coerente. È un costo piccolo una volta e ricorrente su decine di account. Decidi chi lo paga prima di promettere il comportamento.
Una rotta non è il permesso di usurpare
Aggiungere una rotta di ritorno dice alla tua sottorete dove devono andare le risposte. Non dice alla tessitura che l’istanza che inoltra quei pacchetti ha il diritto di emetterli con un’origine estranea. Su AWS il controllo pertinente è la verifica di origine e destinazione, ed è visibile per istanza:
aws ec2 describe-instances --instance-ids i-0a1b2c3d4e5f60718 \
--query "Reservations[].Instances[].SourceDestCheck"
aws ec2 modify-instance-attribute --instance-id i-0a1b2c3d4e5f60718 \
--no-source-dest-check
Disattivala solo per l’istanza il cui lavoro documentato è l’inoltro, e per nient’altro. Ogni VM applicativa che mantiene il controllo attivo è una macchina in meno che può essere usata per emettere traffico con un’origine presa in prestito. Se la tua piattaforma non è AWS, cerca l’impostazione equivalente di anti-usurpazione o di indirizzi consentiti invece di supporre che il comportamento si trasferisca.
Una cattura di pacchetti rapida risolve la questione più in fretta della lettura della console. Se le risposte escono e il client non le vede mai, è la tessitura che scarta l’origine usurpata, non l’applicazione che fallisce.
Cosa compra la traduzione e cosa costa
Riscrivere l’origine sul gateway elimina il problema del percorso di ritorno. L’applicazione vede un indirizzo che sa già come raggiungere, e il prefisso del client non deve mai comparire in una tabella di routing del cloud. Su Linux la regola è una riga, e vale la pena scrivere la versione più stretta che puoi:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 172.20.8.0/24 -o ens5 -j SNAT --to-source 10.40.3.10
Nota cosa registra ora l’applicazione: 10.40.3.10 per ogni utente, su ogni connessione, per sempre. Qualsiasi lista di indirizzi consentiti costruita su quel valore ora concede l’accesso all’intera popolazione di accesso remoto, e qualsiasi revisione di incidente deve tornare al gateway per rispondere a chi fosse.
La soluzione non è abbandonare la traduzione, è smettere di fingere che l’indirizzo sia un’identità. Porta l’identità del client in un campo autenticato, registrala al gateway insieme alla tupla tradotta e lascia che l’applicazione si unisca su di essa. Senza la chiave di unione, la traduzione trasforma un problema di rete in un problema forense permanente.
Il relè è un’interfaccia diversa
Un proxy inverso davanti all’applicazione aggira del tutto la questione del percorso instradato. Il proxy apre la propria connessione backend, così il prefisso del client non deve mai essere instradabile dentro la rete virtuale, e l’applicazione può ricevere l’identità in un’intestazione che il proxy imposta.
Quell’intestazione è affidabile solo quando il backend l’accetta dal proxy e da nient’altro. In termini nginx questo significa nominare esplicitamente il peer fidato invece di credere a qualunque cosa arrivi:
set_real_ip_from 10.40.3.10;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Qualsiasi client che possa raggiungere il backend direttamente può falsificare la stessa intestazione, quindi il backend deve essere irraggiungibile se non attraverso il proxy. È un fatto di firewall, non un’opinione di configurazione, ed è il presupposto che le persone saltano quando copiano lo snippet.
Il relè cambia anche ciò che compri. Ottieni un’identità a livello applicativo e un posto naturale per registrarla; rinunci alla generalità, perché ogni nuovo protocollo ha bisogno del proprio supporto proxy. Per i servizi HTTP quello scambio di solito è buono, e per qualsiasi cosa non sia HTTP di solito non è affatto disponibile.
Scrivi cosa vede ogni confine
Qualunque cosa scegli, la revisione del progetto dovrebbe concludersi con una tabella che nomina l’indirizzo di origine e l’identità dimostrabile a ogni salto. Senza di essa, il primo incidente produce tre team che descrivono ciascuno un client diverso.
| Boundary | Source the next hop sees | What is actually proven |
|---|---|---|
| Client to gateway | 172.20.8.14 | A certificate or credential was presented |
| Gateway to app subnet, preserved | 172.20.8.14 | The same session, if the return route exists |
| Gateway to app subnet, translated | 10.40.3.10 | Only that traffic came through the gateway |
| Proxy to backend | 10.40.3.10 plus a header | The proxy asserted an identity it authenticated |
Poi scegli. Conserva quando l’autorizzazione dell’applicazione dipende davvero dall’indirizzo del client e puoi assumerti la rotta. Traduci quando non è così e puoi portare l’identità fuori banda, e usa le indicazioni AWS per le istanze di inoltro per le impostazioni di inoltro specifiche della piattaforma. Ricorri a un relè quando il servizio parla HTTP e vuoi che l’identità smetta di essere un indirizzo.