Aller au contenu
Conteneurs & Orchestration medium

Incus OS : l'OS immuable dédié à Incus

16 min de lecture

logo incus

Installer Incus sur Debian, c'est ajouter une application à un système généraliste. Incus OS renverse la logique : c'est un système immuable conçu pour ne faire tourner que Incus, sans shell, piloté uniquement par une API REST authentifiée. Cette page explique ce qu'est Incus OS et ses propriétés, puis montre le parcours réellement mené sur un lab Proxmox : installation par ISO + seed, accès à l'interface web embarquée, et surtout le montage d'un cluster 3 nœuds entièrement sans l'interface graphique. Pour administrateurs à l'aise avec Incus et la virtualisation.

  • Ce qu'est Incus OS et pourquoi un OS immuable et sans shell.
  • Installer un nœud par image ISO et fichiers seed.
  • Rejoindre l'interface web embarquée sur le port 8443.
  • Établir la confiance d'un client CLI sans passer par l'interface.
  • Monter un cluster 3 nœuds entièrement par seed et API.

Incus OS est décrit par le projet comme un OS immuable pensé uniquement pour faire tourner Incus de façon sûre et fiable. Ce n'est pas une distribution où l'on installe Incus : c'est une image système où Incus et le noyau sont intégrés et signés, identique bit pour bit sur toutes les machines.

Il est construit sur Debian 13, avec les paquets Incus et noyau du projet. La rupture de philosophie tient en une phrase : aucun shell local ni distant, l'administration passe exclusivement par une API REST authentifiée. Le lab décrit ici tourne sur Incus 7.2 (image IncusOS_202607010319).

Un serveur Incus classique dérive avec le temps : paquets installés à la main, configurations locales, versions qui divergent d'une machine à l'autre. Incus OS supprime cette variance de déploiement en livrant exactement le même logiciel partout. Sur un parc de nœuds, c'est la garantie d'un comportement reproductible.

L'immuabilité apporte aussi une surface d'attaque réduite : les partitions système sont en lecture seule et signées, et l'absence de shell ferme un vecteur d'intrusion classique. Le revers, assumé, est qu'aucun agent tiers ne s'installe à la main et qu'aucun ajustement local n'est possible.

Incus OS empile plusieurs mécanismes de sécurité et d'exploitation qui, ensemble, définissent son positionnement. Le tableau les résume avant d'entrer dans la pratique.

PropriétéCe que ça apporte
UEFI Secure Boot + TPM 2.0Chaîne de démarrage vérifiée et mesurée
Chiffrement complet du disqueLUKS adossé au TPM et chiffrement ZFS
Partitions système en lecture seule et signéesLe système ne peut pas être altéré en place
Mises à jour atomiques A/BBascule sur une nouvelle image, revert facile
API REST uniquement, pas de shellAdministration authentifiée, pas d'accès interactif

C'est l'un des points les plus distinctifs. Les systèmes Incus OS vérifient les mises à jour toutes les 6 heures par défaut et les appliquent automatiquement ; le canal stable reçoit au moins une mise à jour par semaine. La fréquence est configurable et les mises à jour peuvent être désactivées.

Le schéma A/B applique la nouvelle version sur une seconde partition : en cas de problème, le système revient à la précédente sans réinstallation. C'est le même principe que sur les OS immuables de conteneurs ou de mobiles. Le guide mises à jour A/B et rollback détaille comment lire les versions, régler le canal et mettre à jour un cluster sans coupure via l'API.

Là où un Incus sur Debian réclame apt install incus-ui-canonical, Incus OS livre déjà l'interface dans son image. On ouvre https://<IP>:8443/ui/ dans un navigateur et l'interface graphique de gestion des instances, réseaux et pools est là, sans rien installer, ce qui lève la contradiction apparente avec l'immuabilité.

Cette interface gère Incus, pas encore l'OS lui-même (redémarrage, mises à jour système), qui restent pilotés par la sous-commande incus admin os. Surtout, rien n'oblige à l'utiliser : tout ce que fait l'interface, l'API et le client CLI distant le font aussi. Le reste de cette page démontre un déploiement complet sans jamais ouvrir l'interface.

L'installation se fait à partir de l'image ISO du projet, accompagnée d'un jeu de fichiers seed : de petits fichiers JSON, gravés sur un second média étiqueté SEED_DATA, qui pilotent l'installation et la première configuration. Le lab utilise des machines virtuelles Proxmox, mais la logique du seed est indépendante de l'hyperviseur.

Trois contraintes matérielles ont été vérifiées et ne sont pas négociables :

  • La machine doit être en UEFI (OVMF) avec Secure Boot possible et un TPM 2.0.
  • Le disque cible doit être en virtio-scsi. Un disque virtio-blk échoue avec no potential install devices found.
  • Le média SEED_DATA est obligatoire : sans lui, l'installeur s'arrête sur unable to begin install from read-only device without seed configuration.

Un nœud a besoin de trois fichiers. Le premier, install.json, déclenche l'installation :

{"force_reboot": false}

Le deuxième, network.json, fixe une adresse IP statique (indispensable pour un cluster, dont les adresses doivent être connues d'avance). Il embarque la configuration réseau à plat, et l'interface est repérée par son adresse MAC :

{
"version": "1",
"interfaces": [
{
"name": "ens18",
"hwaddr": "bc:24:11:98:92:a0",
"addresses": ["192.168.10.131/24"],
"routes": [{"to": "0.0.0.0/0", "via": "192.168.10.1"}],
"roles": ["management"]
}
],
"dns": {"domain": "lab", "hostname": "node1", "nameservers": ["192.168.10.1", "1.1.1.1"]}
}

Le troisième, incus.json, configure Incus. Pour un premier nœud simple, apply_defaults suffit à créer le pool de stockage local et le réseau par défaut :

{"version": "1", "apply_defaults": true}

Ces trois fichiers sont rassemblés dans une image ISO étiquetée SEED_DATA, avec genisoimage :

Fenêtre de terminal
genisoimage -V SEED_DATA -J -r -o seed-node1.iso seed-node1/

Le nom de volume SEED_DATA n'est pas décoratif : c'est exactement ce label qu'Incus OS recherche pour lire la configuration.

L'installeur écrit le système sur le disque, puis attend le retrait du média : il n'éteint pas la machine.

  1. Démarrer sur l'ISO avec le média SEED_DATA attaché en second lecteur. L'installeur copie le système sur le disque virtio-scsi.

  2. Attendre le message IncusOS was successfully installed. Please remove the install media. La machine reste en attente à cet écran.

  3. Retirer les deux médias (ISO d'install et seed), puis redémarrer sur le disque. Les fichiers seed autres que install.json ont été recopiés dans le système ; ils s'appliquent au premier démarrage.

Au premier démarrage, le nœud applique le réseau statique et la configuration Incus. L'API répond alors sur https://192.168.10.131:8443/1.0, avec auth: untrusted tant qu'aucun client n'est de confiance. Le port SSH est fermé : la confirmation concrète de l'absence de shell.

Sur un nœud sans shell, un client CLI distant doit devenir de confiance pour piloter Incus. L'interface web propose un parcours d'enrôlement, mais il existe une voie entièrement par seed : injecter un certificat client directement dans la configuration Incus au premier démarrage.

On génère d'abord un couple certificat/clé client, une seule fois, sur le poste d'administration :

Fenêtre de terminal
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -nodes \
-keyout client.key -out client.crt -days 3650 -subj "/CN=incus-admin"

On enrichit ensuite le incus.json du premier nœud avec la section preseed.certificates, qui reçoit le certificat client au format PEM :

{
"version": "1",
"apply_defaults": true,
"preseed": {
"certificates": [
{"name": "incus-admin", "type": "client", "certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n"}
]
}
}

Après réinstallation avec ce seed, le certificat est déjà de confiance. Une requête avec ce certificat le confirme :

Fenêtre de terminal
curl -sk --cert client.crt --key client.key https://192.168.10.131:8443/1.0 | grep -o '"auth":"[a-z]*"'
# "auth":"trusted"

Aucun clic dans l'interface, aucun outil de personnalisation d'image : la confiance vient du seed. C'est la brique qui rend tout le reste possible.

Un cluster Incus regroupe plusieurs serveurs sous une seule API, avec une base de configuration répliquée et une tolérance de panne à partir de 3 nœuds. Les concepts de quorum et de récupération sont détaillés dans le guide Cluster Incus ; cette section se concentre sur la spécificité Incus OS : tout monter sans shell et sans interface.

Le poste d'administration utilise le client incus (ici incus-client 6.0.4), configuré avec le certificat déjà de confiance :

Fenêtre de terminal
incus remote add node1 https://192.168.10.131:8443 --auth-type tls --accept-certificate

Le premier nœud devient un cluster à lui seul. On lui donne une adresse de cluster concrète, puis on active le clustering depuis le client de confiance :

Fenêtre de terminal
incus config set node1: cluster.https_address 192.168.10.131:8443
incus cluster enable node1: node1

Activer le cluster régénère le certificat serveur du nœud. Le remote pointe alors sur un certificat périmé ; on le réépingle simplement :

Fenêtre de terminal
incus remote remove node1
incus remote add node1 https://192.168.10.131:8443 --auth-type tls --accept-certificate

Chaque nœud entrant a besoin d'un jeton de jointure unique, émis par le premier nœud. Ce jeton ne peut pas être pré-généré dans un seed statique : c'est la seule étape qui passe par un appel API, réalisé depuis le poste de confiance, jamais par un shell sur les nœuds.

Fenêtre de terminal
incus cluster add node1: node2

La commande renvoie un jeton encodé en base64, qui contient le nom du membre, l'empreinte du certificat cluster et les adresses de contact.

Les nœuds 2 et 3 rejoignent le cluster par leur seed, sans apply_defaults. Le incus.json d'un nœud entrant décrit la jointure. Deux champs sont indispensables en plus du jeton, et leur absence a été diagnostiquée directement dans le code d'Incus :

  • cluster_certificate : le certificat du cluster, au format PEM. Le client interactif le résout tout seul à partir du jeton, mais Incus OS applique le preseed sans cette résolution. Sans ce champ, la jointure échoue sur No target cluster member certificate provided.
  • member_config avec source: local/incus : la source du pool zfs local sur le disque système. Sans elle, Incus tente un pool loop-backed, interdit par Incus OS (Loop backed pools aren't supported on IncusOS).

On récupère le certificat cluster présenté par le premier nœud :

Fenêtre de terminal
openssl s_client -connect 192.168.10.131:8443 -showcerts </dev/null 2>/dev/null \
| openssl x509 -outform PEM > node1-cluster.crt

Le incus.json du nœud 2 ressemble alors à ceci (le nœud 3 est identique, avec ses propres nom et adresse) :

{
"version": "1",
"apply_defaults": false,
"preseed": {
"cluster": {
"enabled": true,
"server_name": "node2",
"server_address": "192.168.10.132:8443",
"cluster_address": "192.168.10.131:8443",
"cluster_token": "<jeton émis par node1>",
"cluster_certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n",
"member_config": [
{"entity": "storage-pool", "name": "local", "key": "source", "value": "local/incus"}
]
}
}
}

On installe chaque nœud avec son seed, exactement comme le premier. Au premier démarrage, le nœud rejoint le cluster tout seul. La confiance du certificat client étant répliquée dans la base du cluster, le certificat d'administration est automatiquement reconnu sur les nœuds joints : rien à réinjecter.

Une fois les trois nœuds installés, le client de confiance liste un cluster opérationnel :

Fenêtre de terminal
incus cluster list node1:
+-------+-----------------------------+------------------+--------+-------------------+
| NAME | URL | ROLES | STATUS | MESSAGE |
+-------+-----------------------------+------------------+--------+-------------------+
| node1 | https://192.168.10.131:8443 | database-leader | ONLINE | Fully operational |
| node2 | https://192.168.10.132:8443 | database | ONLINE | Fully operational |
| node3 | https://192.168.10.133:8443 | database | ONLINE | Fully operational |
+-------+-----------------------------+------------------+--------+-------------------+

Les trois membres portent le rôle database : le quorum à 3 nœuds est atteint, un nœud peut tomber sans arrêter le service. Le pool local est un pool zfs de source local/incus sur chaque membre, et le port SSH reste fermé partout. Le cluster complet a été monté sans jamais ouvrir l'interface web.

Ces erreurs viennent du lab réel. Les connaître fait gagner un cycle de réinstallation.

SymptômeCauseSolution
no potential install devices foundDisque cible en virtio-blkUtiliser un disque virtio-scsi
unable to begin install from read-only device without seed configurationMédia SEED_DATA absentGraver l'ISO seed avec le label SEED_DATA
No target cluster member certificate providedcluster_certificate manquant dans le seed de jointureAjouter le PEM du certificat cluster au preseed
Loop backed pools aren't supported on IncusOSPas de member_config pour le pool localFournir source: local/incus en member_config

Le choix n'est pas « mieux ou moins bien », mais deux modèles d'exploitation distincts. Le tableau aide à trancher.

Incus sur DebianIncus OS
BaseDebian que vous gérezImage immuable fournie
Accès systèmeShell complet (SSH, sudo)API REST uniquement
Mises à jourapt à votre rythmeAtomiques A/B, automatiques
Personnalisation hôteTotaleVolontairement nulle
ReproductibilitéÀ votre chargeGarantie, bit pour bit

Incus OS vise les déploiements où la reproductibilité et la sécurité priment sur la flexibilité : un parc de nœuds identiques, une infrastructure qu'on veut immuable et auto-mise à jour, un contexte où l'absence de shell est un atout de conformité. Pour un serveur unique qu'on bricole, ou pour découvrir Incus, l'installation classique sur Debian reste plus adaptée.

  • Incus OS est un système immuable dédié à Incus, construit sur Debian 13, Incus et noyau signés.
  • Aucun shell : administration par API REST authentifiée uniquement, port SSH fermé.
  • Installation par ISO + seed ; disque virtio-scsi obligatoire, média SEED_DATA obligatoire.
  • La confiance d'un client s'injecte par le seed (preseed.certificates), sans l'interface.
  • Un cluster 3 nœuds se monte par seed et API : jointure avec cluster_certificate et member_config source: local/incus.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn