Aller au contenu
English
English
Virtualisation medium

Accès distant libvirt : gérer vos VMs KVM depuis n'importe où

45 min de lecture

Logo KVM

Administrer un serveur KVM depuis votre poste de travail évite les connexions SSH multiples et permet d'utiliser l'interface graphique de virt-manager. Ce guide vous montre comment configurer l'accès distant de façon sécurisée.

  • Vous connecter à libvirt via SSH, la méthode recommandée
  • Utiliser virsh en ligne de commande sur un hôte distant
  • Configurer virt-manager pour piloter plusieurs hyperviseurs
  • Décrypter les URIs de connexion libvirt et leurs pièges
  • Ouvrir un accès TCP ou TLS par activation de socket, quand SSH ne suffit pas

Sur votre poste de travail (client) :

  • libvirt-client ou équivalent installé
  • Clés SSH configurées (recommandé)
  • virt-manager si vous voulez l'interface graphique

Sur le serveur KVM (distant) :

  • libvirt installé et fonctionnel
  • Service SSH actif
  • Votre utilisateur dans le groupe libvirt

libvirt utilise des URIs (Uniform Resource Identifiers) pour identifier où se connecter. C'est comme une URL, mais pour les hyperviseurs.

Un URI libvirt se lit de gauche à droite comme une adresse postale : le driver dit à quel hyperviseur on parle (qemu pour KVM), le transport dit par quel canal on l'atteint, et le path final dit quel jeu de machines on veut voir. Seul le driver est obligatoire, tout le reste se déduit d'une valeur par défaut quand on l'omet.

driver[+transport]://[username@]hostname[:port]/path[?parameters]

Cinq formes couvrent la quasi-totalité des usages. La colonne Sécurité est celle qui doit guider le choix : deux de ces URIs restent locaux à la machine, deux chiffrent le trafic, et un seul le laisse circuler en clair sur le réseau.

URIDescriptionSécurité
qemu:///systemLocal, VMs système (root/libvirt)Local
qemu:///sessionLocal, VMs utilisateurLocal
qemu+ssh://user@host/systemDistant via SSHChiffré
qemu+tcp://host/systemDistant via TCPNon chiffré
qemu+tls://host/systemDistant via TCP + TLSChiffré

Le suffixe de l'URI ne change pas l'hyperviseur interrogé, il change le socket auquel le client se branche, et donc le lot de machines qu'il voit. Une VM créée en /session reste invisible depuis /system, et réciproquement : c'est l'explication numéro un du « ma VM a disparu » après un changement d'URI.

URIVMs visiblesSocketPermissions
/systemToutes les VMs de l'hôte/run/libvirt/libvirt-sockGroupe libvirt ou root
/sessionVMs de l'utilisateur uniquement$XDG_RUNTIME_DIR/libvirt/libvirt-sockUtilisateur courant

Pour l'administration serveur, utilisez toujours /system.

La connexion via SSH est la plus simple et la plus sécurisée. Elle utilise le tunnel SSH existant, pas de port supplémentaire à ouvrir.

Il n'y a aucun démon supplémentaire à exposer : le transport SSH se contente de relayer, dans un tunnel chiffré, la conversation que le client aurait eue avec le socket local du serveur. C'est pour cette raison qu'un serveur déjà joignable en SSH est déjà prêt pour l'accès distant libvirt.

Connexion SSH vers libvirt

Le schéma se lit en trois temps :

  1. Votre client (virsh ou virt-manager) ouvre une connexion SSH vers le serveur.
  2. Il y démarre un relais qui se branche sur le socket /run/libvirt/libvirt-sock. Par défaut (paramètre proxy=auto), libvirt tente d'abord le relais natif virt-ssh-helper livré avec le paquet, et retombe sur nc -U /run/libvirt/libvirt-sock si ce binaire est absent du serveur.
  3. Toutes les commandes suivantes passent par ce tunnel, sans port supplémentaire ouvert sur le pare-feu.

Ces trois contrôles se font dans cet ordre parce qu'ils isolent trois causes différentes : le transport SSH, les droits de votre compte, puis le service libvirt lui-même. Un échec de connexion distante vient presque toujours de l'un des trois, et les tester séparément évite de chercher au mauvais endroit.

  1. Vérifier que SSH fonctionne

    Depuis votre poste :

    Fenêtre de terminal
    ssh user@serveur-kvm hostname

    Doit afficher le hostname du serveur.

  2. Vérifier que l'utilisateur est dans le groupe libvirt

    Sur le serveur :

    Fenêtre de terminal
    groups

    Sortie attendue :

    user libvirt kvm

    Si libvirt n'apparaît pas :

    Fenêtre de terminal
    sudo usermod -aG libvirt $USER
    # Puis se reconnecter
  3. Vérifier que libvirt fonctionne localement

    Sur le serveur :

    Fenêtre de terminal
    virsh -c qemu:///system list --all

    Doit lister les VMs (même si la liste est vide).

Depuis votre poste de travail :

Fenêtre de terminal
virsh -c qemu+ssh://user@serveur-kvm/system list --all

Sortie attendue :

Id Name State
-----------------------------
1 web-prod running
- db-backup shut off

Pour éviter de retaper l'URI complet à chaque fois :

Option 1 : Alias shell

Ajoutez dans ~/.bashrc ou ~/.zshrc :

Fenêtre de terminal
alias virsh-prod='virsh -c qemu+ssh://admin@prod-kvm.example.com/system'
alias virsh-dev='virsh -c qemu+ssh://admin@dev-kvm.local/system'

Utilisation :

Fenêtre de terminal
virsh-prod list --all
virsh-dev start ma-vm

Option 2 : Variable d'environnement

Fenêtre de terminal
export LIBVIRT_DEFAULT_URI="qemu+ssh://admin@serveur-kvm/system"
virsh list --all # Utilise automatiquement l'URI

Option 3 : Configuration SSH

Ajoutez dans ~/.ssh/config :

Host kvm-prod
HostName prod-kvm.example.com
User admin
IdentityFile ~/.ssh/id_ed25519

Puis :

Fenêtre de terminal
virsh -c qemu+ssh://kvm-prod/system list

virt-manager permet de gérer plusieurs hôtes KVM avec une interface graphique.

  1. Lancer virt-manager

    Fenêtre de terminal
    virt-manager
  2. Ajouter une connexion

    • Menu File → Add Connection...
    • Ou clic droit dans la liste → Add Connection...
  3. Configurer la connexion

    ChampValeur
    HypervisorQEMU/KVM
    ConnectionCocher Connect to remote host over SSH
    Usernamevotre-user
    Hostnameserveur-kvm.example.com
  4. Valider

    Cliquez sur Connect. Si vos clés SSH sont configurées, la connexion s'établit automatiquement.

Les quatre messages ci-dessous couvrent l'essentiel des échecs de connexion, et ils se distinguent par l'endroit où la chaîne casse. Les deux premiers viennent du poste client ou des droits du compte, le troisième du serveur libvirt, le dernier n'est pas une erreur mais une lenteur. Lisez le message exact avant de changer quoi que ce soit : ils se ressemblent peu, et chacun a une cause unique.

SymptômeCause probableSolution
Permission denied (publickey)Clé SSH non configuréeConfigurer l'authentification par clé
Cannot recv data: Connection reset by peerUtilisateur pas dans groupe libvirtsudo usermod -aG libvirt user
error: failed to connect socketlibvirt non démarré sur le serveursudo systemctl start libvirtd
Connexion très lenteRésolution DNS inverseAjouter UseDNS no dans /etc/ssh/sshd_config

Tester la connexion manuellement :

Fenêtre de terminal
# Vérifier que le socket est accessible via SSH
ssh user@serveur-kvm "ls -la /run/libvirt/libvirt-sock"

Sortie attendue :

srw-rw---- 1 root libvirt 0 Jan 31 10:00 /run/libvirt/libvirt-sock

Contrairement au transport SSH, le transport TCP ouvre un véritable service réseau sur le serveur, avec son port et son authentification propres. Trois situations le justifient : une restriction réseau qui interdit SSH, une migration live entre hyperviseurs où le coût du chiffrement SSH se voit, ou un réseau de management physiquement séparé du trafic de production.

C'est systemd qui ouvre le port, pas le fichier de configuration. Sur toute distribution récente, libvirtd est lancé par activation de socket : des unités .socket détiennent les ports et démarrent le démon à la première connexion. Dans ce mode, les directives listen_tcp et listen_tls de libvirtd.conf ne servent plus à rien, et l'option --listen non plus.

Le fichier de configuration livré par la distribution le dit lui-même, juste au-dessus de ces directives :

# This setting is not required or honoured if using systemd socket
# activation.

Vérifiez d'abord que vous êtes bien dans ce cas, ce qui est la situation normale :

Fenêtre de terminal
systemctl list-unit-files 'libvirtd*.socket'

Si la liste contient libvirtd-tcp.socket et libvirtd-tls.socket, tout se règle par ces unités. Activer l'écoute se réduit alors à démarrer la bonne socket, et rien d'autre n'est à modifier dans le fichier de configuration :

  1. Démarrer la socket voulue

    Fenêtre de terminal
    sudo systemctl enable --now libvirtd-tls.socket

    Pour un lab sur réseau isolé, et en connaissance de cause, la variante non chiffrée est libvirtd-tcp.socket.

  2. Redémarrer le démon pour qu'il reprenne ses sockets

    Fenêtre de terminal
    sudo systemctl restart libvirtd
  3. Vérifier l'écoute

    Fenêtre de terminal
    ss -tlnp | grep -E '16509|16514'

    Le port 16514 correspond à TLS, le 16509 au TCP en clair.

  4. Ouvrir le pare-feu sur le port correspondant

    Fenêtre de terminal
    sudo ufw allow 16514/tcp # Ubuntu, TLS
    sudo firewall-cmd --permanent --add-port=16514/tcp && sudo firewall-cmd --reload # RHEL

    Remplacez par 16509 si vous avez délibérément choisi la socket en clair.

Les distributions qui ont migré vers les démons modulaires n'ont plus de libvirtd du tout : virtqemud, virtnetworkd et virtstoraged se partagent le travail selon le domaine, et c'est virtproxyd qui expose l'accès distant en routant les demandes vers le bon démon. La logique reste exactement la même, seules les unités changent de nom :

Fenêtre de terminal
sudo systemctl enable --now virtproxyd-tls.socket

C'est aussi le seul cas où listen_tls garde un sens : virtproxyd lit bien sa configuration, et n'a jamais eu besoin de l'option --listen. Pour savoir dans quelle configuration vous êtes, une seule commande suffit :

Fenêtre de terminal
systemctl list-unit-files 'libvirtd*.socket' 'virt*d.socket'

L'URI perd le nom d'utilisateur : il n'y a plus de compte système à traverser, donc plus rien à authentifier tant que auth_tcp vaut none. Le port 16509 étant implicite, il n'apparaît pas non plus. Depuis le client :

Fenêtre de terminal
virsh -c qemu+tcp://serveur-kvm/system list --all

Pour une connexion TCP sécurisée, utilisez TLS avec des certificats :

  1. Générer une CA et des certificats (serveur + client)
  2. Placer les certificats dans /etc/pki/libvirt/
  3. Configurer listen_tls = 1 dans libvirtd.conf

Cette configuration est plus complexe. Pour la plupart des cas, SSH reste la meilleure option.

Une fois connecté, toutes les commandes virsh fonctionnent normalement :

Fenêtre de terminal
# Définir l'URI par défaut
export LIBVIRT_DEFAULT_URI="qemu+ssh://admin@kvm-server/system"
# Lister les VMs
virsh list --all
# Voir les infos d'une VM
virsh dominfo web-prod
# Démarrer/arrêter
virsh start ma-vm
virsh shutdown ma-vm
# Console série (avec échappement Ctrl+])
virsh console ma-vm
# Voir les logs QEMU (nécessite SSH direct)
ssh admin@kvm-server "tail -f /var/log/libvirt/qemu/web-prod.log"

Comme l'URI est un simple argument, une boucle shell suffit à interroger un parc entier sans outil supplémentaire. La redirection 2>/dev/null masque les messages d'erreur de libvirt pour ne garder que le message de repli, plus lisible dans une sortie qui enchaîne plusieurs serveurs. Script pour lister les VMs de plusieurs serveurs :

#!/bin/bash
# list-all-vms.sh - Liste les VMs de tous les serveurs KVM
SERVERS="kvm1.example.com kvm2.example.com kvm3.example.com"
for server in $SERVERS; do
echo "=== $server ==="
virsh -c qemu+ssh://admin@$server/system list --all 2>/dev/null || echo " Connexion échouée"
echo ""
done

Jamais de mot de passe en clair. Configurez l'authentification par clé :

Fenêtre de terminal
# Générer une clé si nécessaire
ssh-keygen -t ed25519 -C "admin-kvm"
# Copier sur le serveur
ssh-copy-id admin@kvm-server

Sur le serveur, seuls les utilisateurs nécessaires doivent être dans le groupe libvirt :

Fenêtre de terminal
# Voir qui est dans le groupe
getent group libvirt
# Retirer un utilisateur
sudo gpasswd -d utilisateur libvirt

Ne pas utiliser root pour l'administration libvirt. Créez un compte dédié :

Fenêtre de terminal
sudo useradd -m -G libvirt kvm-admin

Les deux directives ci-dessous se complètent : AllowUsers transforme la liste des comptes autorisés en liste blanche, tout compte non cité est refusé même avec le bon mot de passe, et PermitRootLogin no ferme le compte root, cible privilégiée des attaques automatisées. Dans /etc/ssh/sshd_config :

# Autoriser seulement certains utilisateurs
AllowUsers kvm-admin@192.168.1.0/24
# Désactiver root login
PermitRootLogin no

Le pare-feu prend le relais de AllowUsers une couche plus bas : il refuse la connexion avant même la réponse de sshd, ce qui retire le serveur des scans automatisés. Les deux commandes font la même chose avec les deux outils les plus répandus, ufw sur Ubuntu et firewalld sur RHEL. SSH uniquement depuis les postes d'administration :

Fenêtre de terminal
# UFW (Ubuntu)
sudo ufw allow from 192.168.1.100 to any port 22
# firewalld (RHEL/Fedora)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port port="22" protocol="tcp" accept'

Les deux journaux ne racontent pas la même histoire et se lisent ensemble. last donne les ouvertures de session sur le serveur, avec l'adresse d'origine ; le journal de libvirtd donne les clients libvirt qui se sont réellement connectés au socket. Un écart entre les deux signale un accès qui ne passe pas par le chemin prévu. Vérifiez régulièrement les connexions :

Fenêtre de terminal
# Dernières connexions SSH
last -a | head -20
# Logs libvirt
journalctl -u libvirtd | grep -i "client"

Pour gérer plusieurs serveurs KVM, voici une architecture recommandée :

Architecture multi-hôtes libvirt

Dans virt-manager, vous pouvez ajouter les 3 connexions et basculer facilement entre les hôtes.

Ces cinq messages reviennent en boucle, et quatre d'entre eux ne parlent pas de libvirt alors qu'ils s'affichent au lancement de virsh : ils viennent du transport, du service ou des droits. La bonne réflexe est de situer le message avant de chercher une cause : un refus de clé publique est un problème SSH, un refus d'authentification libvirt est un problème de groupe, et une fin de fichier en pleine lecture trahit un écart de version entre client et serveur.

ErreurCauseSolution
Failed to connect socket to '/run/libvirt/libvirt-sock'libvirt non démarrésudo systemctl start libvirtd
authentication failedUtilisateur pas dans groupe libvirtsudo usermod -aG libvirt user
Permission denied (publickey)Pas de clé SSHConfigurer ssh-copy-id
Connection refusedPort non ouvert ou service arrêtéVérifier firewall et service
error: End of file while reading dataVersion libvirt incompatibleMettre à jour client/serveur

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

6 questions
6 min.
70% requis

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

  1. SSH est la méthode recommandée, simple, sécurisé, pas de config serveur
  2. URI = qemu+ssh://user@host/system, mémorisez ce format
  3. Groupe libvirt obligatoire, sur le serveur, pour l'utilisateur distant
  4. Clés SSH = confort, évite les mots de passe à chaque commande
  5. TCP sans TLS = danger, uniquement sur réseau isolé de confiance
  6. virt-manager = multi-hôtes, gérez tous vos serveurs depuis une interface

Ce site vous est utile ?

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

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. 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