Connexion à une machine virtuelle sous proxmox avec SPICE (et un script)

SPICE n’est pas que le qualificatif d’un collectif de jeunes chanteuses à la mode il y a quelques années, c’est aussi un protocole d’affichage distant de machines maintenu par Red Hat. Il est entre autres implémenté par la solution de virtualisation proxmox que j’utilise avec bonheur à la maison.

Côté machine virtuelle, il faut installer l’agent SPICE correspondant à l’OS utilisé; pour des guest linux, les packages sont disponibles dans les dépôts standards des distributions courantes.

Côté client désirant se connecter, SPICE nécessite l’utilisation d’un logiciel client. Il en existe de toutes sortes mais ici on utilisera virt-viewer pour windows.

Une fois le client installé, on se rend vite compte que se connecter à l’interface d’administration de proxmox, sélectionner la machine virtuelle sur laquelle on veut se connecter, puis dérouler le menu console et choisir SPICE, télécharger le fichier de connexion puis l’ouvrir avec virt-viewer, est une procédure assez pénible à réaliser. Voyons une solution alternative permettant une connexion à une machine virtuelle sous proxmox avec SPICE et un script.

Heureusement chez proxmox ce sont des gens biens, et ils fournissent une API REST pour pouvoir interagir avec leur produit. Ainsi voici une solution pour se connecter à une machine virtuelle sous proxmox avec spice et un script, en exemple ci-dessous:

# script de connexion à un bureau distant proxmox
# en utilisant le client SPICE
# nécessite probablement powershell 6

$api_host = "mon_hote_proxmox"
$api_port = "mon_port_proxmox"


function connectToProxmox {
  param (
    [parameter(mandatory)][string]$vmid
  )
  
  $credentials = get-credential
  if ($credentials.UserName.split("@")[1]) {
    $username = $credentials.UserName}
  else {
    write-host "no realm, authenticating against PAM"
    $username = $credentials.UserName + "@pam"}
  $password = $credentials.GetNetworkCredential().Password
  
  $body = @{
            username = $username
            password = $password
          }
  
  try { $response = Invoke-RestMethod -SkipCertificateCheck -uri https://${api_host}:${api_port}/api2/json/access/ticket -Method Post -Body $body -SessionVariable "session" }
  catch {
    write-host -foreground Red "ERREUR : mauvais login ou mot de passe, ou problème de connexion à l'hôte"
    start-sleep 5
    exit
  }
  
  $ticket = $response.data.ticket
  $token = $response.data.CSRFPreventionToken

  $session.Headers.Add("CSRFPreventionToken","$token")
  $session.Headers.Add("Cookie","PVEAuthCookie=$ticket")

  $response = Invoke-WebRequest -SkipCertificateCheck -Method Post -uri https://${api_host}:${api_port}/api2/spiceconfig/nodes/${api_host}/qemu/$vmid/spiceproxy -websession $session -Body "proxy=$api_host"
  
  $spicedata = ($response.RawContent -match ".*(\[virt-viewer\](.|\r|\n)*)")
  write-output $Matches[1] | Out-file $env:temp\$vmid.vv
  
  start "C:\Program Files\VirtViewer v7.0-256\bin\remote-viewer.exe" $env:temp\$vmid.vv
  
}

connectToProxmox

Ce script s’inspire largement d’un script bash gentiment publié  dans les forums du projet proxmox.

Tout d’abord il faut connaître l’id de la machine sur laquelle on veut réaliser la connexion SPICE, on la trouve dans l’interface de proxmox.

Par défaut le script vérifie si on s’authentifie auprès d’une source d’identité tierce configurée dans proxmox (comme un annuaire ldap), si ce n’est pas le cas l’authentification est effectuée en se tournant vers le pam local du serveur.

On voit que la connexion à l’API proxmox implique l’utilisation de deux variables de session obtenues après validation du login/password, le PVEAuthCookie et le CSRFPreventionToken, qu’il faudra fournir dans l’entête de toutes nos requêtes.

Pas d’inquiétude pour une éventuelle saturation du %tmp% par des fichiers .vv à force de connexions, le client virt-viewer se charge de les supprimer à chaque fois (c’est un paramètre décrit dans le fichier .vv).

Le chemin du client virt-viewer est à adapter en fonction de l’environnement, car on voit qu’il dépend de la version du client, et peut-être également de la version de windows où il est installé.

Notons que mon environnement proxmox utilise un certificat ssl autosigné, qui est celui généré par défaut lors de l’installation du produit. Si, comme dans mon cas on ne souhaite pas faire l’effort d’importer le CA qui a généré le certificat, il faudra demander aux cmdlets powershell invoke-restmethod et invoke-webrequest de ne pas vérifier la validité du certificat du serveur (ce qui est mal en principe…) en utilisant le paramètre -skipcertificatcheck. Le problème est que powershell, dans sa version 5, qui est la version fournie avec windows 10 ne propose pas ce paramètre pour ces cmdlets. Il faudra donc installer powershell 6 (core) qui lui le fournit. Remarquons au passage l’initiative opensource de microsoft sur ce coup-là mais chut, pas de politique ici…

Du coup en bonus, ci-dessous les clés de registre sympathiques nous permettant de faire un clic droit sur le fichier du script -> exécuter avec powershell 6 pour que ce soit ergonomique.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Microsoft.PowerShellScript.1\Shell\lancer_w_pwsh6]
@="Exécuter avec powershell 6"
"icon"="C:\\Program Files\\PowerShell\\6\\pwsh.exe"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Microsoft.PowerShellScript.1\Shell\lancer_w_pwsh6\Command]
@="C:\\Program Files\\PowerShell\\6\\pwsh.exe %1"

o/

 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *