Maugan V.
Maugan V. Maugan V. est de la promotion 2024 d'Epitech (Lyon). Il est passionné par le hardware et la programmation bas niveau

Machines virtuelles et contenaires : comment créer ses propres serveurs from scratch?

Machines virtuelles et contenaires : comment créer ses propres serveurs from scratch?

Durant mon temps libre, j’ai eu besoin de mettre en place des machines linux pour différentes raisons :

  • Faire des essais de nouvelles technologies pour ma satisfaction personnelle.
  • Exposer des services qui me sont utiles (serveur web, serveur de jeu, VPN1, stockage de fichiers, etc)
  • Avoir un environnement de tests pour ensuite déployer des services chez d’autres personnes.

À mes débuts, je ne pouvais pas juste louer un serveur pour des raisons de moyens de paiement. Du coup, passionné, je récupérais du matériel (et je continue).

Je prenais donc un vieil ordinateur récupéré et remis en état, le reformatais pour ensuite installer un OS2 et faire mes tests. Mais au fur et à mesure du temps j’ai trouvé cette “logistique” fatigante :

  • Chercher une machine
  • Vérifier le fonctionnement et la compatibilité des composants
  • Chercher un écran et un clavier
  • Tendre un câble ethernet
  • Réinstaller un OS
  • Installer et configurer l’OS et les services dessus

Aussi en cas de besoin d’exposer plusieurs services, je n’avais pas envie de tout mettre sur un même serveur, sans rien diviser pour des raisons de sécurité entre autres.

Seulement, n’ayant pas un énorme switch3 – ni de câbles ethernet, ni beaucoup de prises électriques, ni une volonté de consommer beaucoup trop de courant – maintenir en fonctionnement beaucoup de matériels de récupération, anciens, pas forcément le plus fiable, n’était pas une option.

Me retrouvant limité, j’ai pensé à plusieurs solutions : la virtualisation et les containers. J’ai opté pour les deux solutions à des niveaux différents, comme nous le verrons par la suite.

Architecture

Donc voici les spécifications de la machine de récupération utilisée que j’avais sous la main :

  • CPU4 : Athlon II x2 255 3.1GHz de 2010
  • RAM5 : 8GB
  • Carte Réseau : gigabit ethernet intégrée à la carte mère
  • Stockage : HDD6 de 512GB.

Ce n’est pas très puissant, mais je n’avais pas besoin de beaucoup de puissance et surtout, c’est ce que j’avais sous la main. Mais si vous souhaitez le refaire avec du meilleur matériel c’est parfait. Vérifiez toujours que votre CPU supporte la virtualisation et qu’elle est activée dans le bios7.

Voici donc comment j’ai architecturé mon projet :
schema illustration

Au départ je souhaitais me servir des services de ma box8 comme le NAT, le firewall9 intégré, etc. J’ai donc configuré l’hôte pour que les machines virtuelles soient sur le réseau local, pour expérimenter et faire mes services privés (envie de domotique dans le futur) accessibles en LAN10.

L’idée était donc de me servir du NAT11 de la box pour les rares services exposés.

Sauf que ma box actuelle est si mauvaise qu’elle arrive pas à enregistrer les paramètres nat entre autres. Heureusement la fonctionnalité DMZ “marche”, enfin comme le font certains ISP avec leur box, pas une vraie DMZ avec un second sous réseau, ni même un vlan12, mais juste de quoi refiler tout le trafic à une machine du réseau locale – une vraie passoire si la machine exposée n’a pas un firewall bien configuré.

Comme on peut le voir sur l’image, j’ai donc mis une machine virtuelle dédiée au firewall et c’est elle qui est en front (sur l’extérieur) avec un firewall et qui fait les bonnes redirections vers les autres machines virtuelles du LAN qui leur permettront d’exposer leurs services. En fait c’est du NAT également.

Cette architecture possède des défauts que j’exposerai de façon non exhaustive à la fin de cet article. Je parlerai également de ce que je souhaite changer ou améliorer.

Choix du système hôte

J’ai donc eu besoin d’un hyperviseur13. Étant assez porté sur l’OpenSource, j’ai écarté VMWare. Par ailleurs, je ne suis même pas sûr que mon matériel l’aurait supporté. J’ai fini par chercher une solution faite sur une distribution linux.

Proxmox est vraiment une solution pratique, mais j’avais aussi envie de tout faire par moi-même. J’avais certes un besoin, mais aussi une envie d’apprendre des choses.

J’ai fini par choisir centos 8 dont l’annonce du raccourcissement de la durée de vie n’avait pas encore été faite au moment où j’ai monté ce serveur. Je compte m’occuper de ce problème, comme vous le verrez à la fin avec les améliorations à venir.

Du coup voici les raisons pour lesquelles j’avais choisis centos :

  • Clone de RHEL
  • Stabilité
  • Fiabilité
  • Support 10 ans avec mises à jour de sécurités régulières
  • Groupes de paquets, fonctionnalité équivalente aux méta-paquets debian
  • Documentation redhat parfaitement adaptée.

Pour la virtualisation, j’ai donc choisi qemu-kvm avec libvirt. C’est performant, c’est très utilisé, parmi les mieux intégrés à linux, et cette solution étant conseillée et détaillée dans la documentation redhat, c’est un plus.

Configuration de l’hôte

Dans un premier temps, nous devons installer la solution de virtualisation. Si vous installez centos spécifiquement pour ça, vous pouvez selectionner le groupe de virtualisation dans la selection des paquets à installer. Si vous avez déjà installé centos, vous pouvez installer le groupe de virtualisation avec

1
dnf groupinstall "Virtualization Host"   

Ça installe libvirt, qemu, et tous les outils dont nous aurons besoin.
J’ai également installé ovmf pour pouvoir faire des vm en uefi14.

1
dnf install edk2-ovmf   

Ensuite, normalement tuned-adm est préinstallé sur centos, sinon vous pouvez l’installer avec

1
dnf install tuned && systemctl enable --now tuned   

Enfin selectionnant le profil de performance dédié à la virtualisation avec

1
tuned-adm profile virtual-host && tuned-adm active   

Pour être sur que le service libvirt est activé, nous allons activer et lancer le service

1
systemctl enable --now libvirtd   

Ensuite nous allons configurer le réseau de l’hôte. Pour que les machines virtuelles soient sur le LAN, nous allons créer un bridge15 virtuel. Pour ça il y a deux méthodes : la méthode avec le xml de libvirt et la méthode externe. Pour ma part, j’ai choisi la méthode externe avec networkmanager et en particulier, nmcli. J’ai donc créé un bridge virtuel :

1
nmcli con add ifname br0 type bridge con-name br0

Et ensuite pour que mon hôte puisse être considéré comme connecté au bridge et avoir accès à internet par la même interface, je passe l’interface hôte, ici eth016, en slave de ce bridge :

1
nmcli con add type bridge-slave ifname eth0 master br0

Enfin, avoir une addresse ip statique pour la connection à l’hôte est quand même très pratique, du coup, pour l’ipv417 :

1
2
3
nmcli con mod br0 ipv4.addresses 192.168.0.100/24
nmcli con mod br0 ipv4.gateway 192.168.0.1
nmcli con mod br0 ipv4.method manual

Vous pouvez faire la même chose pour l’ipv618, pour ma part, ma box ne supporte pas l’ipv6. Enfin, nous pouvons activer cette interface :

1
nmcli con up br0

Enfin nous allons configurer le firewall de l’hôte. Étant sous centos, avec firewalld d’installé, c’est plutôt simple et fiable de suivre le principe des zones. Vous pouvez lister les zones et leurs détails avec :

1
firewall-cmd --list-all-zones

N’ayant besoin que du ssh19, la zone publique me convenait, et j’ai donc choisi public comme zone par défaut. La zone libvirt convient aussi.

1
firewall-cmd --set-default-zone=public

Vous pouvez aussi spécifier l’addon’ que vous souhaitez par interface, et également modifier ou ajouter des zones custom, et ajouter des règles. En fait firewalld est un frontend simplifié de nftables, un firewall très utilisé sous linux. Ici je n’en parlerais pas plus car ce n’est pas l’objet de cet article. Normalement, maintenant, nous avons une centos prête à héberger des vm.

Firewall et DMZ

Nous allons maintenant monter la machine virtuelle qui va me servir de firewall. J’ai choisi alpine linux20 pour sa légèreté, sa sécurité et sa faible consommation de ressources. J’ai donc téléchargé la dernière iso21 sur le site officiel de alpine linux sur le disque du serveur, et avec

1
osinfo-query os

j’ai pu récupérer le short-id de l’OS que je veux installer.

Cela va me permettre de créer une machine virtuelle avec la commande suivante.

1
virt-install --boot uefi --machine q35 --name fw-1 --memory 128 --vcpus 1 --disk bus=virtio,size=16 --network bridge=br0,model=virtio --OS-variant alpinelinux3.13 --cdrom alpine-virt-3.13.5-x86_64.iso --graphics none

Cette commande est pour lancer la procédure d’installation dans un terminal, sans interface graphique, il est aussi possible de passer par du vnc22, pour des distributions avec installateurs graphiques. D’autres détails peuvent varier selon l’OS à virtualiser, et la façon de l’installer.

Par exemple ici j’ai choisis 128MB de ram car j’ai pas besoin de beaucoup de RAM pour la gestion du réseau, et que alpine fonctionne très bien avec 128MB.
Également ça me permet de garder la majorité de la RAM restante pour mes services. Aussi remarquer bridge=br0, pour que les machines virtuelles se connectent au bridge établi préalablement.

Ensuite, j’ai lancé la procédure d’installation de alpine linux avec un serveur openssh23 et une ip fixe, ici 192.168.0.101, puis je me suis connecté en ssh, car c’est plus pratique. La configuration du serveur ssh est hors de la portée de cet article.

Pour que la machine virtuelle redémarre toute seule si l’hyperviseur redémarre :

1
virsh autostart fw-1

La suite de l’article porte sur l’architecture pour des services publiques, créer des machines virtuelles suffisent en LAN pour des services privés. La suite de l’article est faite pour l’exposition de services externes. Les commandes suivantes se feront sur la machine virtuelle qui sera utilisée comme firewall.

Configuration basique du firewall sur la machine virtuelle

Pour gérer le firewall, j’ai décidé d’utiliser nftables.
Il a donc fallu l’installer.

1
apk add nftables

Pour pouvoir le configurer il faut lancer le service. Ces étapes sont relativement “critiques”, dans le sens où il y a un risque de s’enfermer dehors.

C’est pourquoi dans un premier temps on va directement autoriser le ssh dès le lancement du service. La configuration alpine par default est plutôt bien faite avec les bonnes règles pour l’ICMP (également cette configuration par défault fait que si on n’autorise pas de nouvelles connexions, les connexions existantes – comme celles utilisées pour la configuration – ne sont pas éjectées, donc on a la possibilité d’autoriser le ssh pour éviter de s’enfermer dehors)

1
2
rc-service nftables start
nft add rule inet filter input tcp dport 22 accept

Pour voir la configuration vous pouvez faire

1
nft -a list ruleset

Tant que vous ne sauvegardez pas, relancer le service suffit à revenir aux paramètres précédents. Evidemment, il est possible d’enlever des règles facilement, mais cet article n’a pas vocation à être une documentation de nftables. Quand vous sauvegardez soyez bien sûr que votre configuration ne vous enferme pas dehors. Pour sauvegarder :

1
rc-service nftables save

Et enfin pour faire en sorte que le service puisse se relancer au redémarrage de la machine virtuelle.

1
rc-update add nftables default

Configuration plus avancée du firewall sur la machine virtuelle

IP forwarding

Pour autoriser le forwarding24, il faut le permettre au niveau du kernel, c’est possible via des réglages avec sysctl25.
Éditez /etc/sysctl.conf, et ajoutez à la fin

1
2
3
4
5
# Pour l'ipv4
net.ipv4.ip_forward=1
# Pour l'ipv6
net.ipv6.conf.default.forwarding=1
net.ipv6.conf.all.forwarding=1

Et ensuite

1
sysctl -p

Pour vérifier que c’est bien appliqué, (par exemple pour l’ipv4) n’hésitez pas à faire

1
sysctl net.ipv4.ip_forward

et à regarder si le retour est bien 1.

Maintenant nous allons activer le forwarding dans nftables en modifiant la chaine forwarding

1
nft 'add chain inet filter forward { policy accept; }'

Mise en place du NAT

Nous allons créer la table et les chaînes du NAT.

1
2
3
nft add table nat
nft 'add chain nat prerouting { type nat hook prerouting priority -100; }'
nft 'add chain nat postrouting { type nat hook postrouting priority 100; }'

En postrouting, nous allons faire du masquerading

1
nft add rule nat postrouting masquerade

Scénario d’exposition d’un service public

Maintenant que nous avons notre firewall prêt, supposons que nous avons sur une machine du réseau local en 192.168.0.102 avec un serveur web à exposer en 80 et 443.

Le prerouting va permettre de rediriger le trafic avant de se frotter aux barrières de la chaine input. Pour plus d’informations, voir la documentation nftables par rapport aux priorités. Pour cela on prend l’interface d’entrée du trafic, ici eth0, et

1
2
nft add rule nat prerouting iif "eth0" tcp dport 80 dnat to 192.168.0.102
nft add rule nat prerouting iif "eth0" tcp dport 443 dnat to 192.168.0.102

Ça redirige tout le trafic qui arrive sur l’interface eth0 en tcp et sur les ports et 80 et 443, vers la machine virtuelle hébergeant le serveur web qui lui répond au firewall qui va faire le masquerading pour pouvoir répondre à la requête à la vraie personne.

Evidemment une fois toutes les actions faites, ne pas oublier de sauvegarder la configuration

1
rc-service nftables save

Configuration de la box pour la DMZ

Je ne peux pas vous aider la dessus car ça dépend des box et opérateurs, mais l’idée c’est de mettre la machine virtuelle faisant office de firewall (dans l’exemple ici, son ip était 192.168.0.101) en DMZ via les paramètres de votre box.

Conclusion et améliorations à venir

Voici les principaux défauts de cette configuration :

  • Tout est dans mon LAN, donc si un service se fait pirater, il a accès à tout le LAN.
  • J’aurais besoin du contrôle de ma box pour faire une vraie DMZ isolée par vlan ou second réseau

Voici des réflexions un peu fouillies que j’ai eues pour parvenir à une meilleure solution:

  • Je ne peux pas changer ma box, pour des raisons de résidences.
  • Je souhaitais me servir des services de la box mais c’est une erreur vu sa médiocrité.
  • Autre possibilité, configurer le bridge virtuel sur l’hôte pour faire un vlan (aucune idée pour le moment de comment m’y prendre), pour que les vm exposées n’aient le droit de communiquer qu’entre elles et avec le monde extérieur mais pas avec le reste du LAN.
  • Ajouter une carte réseau pour conserver un bridge actuel pour les services du réseau local uniquement
  • Faire du routage sur une seconde carte réseau vers un réseau de vms (aucune idée de comment m’y prendre)
  • Faire un réseau entre les vm depuis la vm firewall, mais ce n’est pas trivial car c’est virtuel

Je continue d’apprendre et tout n’est pas forcement juste, et serai heureux d’avoir des suggestions pertinentes par des personnes plus compétantes.
Ce sont des sujets relativement compliqués en réseau si on est pas technicien réseau de formation.
C’est loin d’être aussi trivial que ça puisse paraître, en pratique, les fournisseurs cloud, de serveur et de vps, vous donnent des machines “déjà câblées”.

Mon envie à l’avenir avec ce serveur :

  • Mettre un nouvel OS car le support de centos 8 a été raccourci (debian 11 ? rocky linux 8 ?)
  • Mieux repenser son architecture.
  • M’améliorer en réseau grâce à ça.

Références

  1. VPN, Virtual Private Network 

  2. OS, Operating System 

  3. Switch, Commutateur réseau 

  4. CPU, Central Process Unit 

  5. RAM, Random Access Memory 

  6. HDD, Hard Drive Disk 

  7. Basic Input Output System 

  8. Box Internet 

  9. Pare feu 

  10. LAN, Local Area Network 

  11. NAT, Network Adress Transcripteur 

  12. VLAN, Virtual Local Area Network 

  13. Micrologiciel ou matériel qui crée et exécute machines virtuelles 

  14. Unified Extensible Firmware Interface 

  15. Passerelle entre deux réseaux informatiques 

  16. Nom traditionnellement donné au pilote de la carte physique réseau sur un système Linux 

  17. IPV4, Internet Protocol Version 4 

  18. IPV6, Internet Protocol Version 6 

  19. Secure Shell (SSH) est à la fois un programme informatique et un protocole de communication sécurisé 

  20. Alpine Linux 

  21. ISO, une image ISO est la représentation binaire exacte d’un CD ou DVD-ROM afin de la stocker sur votre disque dur en vue de la duplication ultérieure du média original 

  22. VNC, Virtual Network Computing, système de visualisation et de contrôle de l’environnement de bureau d’un ordinateur distant. 

  23. Ensemble d’outils informatiques libres permettant des communications sécurisées sur un réseau informatique en utilisant le protocole SSH 

  24. le forwarding consiste à rediriger des paquets réseaux reçus sur un port donné d’un ordinateur ou un équipement réseau vers un autre ordinateur 

  25. Interface qui permet d’examiner et de modifier dynamiquement les paramètres des systèmes d’exploitation BSD et Linux