Aller au contenu | Aller au menu | Aller à la recherche

Déployer un firewall sous Xen pour ma soeur.....

Il y a quelques temps, j'ai commencé à faire mumuse avec la virtualisation (sous Xen), y compris pour un cas de figure un poil complexe sur lequel je n'avais trouvé aucune doc sur le net (si vous voulez juste déployer quelques VMs classiques dans un hyperviseur Xen, vous n'êtes pas au bon endroit, il existe plein de tutoriels pour ce cas de figure basique).

Ca tombe bien, vu que je n'avais pas fait de nouveau billet aujourd'hui cette semaine ces derniers temps depuis au moins un an, et comme j'ai quelques potes qui envisagent de faire une conf similaire, c'est un prétexte que je ne pouvais pas louper.

En plus, ca me servira aussi probablement le jour ou mon disque dur va me lâcher et que je vais devoir tout refaire.......


Disclaimer

Attention: contrairement à ce que le titre pourrait laisser croire, ce billet contient de nombreux extraits naturels de trucs techniques plus ou moins compliqués. En particulier, des connaissances de base en virtualisation sont à peu près indispensables, et une expérience de Xen en particulier est vivement souhaitée.

En cas de dépressurisation cérébrale suite à la lecture de ce billet, des masques à oxygène ne tomberont probablement pas automatiquement du plafond. Vous êtes invités à repérer à l'avance les issues de secours, qui ne seront probablement pas non plus indiquées par des consignes lumineuses en cas d'incident.

Les actions décrites ci-après ont été réalisées par un Vieux Con de Hacker Old School (tm), qui porte des t-shirts de geek, qui va généralement plus vite en utilisant un shell ou emacs qu'avec une interface graphique, un gars qui a survécu à la Grande Guerre (entre l'Amiga et l'Atari ST), tout ça....

Et bien évidemment, tout a été réalisé dans des conditions optimales de sécurité, avec un bouton rouge, une équipe d'intervention d'urgence prête à réagir à tout moment, 8 litres de coca (note pour moi même: en rester là, j'ai déjà fait la reprise de la blague de Naheulbeuk avec la liste de courses.....), et un vrai réseau de prod à coté pendant toute la durée de l'opération.

Donc les enfants, NE FAITES SURTOUT PAS CA CHEZ VOUS, et si vous le faites quand même (bah oui, on ne va pas se mentir: dire à quelqu'un "ne fais surtout pas ça", c'est quand même un excellent moyen de l'inciter à le faire, juste pour voir.....), vous serez seul(e) responsable de toute conséquence dramatique qui en découlerait, comme une instabilité réseau, la perte de données, la création d'une brêche dans le continuum spatio-temporel, le départ de votre copine, un contrôle fiscal, l'arrivée de votre belle mère, une halitose subite, ou tout autre désagrément non listé ci-dessus.
Notez cependant que, à l'exception d'une légère instabilité réseau lors de la première mise en prod, aucun des autres symptômes cités en exemple n'est survenu lors de ma mise en prod !

Ah, et aucun animal mignon n'a été blessé, tué ou mangé pendant l'intervention.


Ok, et on voulait pas faire un vrai truc, à un moment ?

Ne soyez pas impatients, comme ça, si, effectivement, on voulait faire un vrai truc, que j'ai essayé de transcrire en un (magnifique, je sais) schema (cliquez dessus pour l'agrandir):

SchemaReseauDom0


En admettant que vous n'ayez pas tout à fait compris la configuration, malgré la profusion de couleurs et mon extraordinaire maîtrise de l'outil de création du truc, l'idée est donc, comme le titre du billet le suggérait quand même déjà relativement clairement, de déployer un firewall virtuel (ais-je vraiment besoin de préciser la marque du firewall dans mon cas ???) dans un hyperviseur Xen.

Ce qui pourrait paraître relativement classique (un hyperviseur, une VM, du réseau) pose cependant une problématique particulière dans mon cas: je veux pouvoir gérer à ma convenance un ou plusieurs bridges au niveau du firewall (donc avec filtrage, IPS, tout ça...), sans devoir faire de modifications de configuration sur le Dom0 à chaque fois, et évidemment sans perturbations par le Dom0, sans paquets qui passent discrètement d'une interface physique une autre en glissant un petit biffeton à l'hyperviseur, ou autres trucs pas recommandables dans un réseau de bonne famille et propre sur lui.

Dit autrement, tout doit réagir exactement comme si les interfaces réseau physiques étaient directement reliées au firewall.

Et, accessoirement, si ça peut fonctionner, c'est mieux, y compris avec d'autres VMs sur le même hyperviseur, également branchées sur des interfaces dédiées du firewall.

Dans tout le reste de l'explication, on considèrera 8 interfaces pour le firewall, dont 4 reliées à des interfaces physiques, si votre configuration est différente, l'idée reste la même, il suffit d'adapter....


Autres solutions possibles


Un autre hyperviseur

Euh, oui, on aurait pu, effectivement..... mais en gros, VMWare n'est pas OpenSource, Xen est officiellement supporté par ma VM de firewall (ok, la version commerciale, mais dans les faits, je sais que ça fonctionne bien), et aucune autre solution de virtualisation ne m'a paru avoir le "truc en plus" qui aurait justifié le changement de techno.

Et j'en vois deux dans le fond qui auraient de toutes façons fait la remarque "mais y'avait d'autres solutions" si j'en avais choisi une autre.....


OpenVSwitch

Pour la configuration réseau au niveau de l'hyperviseur, j'ai utilisé les bridges Linux (brctl, tout ça.....).
On aurait pu également utiliser OpenVSwitch, j'ai le souvenir d'avoir un peu regardé cette solution, et de l'avoir mise de coté pour une bonne raison à l'époque...... bonne raison dont je ne me souviens plus, évidemment....

Il est également possible que cette bonne raison soit devenue obsolète depuis.


Un firewall physique

Euh, oui, on peut, mais c'est pas écolo, c'est pas tendance (virtualisation, nuages, blabla.....), et c'est un peu trop facile pour être fun.
Accessoirement, ca ne répond pas non plus au cas de figure "autres VMs à filtrer via le firewall", en tout cas pas simplement, si j'ai plusieurs VMs que je veux segmenter entre elles.


Passer directement les interfaces réseau à la VM

Sur le papier (enfin, sur le site web, ne commencez pas à pinailler comme ça), Xen sait faire, ca s'appelle le PCI Passthrough.
Et c'est fort logiquement la première option que j'avais étudié quand j'ai commencé à bricoler ma configuration.

Sauf que, dans les faits, ca n'est pas aussi simple, il faut déjà avoir une carte mère qui supporte l'IOMMU, ce qui n'était pas mon cas.
Si la carte mère de votre Dom0 le supporte, cependant, c'est probablement une possibilité intéressante à tester !

Et cette solution ne gère pas le branchement entre le firewall et d'autres machines virtuelles, donc ne serait applicable que pour les interfaces physiques.


DomO, VM, etc...


Installation de l'hyperviseur Xen

L'installation de base est une procédure relativement simple, et allègrement documentée sur le net.

Dans notre exemple, il s'agira d'une Debian, je ne vous ferai pas l'affront d'expliquer ici comment on installe une Debian de base, et la mise en place de l'hyperviseur Xen est également documentée sur le wiki Debian sur Xen (n'allez pas trop loin dans les manips du wiki, en particulier pour tout ce qui est configuration réseau, c'est pour le cas "classique").

Note: il existe plusieurs facades pour configurer/administrer un Xen. J'étais parti pour une administration avec le toolstack Xl, mais j'ai eu divers problèmes avec, entre autres à cause de la version de Xen fournie par ma Debian. Je me suis donc rabattu sur le toolstack xm, raison pour laquelle les exemples de configuration seront fournis sous ce format.

Cependant, xm/xend est marqué DEPRECATED, il est donc préférable de convertir les configurations au format xl si vous utilisez une version récente de Xen.


Préparation et configuration de la VM Firewall

Dans mon cas, la VM Firewall fait tourner un dérivé de FreeBSD, ce qui nécessite une configuration un poil différente pour le démarrage:

name = "Firewall"

kernel = "/usr/lib/xen-4.1/boot/hvmloader"
builder = 'hvm'

vcpus = 1
maxvcpus = 1
cpu_weight = 512

memory = 1024
maxmem = 1024

#on_poweroff = "restart"
on_watchdog = "restart"
on_crash = "restart"
on_reboot = "restart"

serial = 'pty'

disk = [ 'file:/home/Xen/Firewall.img,hda,w' ]

Pour l'essentiel, cependant, cette partie de la configuration est très classique (vous penserez à mettre à jour le chemin de la ligne kernel, si votre version de Xen est différente, évidemment.....), je lui réserve 1 VCPU et 1Go de RAM dans mon cas, et comme c'est un firewall, je décrète que presque tous les cas d'arrêt de la VM nécessitent un redémarrage (sauf un arrêt explicite et volontaire).

Le serial='pty' me permettra également d'avoir un accès facile à la console de ma VM depuis un shell de l'hyperviseur en cas de soucis (note pour moi: KernelMsg=1). Selon votre VM firewall, la méthode sera peut être différente.


Configuration réseau


A un moment, on veut faire des trucs pour le réseau, il va bien falloir le configurer.....

Configuration du Dom0

D'un point de vue Dom0, on va créer plein de bridges à 2 interfaces: un pour chaque interface physique du Dom0 (à chaque fois couplé à une interface du firewall), et un pour chaque autre VM (ou éventuellement groupe de VMs) présente dans l'hyperviseur.
Il faut donc installer le package bridge-utils:

apt-get install bridge-utils

Les interfaces du Dom0 n'auront pas d'adresse IP (les bridges non plus, d'ailleurs), il va donc falloir forcer leur activation manuellement.
Dans /etc/network/interfaces, pour une interface physique ethx donnée, on aura donc:

auto ethx
auto brx

iface ethx inet manual

iface brx inet manual
       bridge_ports ethx

Dans le cas d'un bridge non relié à une interface physique, la seule différence est qu'on indiquera:

      bridge_ports none

(vous aurez la présence d'esprit de remplacer à chaque fois x par le numéro de l'interface, ça reste valable dans toute la suite de l'explication)

Notez que vous pouvez à priori remplacer "inet" par "inet6", pour faire tendance, ce qui ne devrait absolument rien changer: il ne s'agit pas ici de configurer des interfaces, mais juste de les activer et de les relier à des bridges qu'on crée au passage.
Selon le niveau de support et de configuration d'IPv6 par votre VM firewall, il sera peut être nécessaire de désactiver pas mal de choses au niveau IPv6 sur votre Dom0, y compris (surtout ?) les adresses Lien Local (celles en fe80::), ce qui vous évitera des boucles réseau étranges en IPv6...

Pour pouvoir accéder au Dom0 depuis le réseau, une interface aura un status un peu particulier: elle aura une adresse IP, la veinarde !
Enfin, plus précisément, le bridge sur lequel elle est attachée aura une IP, puisque c'est le fonctionnement normal sous Linux: une interface reliée à un bridge n'est plus utilisable directement.

Par rapport aux autres bridges, tout simplement, on va remplacer "inet manual" par "inet static" (et/ou par inet6 static si vous êtes tendance), et rajouter address, netmask, gateway (l'IP du firewall sur le LAN, en configuration finale, l'IP de votre passerelle actuelle pendant la préparation). Une configuration type DHCP, autoconf en v6 ou autre est à éviter: votre Dom0 démarrera logiquement avant tout le reste, y compris le firewall (bah oui, logique....), et ne saura donc peut être pas accéder à un serveur DHCP...
J'ai également du forcer son adresse MAC (hwaddress, j'ai mis l'adresse MAC de l'interface physique), vous verrez pourquoi après.

Idéalement, si votre niveau de parano est assez élevé (et surtout si vous avez un moyen assez facile d'accéder à votre Dom0 en console en cas de problèmes), dans la configuration finale, ce bridge sera reliée à une interface dédiée de la VM firewall (et donc à aucune interface physique).

  • avantage: permet de filtrer et protéger le Dom0
  • inconvénient: en cas de problème avec la VM firewall (erreur de configuration, reboot, mauvaise manip, etc...), la console sera le seul recours !

Une interface physique dédiée (et toujours reliée à une interface dédiée du firewall) vous permettra de venir brancher en urgence un ordinateur portable pour réparer d'éventuels problèmes, tout en bénéficiant de la même protection par le firewall en usage normal.

A défaut, si vous ne laissez pas n'importe qui se brancher sur votre LAN, et si vous mettez en place un filtrage au niveau du Dom0 n'autorisant que les accès ssh vers celui-ci (en certificats uniquement, évidemment), le niveau de sécurité restera tout à fait correct, et permettra une intervention simplifiée en cas de soucis.

Si vous êtes vraiment cool et partageur, un accès telnet en openbar sur une IP publique (et sans mot de passe pour root, on ne va pas commencer avec des mesquineries du genre) fera probablement plein d'heureux sur le net......

Selon votre topologie réseau, vous serez peut être amenés à configurer ainsi plusieurs interfaces/bridges sur le Dom0 (si vous avez plusieurs plans d'adressages qui peuvent servir à administrer en urgence), il suffira de reproduire la même idée pour chacune de ces interfaces.


Configuration réseau de la VM Firewall

Pour notre VM, nous utiliserons donc le script vif-bridge, ce qui donne dans la configuration de la VM firewall, pour la partie réseau:

vif = [
       'bridge=br0,model=e1000,mac=00:16:3e:xx:0',
       'bridge=br1,model=e1000,mac=00:16:3e:xx:1',
       'bridge=br2,model=e1000,mac=00:16:3e:xx:2',
       'bridge=br3,model=e1000,mac=00:16:3e:xx:3',
       'bridge=br4,model=e1000,mac=00:16:3e:xx:4',
       'bridge=br5,model=e1000,mac=00:16:3e:xx:5',
       'bridge=br6,model=e1000,mac=00:16:3e:xx:6',
       'bridge=br7,model=e1000,mac=00:16:3e:xx:7',
    ]

Ici, on force le type d'interface à e1000 (le type par défaut était moins performant au niveau de la VM, de mémoire), et on va également forcer les adresses MAC pour éviter d'avoir un bordel ambiant à chaque redémarrage de la VM. Le préfixe 00:16:3e est réservé pour Xen, ce qui évitera des collisions avec d'autres cartes ethernet du réseau, vous mettez ce que vous voulez à la place de :xx: (qui est d'ailleurs :xx:xx:, vu qu'une adresse MAC est codée sur 6 octets), et tant qu'à faire, on va numéroter le dernier octet dans l'ordre pour faire propre.


Bricolage et magie noire sur le Dom0

Si toutes vos interfaces ont des plans d'adressages différents, cette configuration devrait presque suffire à faire fonctionner le truc.
Sauf que, dans mon cas, je veux pouvoir gérer des bridges au niveau du firewall, et c'est là que ca devient poilu, vu que, en l'état, ça ne fonctionnera pas (ou en tout cas pas correctement).


Gestion des paquets entrants

Le premier problème, c'est que les interfaces du Dom0 n'accepteront pas les paquets à destination d'autres adresses MAC (ou en tout cas pas toujours, selon la configuration de plein de trucs). Il faut donc forcer toutes les interfaces avec l'adresse MAC de broadcast.

Nous allons donc rajouter la ligne suivante dans la configuration de toutes les ethx:

up /sbin/ifconfig ethx -arp hw ether fe:ff:ff:ff:ff:ff

Pareil pour les bridges, sauf qu'il est nécessaire de le faire en post-up (en phase "up", apparemment, le bridge n'existe pas encore assez pour l'opération):

post-up /sbin/ifconfig brx -arp hw ether fe:ff:ff:ff:ff:ff

C'est à ce moment que l'intérêt de forcer l'adresse MAC de l'interface d'administration apparaît....
Maintenant que j'y repense, je me rends également compte que, sur cette interface, l'option hwaddress fonctionne très bien, y compris sur une interface de type bridge...... je n'ai pas fait le test (j'étais déjà en prod quand j'y ai pensé), mais l'option devrait aussi logiquement fonctionner ici, pour les eth comme pour les br:

iface <un ethx ou un brx> inet manual
    hwaddress fe:ff:ff:ff:ff:ff
    bridge_ports ethx # seulement pour les interfaces brx


Bypass de netfilter

Le second obstacle, c'est que tous les paquets passent par le Netfilter du Dom0, qui peut donc les bloquer, les router, ou faire d'autres choses avec, que la morale n'approuve pas forcément...
Nous allons donc indiquer au système que les paquets qui passent sur un bridge ont une bouteille à l'intérieur, connaissent bien le patron, et seront gérés par le service de sécurité de la salle VIP s'ils ont des baskets ou une casquette.
Ca se fait en ajoutant à /etc/sysctl.conf:

net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0

Activez à la main ces sysctl si vous voulez économiser un reboot.


Accélération du démarrage

A un moment, vous remarquerez que le démarrage du Dom0 est très long, curieusement depuis qu'on a modifié la configuration réseau pour rajouter tous les bridges....
Pour revenir à une vitesse de démarrage normale, il suffit d'ajouter les paramètres suivantes dans chaque section brx du fichier /etc/network/interfaces:

       bridge_stp off
       bridge_waitport 0
       bridge_fd 0

Evidemment, si vous avez un réseau avec plein de boucles, désactiver le protocole STP partout est probablement une très très mauvaise idée.....


Amélioration des performances

A ce moment, votre configuration devrait fonctionner, mais avec des performances réseau complètement pourries dès que ça traverse le firewall, voire des sessions TCP qui ne finissent jamais vraiment.

Une enquête approfondie réalisée conjointement entre Les Experts et NCIS révèle des trucs très étranges sur le réseau, dont par exemple des paquets qui dépassent allègrement la MTU, voire qui arrivent plus gros qu'ils ne sont partis.

Le grand méchant de cette histoire est finalement l'accélération matérielle des cartes réseau, en particulier la segmentation déportée des gros paquets et/ou le déport des sommes de contrôle.
Votre moteur de recherche préféré vous confirmera rapidement que ces trucs là ne font pas forcément bon ménage avec la virtualisation, en tout cas sous Xen, en tout cas aujourd'hui.

Nous allons donc désactiver tout ça sur les interfaces vif (le pendant sur le Dom0 des interfaces des VMs), à l'aide de la commande ethtool (donc oui, apt-get install ethtool).
Au passage, tant qu'on est là et qu'on parle de performances, réseau, on va également augmenter la taille de la file d'attente des interfaces vif, qui est à une valeur très faible par défaut.

Pour que les modifications soient faites automagiquement à chaque création d'interface vif, nous allons donc modifier le script /etc/xen/scripts/vif-bridge:

[....]
case "$command" in
   online)
       setup_virtual_bridge_port "$dev"
       mtu="`ip link show $bridge | awk '/mtu/ { print $5 }'`"
       if [ -n "$mtu" ] && [ "$mtu" -gt 0 ]
       then
               ip link set $dev mtu $mtu || :
       fi
       add_to_bridge "$bridge" "$dev"
       ;;

devient:

[....]
case "$command" in
   online)
       setup_virtual_bridge_port "$dev"
       mtu="`ip link show $bridge | awk '/mtu/ { print $5 }'`"
       if [ -n "$mtu" ] && [ "$mtu" -gt 0 ]
       then
               ip link set $dev mtu $mtu || :
       fi
       ethtool -K "$dev" tso off gso off gro off tx off rx off
       ifconfig "$dev" txqueuelen 1024
       add_to_bridge "$bridge" "$dev"
       ;;

Sur ma configuration, ces deux petites lignes permettront de faire passer le débit de "3-4 Mb/s quand ça fonctionne" à "environ 400Mb/s et ça fonctionne tout le temps", ce qui est quand même assez appréciable (c'est apparemment la limite de mon serveur de fichier qui commence à se faire vieux), il faut bien le reconnaître, et sans aucune substance illégale, en plus !

Il sera probablement nécessaire de désactiver les mêmes fonctions au niveau de votre VM firewall, si celle-ci ne le fait pas automatiquement. Dans mon cas, c'est fait nativement.

En théorie, sur un réseau Gb, on gagnerait encore en performances en utilisant des jumbo frames, sauf que, toujours sur ma version actuelle de Xen, le support des jumbo frames est expérimental....


Configuration réseau finale du Dom0

Pour résumer la configuration finale (oui, j'aurais pu directement vous donner cette configuration, mais l'intensité narrative y aurait perdu, et je me trouve à vrai dire déjà assez sympa comme ça de vous faire un résumé) de /etc/network/interfaces va donner, pour une interface ethx (oui, vous ferez à nouveau l'effort de remplacer x par le bon numéro, et de faire la conf pour chaque interface):

auto ethx brx

iface ethx inet manual
       hwaddress fe:ff:ff:ff:ff:ff

iface brx inet manual
       bridge_ports ethx
       bridge_stp off
       bridge_waitport 0
       bridge_fd 0
       hwaddress fe:ff:ff:ff:ff:ff

Et vous mettrez "bridge_ports none" au lieu de "bridge_ports ethx" pour les bridges non reliés à une interface physique, et vous ferez la modification de configuration qui va bien pour le bridge qui aura une adresse IP.


Configuration réseau de la VM

A partir de là, c'est un fonctionnement et une configuration normales au niveau de la VM firewall. Dans mon cas, j'ai une interface externe sur un plan d'adressage dédié (zone encadrée en rouge sur le schéma du début), et toutes les autres interfaces du firewall (chacun encadré en bleu sur le même schéma) sont mises dans un bridge commun (au niveau du firewall, donc).

Il reste à faire la configuration réseau de la VM, les règles de filtrage, la configuration IPS, le NAT, et tout ce qui est à configurer lors d'un déploiement de firewall.


D'autres VMs pendant qu'on y est...

A partir de ce moment, installer d'autres VMs sur l'hyperviseur est une activité classique:
On récupère de quoi faire une install, comme par exemple l'image ISO Debian pour une installation de DomU, on fait "ce qu'il faut" pour avoir un espace disque (dans mon cas, donc, qemu-img create, mais il parait que c'est plus tendance d'utiliser lvm), et on lance l'install en suivant un tutoriel classique d'installation de VM pour Xen.

Pour les archives, je rajoute à la configuration Xen de cette VM:

 extra = "console=hvc0"

Cette commande me permettra d'accéder à la console de la VM depuis un shell de l'hyperviseur (il me semble qu'il fallait aussi faire une modif dans la conf grub de la VM......).

La seule subtilité de notre configuration par rapport aux tutoriels standards est fort logiquement au niveau de la configuration réseau. Si on veut relier la VM à l'interface x du firewall (et comme on a fait un numérotage propre et homogène sur toute la ligne), on aura:

vif = [
       'bridge=brx,model=e1000,mac=00:16:3e:<de l'hexa>'
    ]

I am the king of the wooooorld !!!

Bon, ok, du monde, peut être pas, mais de mon hyperviseur et de ma VM firewall, en tout cas, oui, du moins tant que je conserve des mots de passe et une configuration de filtrage corrects.

Ca n'est pas forcément hyper efficace pour pecho en boite, et c'est déjà parfois assez limite comme sujet de discussion quand des amis passent à la maison et demandent naivement "quoi de neuf".
Ca pourrait faire le café, mais comme je n'en bois pas, je n'ai pas testé.

Mais au moins, ca permet d'avoir un firewall/IPS/UTM qui protège le réseau physique ET les machines virtuelles, tout en conservant une quantité de serveurs limitée, et si vous relisez bien le début du post, je n'avais pas promis plus !

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

Fil des commentaires de ce billet