Introduzione. La necessità di una piattaforma virtuale
Dopo diversi anni di dignitoso lavoro ho deciso di sostituire il mio server con uno più potente e strutturato. Il mio obiettivo era quello di avere un grosso server su cui installare server virtuali, da attivare quando necessario.
Dopo una valutazione del mercato ho optato per OVH, provider di origine francese, che mi è piaciuto per la sua offerta e i suoi prezzi. In particolare la possibilità di installare a piacimento sistemi operativi che consentano la virtualizzazione, come vmware ESXi, che conosco molto bene, e Xen Server.
Ho optato per un bel server, con 32Gb di RAM, e 2 dischi da 2 Tb, ma, aimè, per motivi di budget non ho potuto prendere un server RAID Hardware.
Ho installato un ambiente di Vmware ESXi, ma ho scoperto che non è possibile avere raid software sui dischi di sistema. vmWare ESXi è una versione custom, con un particolare kernel, che non prevede meccanismi di raid software. Dato che comunque ho la necessità di avere un ambiente di produzione, con DB e con mail che cambiano in continuazione, non posso permettermi dei backup “ogni tanto”, ma un minimo di sicurezza sui dischi è indispensabile per non perdere dati.
Una possibile soluzione era quella di avere un mirror a livello di partizioni e dischi su macchine virtuali, utilizzando mirror tra partizioni raw di vmware, ma non mi sembrava abbastanza affidabile, né stabile per un ambiente di produzione. Inoltre, in caso di fail di un disco, dato che la procedura di installazione dell’ambiente è automatica e non si ha il controllo di quello che accade, niente vieta che la procedura, a seguito di una sostituzione del disco principale, reinstalli il sistema su quello che rimane, che contiene gli unici dati rimasti.
Ho installato e testato Xen Server, e ho apprezzato il fatto che poggia su un sistema CentOS reale, non molto ‘customizzato’, per cui è realmente personalizzabile. Una delle possibilità è quella di avere dischi di boot in raid software, con MD, che ho usato anni fa, e che, già allora, mi era sembrato stabile, affidabile e semplice.
Il problema di Xen Server si è presentato nel momento di configurare la rete. Questo ambiente offre un virtual switch di livello 2, utilizzando OpenSwitch. Questo vuol dire che non e’ possibile, con i meccanismi di Xen Server, realizzare un NAT fra una macchina virtuale e il mondo esterno. La macchina virtuale può solo ‘affacciarsi’ sulla rete pubblica, su un indirizzo che viene fornito dal provider.
Io avevo realmente bisogno di proteggere, con ip di rete 172.16.y.z i miei server, e di effettuare un NAT sulle porte esterne che mi occorrevano, senza preoccuparmi troppo della protezione dei server, posizionati all’interno di una rete privata, ma questa possibilità non viene offerta nativa da Xen Server.
Accenno brevemente a quello che è possibile fare, con gli strumenti base che sono messi a disposizione sia dal Xen, che dal provider, poi descriverò l’approccio e i compromessi che io ho adottato, nella speranza che qualcuno possa evitare 5 giorni di tentativi, prima di definire una soluzione.
Configurazione della rete di XenServer e di OVH.
Il meccanismo base di Xen consiste in una definizione di una interfaccia di rete virtuale sul server per ogni indirizzo IP fisico che viene associato alla macchina. Il provider ne mette a disposizione fino a 16, per cui è possibile associare tranquillamente 16 macchine virtuali ad altrettanti IP. Tali macchine sono direttamente esposte sulla rete, e vengono mappate 1 a 1 con gli indirizzi. Xen chiama questo meccanismo bridge, anche se in realtà questo concetto, in ambiente Linux, è una forzatura. Quello che viene fatto è una associazione reale tra una interfaccia di rete virtuale del server Xen e una macchina virtuale ospitatavi sopra. Altro non viene fatto.
Il meccanismo di routing in questa configurazione è particolare, perché’ praticamente il default router è l’interfaccia stessa. Per cui ogni pacchetto viene ‘buttato’ sull’interfaccia, e poi il router del provider si occupa di instradarlo. Attenzione che il gioco funziona SOLO se il router comunica il MAC address dell’interfaccia, da cui si aspetta che escano i pacchetti di rete. Il provider mette a disposizione un meccanismo (da interfaccia web) per cui il router CREA il MAC della macchina virtuale, da cui si aspetta i pacchetti. Tale MAC deve essere impostato a mano sulla macchina virtuale, altrimenti non funziona nulla. La macchina virtuale stessa viene configurata per inviare i pacchetti di default alla interfaccia. Consiglio di cercare e vedere la documentazione del provider, o di vedere questo documento, che mi ha illuminato (Configuration of OVH IP Failover on VMs https://binaryimpulse.com/2014/08/ovh-ip-failover-vm-configuration/).
Tutto questo naturalmente funziona; solo che non è quello che io volevo; qua non esiste NAT, non esiste protezione, non esistono DMZ o altro, e le macchine virtuali sono direttamente su internet.
Il sistema standard per creare tutto ciò è la installazione di una macchina virtuale come router/firewall, e costruire su questa tutto il meccanismo di routing/NAT/firewalling.
Ho provato a costruire questa struttura, ma ho avuto un paio di problemi, che mi hanno portato via parecchio tempo, e non mi hanno lasciato soddisfatto.
Il primo problema, sicuramente superabile, è stata la gestione di questa macchina virtuale. Quando si installa un firewall si dà per scontato che l’interfaccia di amministrazione sia in zona ‘green’, cioè in zona protetta. Ma in questo caso l’amministrazione iniziale o viene fatta a linea comando, o viene realizzata da remoto, dalla zona ‘red’. E questo, vi assicuro, non e’ semplice, specialmente per chi utilizza firewall abbastanza complessi, come Endian o ipcop, per la prima volta.
Il secondo problema, non tecnico, ma concettuale, e’ il fatto di creare una macchina virtuale che realizza ad alto livello (in una macchina virtuale appunto..) quello che dovrebbe essere fatto a basso livello (nel kernel del server). Ogni pacchetto attraversa le interfacce fisiche, viene passato alle interfacce virtuali, poi alla macchina virtuale, che processa il pacchetto, lo manipola, e lo ripassa alla macchina fisica, che lo instrada nuovamente verso le macchine virtuali e viceversa… Troppo lungo, complicato e macchinoso. Non è pensabile demandare al alto livello delle funzionalità che devono essere gestite e risolte a livello di kernel.
Per cui l’unica soluzione che ho intravisto come possibile è stata quella di mettere regole di NAT e filtro di indirizzi direttamente dentro lo Xen Server, e di implementare il firewall e il routing con le iptables direttamente sul kernel del Xen Server.
La cosa mi ha un po’ preoccupato, perché, per una configurazione errata, il rischio di bloccare tutto, specialmente su un sistema che a sua volta ospita altri sistemi, è elevato.
Poi ho analizzato il problema con attenzione, e il tutto è risultato fattibile abbastanza semplicemente, e, dopo questa lunga introduzione, vi spiego come ho fatto.
Configurazione di routing e firewall in uno XenServer
Tutta la configurazione ruota intorno a una serie di interfacce virtuali, costruite su un’unica interfaccia fisica. A questa interfaccia devono essere associati una serie di IP esterni, di cui il fornitore vi dota.
Non si deve chiedere alcun MAC address al provider (al contrario della soluzione standard).
Per cui:
Per mezzo della interfaccia grafica di xenserver delle network sul server
- Si associa alla NIC1 fisica l’indirizzo del server (5.5.5.5).
- Si associa alla NIC1 tutti gli indirizzi IP forniti dal provider (6.6.6.6)
- Si associa alla NIC1 una rete interna (es.172.16.10.254/24)
Per mezzo della configurazione degli IP si definisce per ogni interfaccia la sua maschera, il suo GW, che viene fornito dal provider per l’interfaccia fisica, e coincide con l’IP per le interfacce virtuali; la sua maschera, che per l’interfaccia fisica e’ fornito dal provider, e per l’interfaccia virtuale e’ /32. Per l’interfaccia interna non si fornisce alcun GW.
Le macchine virtuali interne hanno le interfacce che appartengono alla rete interna, e come GW la 172.16.10.254.
A questo punto i giochi sono fatti. Le interfacce virtuali esterne ricevono i pacchetti, che vengono ruotati sulla rete interna.
Faccio fin da subito presente che il livello di sicurezza non e’ lo stesso di una vera DMZ. In questo modello e’ presente una sola interfaccia fisica, e non viene fatto un reale routing fra interfacce. In effetti il routing e il NAT vengono definiti, come vedremo tra poco, ma, dato che il modello di switch utilizzato e’ un bridge, tutte le interfacce vedono tutto. Questo vuol dire che i pacchetti che ruotano sulla rete interna sono anche percepiti dalla rete esterna, per cui un ipotetico indirizzo IP 172.16.10.X associato ad una macchina sulla stessa rete esterna vedrebbe anche la mia rete interna; e questo non e’ il massimo per la sicurezza….
Nel mio caso tutte le macchine sono in produzione verso l’esterno, e non ho macchine interne, per cui posso accettare questo compromesso. Per chi avesse dei DB con dati importanti da proteggere, tenga presente che questo schema non garantisce alti livelli di sicurezza.
Dopo questa importante osservazione sulla sicurezza vediamo come configurare il NAT e il firewall del server server. Il routing nel voro senso della parola non viene fatto, dato che ho una sola interfaccia. Non è pertanto necessario attivare l’ip-forwarding a livello di kernel.
Ammettiamo di avere un indirizzo principale esterno 5.5.5.5, acceduto dalla gui del mio PC con il clint di xenserver, un indirizzo virtuale aggiuntivo esterno 6.6.6.6 e una rete interna 172.16.10.x , con indirizzo virtuale associato alla rete interna del server 172.16.10.254.
Esempi di configurazione del server sono i seguenti:
NAT IN uscita, dalla rete interna a quella esterna, che passa per l’indirizzo virtuale 6.6.6.6
iptables -t nat -A POSTROUTING -s 172.16.10.0/24 -j SNAT --to-source 6.6.6.6
NAT IN INGRESSO, una regola per ogni servizio. Qua si espone la porta 80 sulla interfaccia 6.6.6.6 e si ruota sull’IP interno 172.16.10.25:80
iptables -t nat -A PREROUTING -d 6.6.6.6/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.10.25:80
NAT IN INGRESSO, si espone la porta 234 e si mappa sulla porta 237 su un server interno
iptables -t nat -A PREROUTING -d 6.6.6.6/32 -p tcp -m tcp --dport 237 -j DNAT --to-destination 172.16.10.25:237
Eventuali regole di limitazione del traffico in NAT devono essere gestite dalla tabella FORWARD, e non dalla tabella INPUT ( il NAT non passa dalla tabella INPUT…)
In questo esempio viene droppato tutto quello che non arriva dall’indirizzo 9.9.9.9 verso lamacchina interna sulla porta 443
iptables -A FORWARD ! -s 9.9.9.9 -d 172.16.10.25 -p tcp -m tcp --dport 443 -j DROP
La manutenzione di queste regole e’ fondamentale per il funzionamento del sistema, ma si riesce, con un po’ di attenzione, ad avere un bel sistema, funzionante ed efficiente.
TAG: xenserver, rete, nat, bridge, switch, firewall