Broken-by-Design/posts/proxmox-fcos1.md
2024-06-04 17:32:47 +02:00

255 lines
13 KiB
Markdown

---
title: Expérimentation de Fedora CoreOS sur Proxmox
slug: proxmox-fcos1
authors: Florian Maury
description: "Un article discutant de l'installation d'un serveur sur Fedora CoreOS sur Proxmox et des défis rencontrés"
date: 2024-05-29T00:00:00+02:00
type: posts
draft: false
categories:
- devops
tags:
- proxmox
- fcos
- knot
lang: fr
---
Ce billet est le premier d'une série de billets traitant de la création d'une
infrastructure virtualisée à l'aide de Proxmox[^proxmox] pour la partie
hyperviseur, de Fedora CoreOS[^fcos] pour le système d'exploitation des machines
virtuelles invitées (*guests*). L'infrastructure codifiée (*Infrastructure as
Code*) est réalisée avec OpenTofu[^opentofu] (Hashicorp Terraform ayant rejoint
le côté obscur de la Force).
[^proxmox]: https://www.proxmox.com/en/
[^fcos]: https://fedoraproject.org/coreos/
[^opentofu]: https://opentofu.org/
## Présentation de Proxmox
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.
## Présentation de Fedora CoreOS
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-immuable[^pseudo-integrity],
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
ignition[^ignition] 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 servers*[^snowflakes]).
[^pseudo-integrity]: https://mastodon.social/@pid_eins/112393043769199622
[^ignition]: https://coreos.github.io/ignition/
[^snowflakes]: https://www.learnsteps.com/what-are-snowflake-servers/
Ignition et cloud-init[^cloud-init] 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.
[^cloud-init]: https://cloud-init.io/
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)[^openbao] avec l'emballage de réponses[^respwrap], Bitwarden
Send[^bwsend] ou Bitwarden Secret Manager[^bwsm].
[^openbao]: https://openbao.org/
[^respwrap]: https://developer.hashicorp.com/vault/docs/concepts/response-wrapping
[^bwsend]: https://bitwarden.com/fr-fr/products/send/
[^bwsm]: https://bitwarden.com/fr-fr/products/secrets-manager/
## Défis d'un déploiement de Fedora CoreOS sur Proxmox
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`[^bpgprox], il est
possible de fabriquer à la volée un ISO disposant du label CIDATA, et ainsi
d'exploiter le mode "nocloud" de cloud-init[^nocloud]. Tout ceci n'aide
cependant pas au déploiement de Fedora CoreOS.
[^bpgprox]: https://registry.terraform.io/providers/bpg/proxmox/latest
[^nocloud]: https://cloudinit.readthedocs.io/en/latest/reference/datasources/nocloud.html
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.
### Fourniture de l'adresse du fichier Ignition par PXE
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.
### Fourniture du fichier de configuration par personnalisation du fichier ISO
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
noyau[^customizeiso].
[^customizeiso]: https://docs.fedoraproject.org/en-US/fedora-coreos/live-booting/#_booting_via_iso
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 btrfs[^btrfs] 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.
[^btrfs]: https://btrfs.readthedocs.io/en/latest/Deduplication.html
[^zfs]: https://openzfs.org/wiki/Main_Page
### Fourniture du fichier de configuration par une variable du micrologiciel
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"[^snippets_api]. Il est donc là
encore nécessaire de se connecter en SSH/SFTP pour téléverser le fichier de
configuration...
[^snippets_api]: https://forum.proxmox.com/threads/creating-snippets-using-pve-api.54081/
### Convertir un fichier cloud-init
Geco IT[^gecoit] a créé un script qui permet de convertir certaines options de
cloud-init en fichier de configuration Ignition.
[^gecoit]: https://wiki.geco-it.net/public:pve_fcos
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.
## Une proposition de solution : une machine virtuelle d'installation
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 !