
Une VM compromise ne doit pas donner accès à l'hôte, ni à ses voisines. KVM s'appuie pour cela sur plusieurs couches qui travaillent déjà chez vous, souvent sans que vous le sachiez : un utilisateur dédié par machine, un label sVirt dérivé de son identifiant, un firmware qui peut refuser un noyau non signé. Ce guide montre comment vérifier que ces couches sont réellement actives, car une protection chargée n'est pas forcément une protection qui bloque.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Lire les couches de confinement que libvirt applique à chaque machine
- Vérifier que le profil sVirt est en mode bloquant, et non simplement chargé
- Activer le Secure Boot et savoir ce que la NVRAM contient
- Ajouter un vTPM, et ce que cela implique pour vos sauvegardes
- Filtrer le trafic d'une VM avec nwfilter, au plus près de la machine
Prérequis
Section intitulée « Prérequis »- KVM/libvirt installé (guide installation)
- Une VM définie, même arrêtée, pour lire son XML
- Les droits d'administration sur l'hôte
Deux couches, appliquées par défaut
Section intitulée « Deux couches, appliquées par défaut »Regardez le XML d'une machine qui tourne : libvirt y écrit ce qu'il a réellement mis en place.
virsh dumpxml ma-vm | grep -A3 '<seclabel'Sur l'hôte de ce guide, une Ubuntu 24.04, la réponse contient deux blocs :
<seclabel type='dynamic' model='apparmor' relabel='yes'> <label>libvirt-7fe39141-9708-4375-b960-8bba34cd58f2</label></seclabel><seclabel type='dynamic' model='dac' relabel='yes'> <label>+64055:+994</label></seclabel>| Couche | Ce qu'elle fait |
|---|---|
dac | Le processus QEMU tourne sous un utilisateur et un groupe dédiés, ici 64055:994, pas sous root |
apparmor | Un profil par machine, nommé d'après l'UUID du domaine |
C'est sVirt : le label n'est pas commun à toutes les VM, il est propre à
chacune. Deux machines du même hôte portent deux labels différents, et le
profil de l'une ne l'autorise pas à toucher les fichiers de l'autre. Le
type='dynamic' indique que libvirt crée et retire ce label au démarrage et
à l'arrêt, sans que vous ayez rien à écrire.
Le contrôle qui compte : confiner, ou seulement observer
Section intitulée « Le contrôle qui compte : confiner, ou seulement observer »Un profil chargé n'est pas un profil qui bloque. AppArmor distingue deux modes, et la différence décide de tout : en enforce, une violation est refusée ; en complain, elle est simplement journalisée et l'action aboutit quand même.
sudo aa-status | grep -c 'libvirt-'ps -eo label,comm | grep qemu-systemLa seconde commande est la plus parlante, car elle donne le mode réellement appliqué au processus en cours :
libvirt-7fe39141-9708-4375-b960-8bba34cd58f2 (complain) qemu-system-x86Ce (complain) change tout. Sur l'hôte qui a servi à écrire ce guide,
18 profils libvirt sont en mode plainte contre 9 en mode bloquant : la
majorité des machines n'y sont donc pas confinées, elles sont observées. Le
mécanisme est en place, les journaux se remplissent, et rien n'empêche une
violation d'aboutir.
Trois protections que vous n'avez pas demandées
Section intitulée « Trois protections que vous n'avez pas demandées »sVirt est la couche visible, celle qui apparaît dans le XML. Trois autres travaillent sans rien y écrire, et elles se vérifient sur le processus lui-même. Relevez d'abord son identifiant :
PID=$(pgrep -f 'qemu-system-x86.*ma-vm')Un espace de montage par machine
Section intitulée « Un espace de montage par machine »libvirt lance chaque QEMU dans son propre espace de montage. Le résultat est spectaculaire, et se mesure en une commande :
ls /dev | wc -l # sur l'hôtesudo nsenter -t "$PID" -m ls /dev | wc -l # vu par QEMUSur l'hôte de ce guide, /dev compte 235 entrées. Le QEMU d'une VM n'en voit
que onze :
full hugepages kvm mqueue null ptmx pts random shm urandom zeroNi les disques de l'hôte, ni les périphériques USB, ni rien d'autre que
le strict nécessaire. Un QEMU compromis ne peut pas ouvrir ce qu'il ne voit
pas. Le réglage qui gouverne cela est namespaces = [ "mount" ] dans
qemu.conf.
Un filtre d'appels système
Section intitulée « Un filtre d'appels système »QEMU tourne sous un filtre seccomp, qui interdit les appels système dont il n'a pas besoin et réduit d'autant la surface offerte au noyau :
grep Seccomp /proc/$PID/statusLa valeur Seccomp: 2 signifie qu'un filtre est actif. libvirt l'applique
avec une politique qui refuse les appels obsolètes, l'élévation de
privilèges, la création de processus et le contrôle des ressources.
Le réglage correspondant est seccomp_sandbox = 1.
Aucune capability
Section intitulée « Aucune capability »grep CapEff /proc/$PID/statusLa réponse est 0000000000000000 : le processus ne conserve aucun
privilège particulier. Même s'il parvenait à sortir de son périmètre, il
ne pourrait ni charger un module, ni ouvrir un port privilégié, ni changer
d'identité.
Ce cloisonnement répond au modèle de menace que QEMU assume explicitement : l'invité est considéré comme non fiable, au même titre que les images de disque, les protocoles réseau et les périphériques passés en direct. L'objectif déclaré du projet est qu'un invité malveillant ne puisse ni prendre le contrôle d'un autre invité, ni accéder à ses données.
Ce qui reste, même en confinant bien
Section intitulée « Ce qui reste, même en confinant bien »Le confinement protège l'hôte d'une VM compromise. Il ne protège pas d'un
administrateur de l'hyperviseur : qui contrôle l'hôte lit les disques,
attache un périphérique, ouvre une console. C'est pourquoi l'appartenance au
groupe libvirt est un pouvoir d'administration, et se décide comme tel.
Les autorisations fines par action passent par polkit, traité dans le
guide d'installation.
Secure Boot : refuser un noyau non signé
Section intitulée « Secure Boot : refuser un noyau non signé »Le Secure Boot fait vérifier par le firmware la signature de ce qu'il démarre. Pour une VM, cela suppose un firmware UEFI capable de le faire, et un jeu de variables contenant les clés reconnues.
ls /usr/share/OVMF/Les quatre fichiers qui comptent sur une Ubuntu récente :
| Fichier | Rôle |
|---|---|
OVMF_CODE_4M.fd | Firmware sans Secure Boot |
OVMF_CODE_4M.secboot.fd | Firmware avec Secure Boot |
OVMF_VARS_4M.ms.fd | Variables préchargées des clés Microsoft, celles qui signent les distributions courantes |
OVMF_VARS_4M.snakeoil.fd | Clés de test, jamais en production |
À la création, virt-install accepte de déclarer le tout :
virt-install ... --boot uefi,firmware.feature0.name=secure-boot,firmware.feature0.enabled=yesLa NVRAM mérite une attention particulière : c'est un fichier par
machine, créé à partir du gabarit de variables, et il contient les clés et
les entrées d'amorçage propres à cette VM. Il vit à côté du disque, en
général sous /var/lib/libvirt/qemu/nvram/.
vTPM : un coffre par machine
Section intitulée « vTPM : un coffre par machine »Un TPM virtuel offre à l'invité ce qu'une puce TPM offre à une machine
physique : un stockage scellé pour des clés, utilisé par BitLocker, par
systemd-cryptenroll ou par une attestation. Il est fourni par swtpm,
un émulateur indépendant de QEMU.
swtpm --versionLa déclaration tient en trois lignes de XML :
<tpm model='tpm-crb'> <backend type='emulator' version='2.0'/></tpm>libvirt crée alors un état persistant pour ce TPM, sous
/var/lib/libvirt/swtpm/, propre à la machine et indispensable à son
fonctionnement ultérieur.
nwfilter : filtrer au plus près de la machine
Section intitulée « nwfilter : filtrer au plus près de la machine »Un pare-feu sur l'hôte filtre ce qui traverse le pont. nwfilter agit un cran plus bas, sur l'interface virtuelle elle-même, ce qui protège aussi les machines les unes des autres sur le même réseau.
virsh nwfilter-listlibvirt livre des filtres tout faits, dont le plus utile s'attache en une ligne au XML de l'interface :
<interface type='network'> <source network='default'/> <filterref filter='clean-traffic'/></interface>clean-traffic interdit à la VM d'usurper son adresse MAC ou son adresse
IP, et bloque les annonces ARP mensongères. Sur un réseau où plusieurs machines
de confiance inégale cohabitent, c'est la protection qui empêche l'une d'écouter
le trafic des autres.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- libvirt applique deux couches par défaut : un utilisateur dédié (
dac) et un label sVirt par machine, dérivé de son UUID. - Ce label est propre à chaque VM : le profil de l'une ne lui permet pas de toucher les fichiers de l'autre.
- Un profil chargé n'est pas un profil qui bloque. Le mode
(complain)lu sur le processus signifie observation, pas confinement. Sur l'hôte de ce guide, 18 profils sur 27 étaient dans ce cas. - Le confinement ne protège pas d'un administrateur de l'hyperviseur : le
groupe
libvirtest un pouvoir d'administration, polkit permet de le découper. - Le Secure Boot demande un firmware
secbootet un jeu de variables :OVMF_VARS_4M.ms.fdpour les clés Microsoft, jamaissnakeoilen production. - Une VM UEFI ou vTPM possède un état hors du disque, NVRAM et swtpm : une sauvegarde qui les oublie ne restaure pas une machine qui démarre.
clean-trafficempêche une VM d'usurper une adresse MAC ou IP, au niveau de son interface et non du pont.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Accès distant à libvirt : Le chiffrement du canal d'administration, SSH ou TLS, et ce que le TCP nu expose.
- KVM et Terraform : Déclarer ces protections dans le code plutôt que de les reposer à la main.
- Dépannage réseau KVM : Quand un filtre trop strict passe pour une panne de réseau.