I pacchetti possono seguire una rotta OpenVPN ed essere comunque catturati da una policy IPsec, e questa combinazione sembra un bug di routing da ogni angolazione tranne quella giusta. Linux risolve una rotta e poi consulta un database separato delle policy di sicurezza, quindi una rotta di destinazione più specifica non sposta una policy XFRM corrispondente. Il sintomo visibile è traffico che lascia l’host e non arriva mai, mentre entrambi i tunnel si dichiarano sani. Tre opzioni lo risolvono, e quale scegliete dipende da quale dei due percorsi deve portare quel prefisso.

Due decisioni, non una

La selezione della rotta risponde a una domanda ristretta: quale prossimo hop e quale indirizzo sorgente devono portare questo pacchetto. Il database delle policy di sicurezza risponde a un’altra: questo pacchetto richiede protezione IPsec, e sotto quali selettori. Entrambi vengono eseguiti per lo stesso pacchetto, e soddisfare il primo non dice nulla sul secondo. Per questo cambiare una metrica o aggiungere una rotta statica può lasciare il sintomo intatto.

Un selettore IPsec ampio è la causa abituale. Una policy che protegge 172.16.0.0/12 copre anche 172.20.8.0/24, che un amministratore potrebbe voler raggiungere tramite il tunnel OpenVPN. L’intenzione esiste solo nella tabella di routing, e il database delle policy non ne ha mai saputo nulla.

Trattatelo come un conflitto tra due percorsi di protezione configurati e non come una competizione tra due metriche. La correzione appartiene al componente configurato con l’ambito sbagliato.

Leggete la rotta che il kernel sceglie davvero

Iniziate dalla ricerca che esegue il kernel, compresi l’indirizzo sorgente e qualsiasi regola di policy che potrebbe deviarla verso un’altra tabella. Una rotta nella tabella principale potrebbe non essere mai consultata se una regola precedente sceglie un’altra tabella, e la corrispondenza del prefisso più lungo vale solo all’interno della tabella scelta da una regola.

ip rule show
ip route show table all
ip route get 172.20.8.20 from 10.44.7.15

L’ultimo comando è quello che conta, perché stampa la rotta scelta insieme all’indirizzo sorgente che il kernel userebbe. Confrontate quell’output con il selettore a cui corrisponde la policy IPsec. Quando la rotta punta all’interfaccia OpenVPN e la policy corrisponde ancora alla stessa coppia, avete riprodotto il conflitto senza indovinare.

Tenete i dump privi di indirizzi non pertinenti prima che arrivino a un ticket. Una tabella di routing di un host di produzione porta topologia interna, e solo le righe che rispondono alla domanda meritano di essere incollate.

Leggete la policy che si applica anch’essa

L’elenco delle policy mostra direzione, selettori e il modello che decide che cosa succede a un pacchetto corrispondente. Leggete prima la direzione in uscita, poi il lato in entrata per il traffico di ritorno, perché un’eccezione unidirezionale produce una connessione che inizia e non si completa mai.

ip -s xfrm policy
swanctl --list-sas

Confrontate i selettori dell’elenco con i prefissi negoziati dalla connessione. Disattivare l’installazione delle rotte di strongSwan non rimuove quelle policy, e cambiare una metrica non modifica quale coppia sorgente-destinazione una policy protegge. Vale la pena escludere subito queste due false correzioni, perché sono le prime che la gente prova.

Se l’elenco non contiene alcuna policy per il prefisso atteso, il problema è altrove e la tabella di routing probabilmente dice la verità. Se contiene una policy più ampia che copre il prefisso, avete trovato la cattura.

Tre opzioni quando entrambi i percorsi sono legittimi

Restringere il selettore IPsec è l’opzione più pulita quando il prefisso ampio era una comodità e non un requisito. Ridurre il selettore del traffico remoto alle sottoreti che appartengono davvero dietro IPsec elimina il conflitto per ogni host in una volta, e costa una rinegoziazione delle chiavi invece di un nuovo componente.

Un’eccezione passthrough è l’opzione chirurgica quando il selettore ampio deve restare. strongSwan supporta una connessione separata il cui child usa la modalità pass, che dice al kernel che il traffico corrispondente non deve essere elaborato da IPsec. L’indirizzo remoto di loopback impedisce che quella connessione venga scelta per i peer in entrata, e i selettori devono descrivere la coppia realmente autorizzata e non tutto.

connections {
    openvpn-exception {
        remote_addrs = 127.0.0.1
        children {
            openvpn-exception {
                local_ts = 10.44.7.0/24
                remote_ts = 172.20.8.0/24
                mode = pass
                start_action = trap
            }
        }
    }
}

Gli esempi di configurazione di strongSwan documentano questo tipo di policy e la convenzione del peer in loopback. La terza opzione è un design basato sul routing con interfacce XFRM, che lega la policy al traffico instradato attraverso un’interfaccia con nome invece che a un selettore globale. È una migrazione e non un ritocco, e il traffico deve comunque soddisfare i selettori negoziati.

OptionUse it whenCost
Narrow the selectorThe broad prefix was convenienceA rekey and a policy review
Passthrough childThe broad selector must stayOne exception per intended pair
XFRM interfacePolicy should follow routingA design migration

Dimostrate l’eccezione senza indebolire il resto

Dopo aver caricato la modifica, provate l’eccezione e una destinazione ordinaria che deve restare protetta. Controllate entrambe le direzioni, poi abbattete il tunnel OpenVPN e confermate che cosa succede al traffico escluso. Un’eccezione che invia quel prefisso in chiaro in silenzio quando il tunnel è abbattuto è una decisione di policy che dovreste prendere di proposito, non scoprire durante un incidente.

Annotate quale prefisso usa quale percorso e perché. Altrimenti il prossimo ingegnere che vede un selettore ampio riaprirà la stessa indagine, e la risposta starà in un messaggio di commit che nessuno legge.

Articoli correlati