Ce billet est le premier d’une série de billets traitant de la création d’une infrastructure virtualisée à l’aide de Proxmox1 pour la partie hyperviseur, de Fedora CoreOS2 pour le système d’exploitation des machines virtuelles invitées (guests). L’infrastructure codifiée (Infrastructure as Code) est réalisée avec OpenTofu3 (Hashicorp Terraform ayant rejoint le côté obscur de la Force).
Proxmox est un ensemble d’outils, voire une distribution Linux à part entière reposant sur Debian, permettant l’administration d’une infrastructure virtualisée en ligne de commande, via une interface web, ou grâce à une API. Proposant des options de stockage réparti, de réseau étendu à un groupe d’instances (cluster), de groupes de sécurité, de haute disponibilité, pour n’en citer que quelques-unes, il s’agit d’une solution qui peut remplacer aisément VMWare, au minimum sur les cas d’usage relativement simples.
Fedora CoreOS est une distribution Linux orientée sur la stabilité et la sécurité. Son objectif principal est l’hébergement de conteneurs, et pour cette raison, elle est pourvue d’un socle minimaliste et durci, mis à jour automatiquement. Ces mises à jour automatiques sont aisément réversibles en cas de problème, grâce à son approche pseudo-immuable4, reposant sur rpm-ostree, et son système de mise à jour (Zincati) permet également d’orchestrer ces dernières de façon à maintenir un service hautement disponible.
Fedora CoreOS est également un système d’exploitation à part en cela qu’il est conçu pour ne pas avoir besoin d’interagir directement avec le système, que ce soit pour l’installation/configuration ou l’administration. L’idée est qu’un cas de changement de configuration, on réinstalle totalement le système. Au premier démarrage, lors de l’exécution de l’initramfs, le programme ignition5 exécute une recette qui configure le système : formatage et partitionnement des disques, ajout des utilisateurs, copies de fichiers et de services, etc..
Si cette approche peut sembler lourde de prime abord, elle présente en réalité l’avantage d’apporter la sérénité à ses administrateurs et administratrices ; en effet, il est dès lors possible de réaliser la recette de la nouvelle configuration à l’identique dans un environnement de préproduction, sans risque d’interférence avec l’existant (snowflake servers6).
Ignition et cloud-init7 sont des cousins éloignés. Les deux participent à la configuration et la personnalisation d’une image système. Le moment de l’exécution est cependant très différent et importe. En effet, Ignition intervient lors de l’initramfs, tandis que cloud-init intervient plus tard lors du démarrage du système d’exploitation. Ignition est donc en mesure de modifier les tables des partitions avant que le véritable système d’exploitation ne démarre, et préconfigure le système comme si cette configuration avait toujours existé ou avait été modifiée lors d’une exécution précédente.
Ignition possède néanmoins quelques limitations, assumées, notamment si on le compare à Ansible. En effet, Ansible possède de très nombreux greffons lui permettant d’effectuer des actions riches sur un système en cours d’exécution. Ignition permet essentiellement la copie de fichiers et de services, et les opérations complexes doivent être effectuées par des scripts shell (Fedora CoreOS n’installe pas Python, par exemple). Ce choix est raisonnable étant donné que relativement peu d’opérations d’administration sont attendues sur le socle faisant tourner Fedora CoreOS.
En outre, Ansible Vault permet le stockage et le déploiement sécurisé de secrets, y compris dans les outils de versionnement de code comme git. Ignition, pour sa part, ne permet pas la communication de secrets de manière sécurisée ; au mieux, il est possible de les stocker dans un fichier qui sera téléchargé puis fusionné avec le reste de la configuration par Ignition. Cette solution n’étant pas très satisfaisante, il est donc nécessaire d’utiliser un gestionnaire de secrets comme OpenBao (Hashicorp Vault ayant rejoint le côté obscur de la Force)8 avec l’emballage de réponses9, Bitwarden Send10 ou Bitwarden Secret Manager11.
Proxmox dispose d’une couche de compatibilité native avec Cloud-init. Celle-ci
n’est hélas pas générique, et ne permet pas de configurer toutes les options de
Cloud-init. Avec OpenTofu et le fournisseur bpg/proxmox
12, il est
possible de fabriquer à la volée un ISO disposant du label CIDATA, et ainsi
d’exploiter le mode “nocloud” de cloud-init13. Tout ceci n’aide
cependant pas au déploiement de Fedora CoreOS.
Il existe une multitude de moyens de fournir un fichier de configuration à Ignition : par HTTP après une indication par PXE ou sur la ligne de commande du noyau, directement dans le fichier ISO d’installation après une personnalisation de ce dernier, dans une variable du micrologiciel (firmware), etc. Hélas, l’utilisation d’un ISO séparé, à l’instar du mode “nocloud” de cloud-init, n’est pas une option. Nous allons néanmoins voir qu’aucune des autres options n’est native à Proxmox ou satisfaisante.
Proxmox dispose d’une couche réseau programmable/configurable (Software-defined Network (SDN)) assez développée. Cette dernière permet la définition de différentes zones réseau, avec un filtrage des flux par règles et par groupes de sécurité. En outre, elle fournit différents services, dont un serveur DHCP branché sur un IPAM (IP Address Management), avec possible synchronisation des adresses avec un serveur DNS.
Hélas, il n’est pas possible (par l’interface web ou l’API) de personnaliser la configuration DHCP pour y rajouter les options nécessaires à PXE, ni d’ajouter un service pour publier les fichiers de configuration Ignition par HTTP ou TFTP.
Il est bien sûr possible de se connecter en console, en root, pour modifier cette configuration, mais cela demande des privilèges élevés sur l’hyperviseur, et ce n’est pas officiellement supporté par Proxmox. Il est donc préférable de rechercher une voie alternative, supportée et ne nécessitant que peu de privilèges.
La personnalisation du fichier ISO de Fedora CoreOS est assez aisée. En effet, ses développeurs fournissent, notamment sous la forme de conteneurs, des outils pour ajouter des fichiers et modifier la ligne de commande du noyau14.
Cette approche nécessite cependant d’avoir un fichier ISO distinct par poste à installer. Ce fichier doit à nouveau être téléversé en intégralité à chaque modification de la configuration Ignition, ce qui est consommateur de bande passante. Il peut surement être possible d’utiliser un LXC hébergé par Proxmox pour faire cette personnalisation directement sur l’hyperviseur, sans nécessiter le téléversement.
Au niveau stockage, il est possible de ne pas trop surconsommer du fait que Proxmox prend en charge nativement btrfs15 et ZFS, et que ces systèmes de fichiers permettent la déduplication des blocs. Cette approche relève cependant d’une certaine forme de bricolage, avec de potentielles pertes de performances dans le cas de ZFS ou d’espace disque dans le cas de btrfs si la déduplication n’est pas demandée assez souvent.
La fourniture du fichier de configuration par une variable de micrologiciel s’effectue en ajoutant un argument à la commande qemu qui lance la machine virtuelle. Cet argument ressemble à la ligne suivante :
-fw_cfg name=opt/com.coreos/config,file=/local/path/to/config.ign
Cet argument peut être fourni en modifiant le fichier de configuration de la
machine virtuelle sur l’hyperviseur dans le répertoire
/etc/pve/qemu-server/<vm_id>.conf
. Cette méthode nécessite néanmoins la
connexion en utilisateur root (via le console ou en SSH), ce qui n’est pas
forcément souhaitable, et la manipulation plus ou moins manuelle de fichiers
système.
Il peut être également fourni lors des appels à l’API, et le greffon OpenTofu
bpg/proxmox
permet de le faire avec l’attribut kvm_paramters
de la ressource
proxmox_virtual_environment_vm
. Cette méthode nécessite cependant qu’OpenTofu
se connecte avec l’utilisateur root@pam
, avec mot de passe et sans avoir
défini de second facteur d’authentification. En effet, Proxmox ne permet pas
l’utilisation de jetons d’API, même pour l’utilisateur root@pam
, pour cette
opération. Cette approche abaisse donc significativement le niveau de sécurité
et n’est donc pas souhaitable.
En outre, l’option permettant la définition d’une variable dans le micrologiciel prend en argument le chemin vers le fichier de configuration Ignition. Ce chemin est local à l’hyperviseur. Hélas, il n’est pas possible de téléverser sur un serveur Proxmox un fichier arbitraire par l’API ou l’interface web, malgré l’existence d’une fonctionnalité de “snippets”16. Il est donc là encore nécessaire de se connecter en SSH/SFTP pour téléverser le fichier de configuration…
Geco IT17 a créé un script qui permet de convertir certaines options de cloud-init en fichier de configuration Ignition.
Leur méthode de création de VM ne passe pas par l’API Proxmox mais utilise un autre script shell qui lance des outils en ligne de commandes de la distribution Proxmox. Ces commandes sont exécutées en tant que root, et parmi celles-ci, la commande suivante :
qm set <vmid> -hookscript <snippet_storage>:snippets/hook-fcos.sh
L’attribut -hookscript
peut être défini par l’API de Proxmox, et par le
greffon bpg/proxmox
d’OpenTofu. Cependant, à l’instar de l’attribut -args
,
celui-ci n’est accepté que si le compte d’API utilisé est root@pam
,
c’est-à-dire le compte root du serveur Proxmox, avec une authentification par
mot de passe et sans second facteur d’authentification.
En conséquence, cette méthode n’apporte aucune sécurité additionnelle par rapport à la précédente discutée, tout en réduisant l’expressivité du fichier de configuration Ignition.
Comme nous avons pu le voir dans les sections précédentes, l’usage de l’API
Proxmox pour les attributs -args
et -hookscript
est rédhibitoire puisque
nécessitant non seulement d’utiliser le mot de passe du compte root dans la
configuration OpenTofu, mais aussi de désactiver les seconds facteurs
d’authentification.
La solution PXE est certainement la plus élégante, mais l’impossibilité de configurer le serveur DHCP de Proxmox (sans passer par le shell) pour permettre un tel démarrage nous en prive. Finalement, l’approche ISO personnalisé ne passerait pas à l’échelle d’un parc complet.
Nous disposons cependant ici de toutes les briques suffisantes pour construire une solution satisfaisante !
L’idée est la suivante : personnaliser un ISO de Fedora CoreOS afin d’y ajouter un fichier Ignition permettant d’installer un serveur DHCP (pour distribuer les IPs mais aussi la configuration PXE), un serveur HTTP pour servir les fichiers indiqués par PXE, et un serveur SFTP afin de déposer les fichiers de configuration Ignition servis par HTTP.
À l’origine, je souhaitais détailler ici la solution, mais son développement s’est avéré suffisamment complexe (et surprenant) pour constituer un billet de blog séparé. À suivre !
https://developer.hashicorp.com/vault/docs/concepts/response-wrapping ↩︎
https://registry.terraform.io/providers/bpg/proxmox/latest ↩︎
https://cloudinit.readthedocs.io/en/latest/reference/datasources/nocloud.html ↩︎
https://docs.fedoraproject.org/en-US/fedora-coreos/live-booting/#_booting_via_iso ↩︎
https://btrfs.readthedocs.io/en/latest/Deduplication.html ↩︎
https://forum.proxmox.com/threads/creating-snippets-using-pve-api.54081/ ↩︎