Aller au contenu

API REST Proxmox : premiers appels

Day 2 · ExploiterNiveau 3 · MaîtriserCoursRédigé · à valider en lab

Tout ce que fait la GUI Proxmox VE passe par une API REST JSON exposée sur https://<nœud>:8006/api2/json/. Savoir l'appeler avec curl vous permet de scripter l'inventaire, la supervision ou des actions simples, et de comprendre ce que font Terraform et Ansible sous le capot.

Notions clés

Notion Détail
URL de base https://pve01.corp.local:8006/api2/json/ (aussi /api2/extjs/ pour la GUI)
Arborescence /cluster, /nodes/{node}, /storage, /access, /pools, /version
Verbes GET lit, POST crée ou lance une action, PUT modifie, DELETE supprime
Réponse Objet JSON avec un champ data
Tâches asynchrones Une action longue (démarrage, clone, sauvegarde) renvoie un UPID à suivre
N'importe quel nœud Chaque nœud du cluster accepte tous les appels et relaie vers le bon nœud
Référence API Viewer ou pvesh usage <chemin> --verbose

Deux façons de s'authentifier

Ticket (session) Jeton API
Obtention POST /access/ticket avec utilisateur et mot de passe (et 2FA) Créé une fois avec pveum user token add
Envoi Cookie PVEAuthCookie + en-tête CSRFPreventionToken pour POST/PUT/DELETE En-tête Authorization: PVEAPIToken=USER@REALM!ID=SECRET
Durée 2 heures, renouvelable Jusqu'à expiration ou révocation
Usage Scripts interactifs, tests Outils automatisés (recommandé)
flowchart LR
    S[Script] -->|PVEAPIToken=...| P[pveproxy :8006 sur pve01]
    P --> D[pvedaemon : contrôle des ACL]
    D -->|action sur pve02| R[relais vers pve02]
    D -->|réponse JSON / UPID| S

Premiers appels avec un jeton

Créez un jeton en lecture seule pour vos essais, comme décrit dans Jetons API et comptes de service, puis :

export PVE='https://pve01.corp.local:8006/api2/json'
export AUTH='Authorization: PVEAPIToken=svc-monitoring@pve!zabbix=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

curl -s -H "$AUTH" "$PVE/version" | jq .data
curl -s -H "$AUTH" "$PVE/cluster/status" | jq '.data[] | {name, type, online, quorate}'
curl -s -H "$AUTH" "$PVE/cluster/resources?type=vm" \
  | jq -r '.data[] | [.vmid, .name, .node, .status] | @tsv'
curl -s -H "$AUTH" "$PVE/nodes/pve01/storage/pbs-local/status" | jq .data

Les variables sont entre guillemets simples à la déclaration : le ! du jeton ne doit pas être interprété par le shell.

Une action : démarrer une VM et suivre la tâche

Avec un jeton disposant de VM.PowerMgmt sur /vms/101 :

UPID=$(curl -s -X POST -H "$AUTH" "$PVE/nodes/pve01/qemu/101/status/start" | jq -r .data)
echo "$UPID"           # UPID:pve01:000A1B2C:...:qmstart:101:svc-ops@pve!ci:
curl -s -H "$AUTH" "$PVE/nodes/pve01/tasks/$UPID/status" | jq '.data | {status, exitstatus}'
# status "stopped" et exitstatus "OK" = tâche terminée avec succès

Le paramètre d'une modification se passe en formulaire : curl -X PUT -H "$AUTH" --data-urlencode 'description=Serveur web' "$PVE/nodes/pve01/qemu/101/config".

Avec un ticket (sans jeton)

curl -s -d 'username=jdupont@pve' --data-urlencode 'password=<mdp>' \
  "$PVE/access/ticket" | jq -r '.data | .ticket, .CSRFPreventionToken'
# appels suivants :
curl -s -b "PVEAuthCookie=<ticket>" -H "CSRFPreventionToken: <csrf>" -X POST \
  "$PVE/nodes/pve01/qemu/101/status/shutdown"

Un compte avec 2FA reçoit un ticket partiel et doit compléter le second facteur : pour l'automatisation, utilisez un jeton.

Recommandations MSP

  • Un jeton par outil, en privsep 1, avec le rôle minimal. Jamais le mot de passe root@pam dans un script.
  • Vérifier le certificat : évitez -k. Utilisez un certificat valide ou --cacert /etc/pve/pve-root-ca.pem copié sur le poste client.
  • Viser un FQDN ou une IP de nœud stable ; pour un cluster, prévoir une liste de nœuds de repli dans le script.
  • Les appels de lecture sont libres pour le client. Les appels qui modifient cluster, Ceph, SDN ou HA restent soumis à la matrice de responsabilité.
  • Pour l'API PBS : même logique sur le port 8007, en-tête Authorization: PBSAPIToken=....

Pièges vus en support

  • 401 No ticket : en-tête mal formé, souvent un ! mangé par le shell ou un espace en trop.
  • 403 Permission check failed : jeton en privsep 1 sans ACL propre, ou chemin non couvert.
  • 501 Method not implemented : mauvais verbe HTTP (GET au lieu de POST sur status/start).
  • Script qui enchaîne des actions sans attendre la fin de la tâche (UPID) : verrous lock: clone, VM non démarrée.
  • Boucle de supervision trop agressive (plusieurs appels par seconde) : charge inutile sur pveproxy. Préférer /cluster/resources en un appel.

Testez-vous

  1. Quel point d'API donne en un appel l'état de toutes les VM du cluster ?

    Réponse

    GET /cluster/resources?type=vm.

  2. Un POST .../status/start répond tout de suite. La VM est-elle démarrée ?

    Réponse

    Pas forcément : la réponse est un UPID de tâche. Il faut suivre /nodes/{node}/tasks/{upid}/status jusqu'à status: stopped et exitstatus: OK.

  3. Quel en-tête est obligatoire, en plus du cookie, pour une écriture avec un ticket ?

    Réponse

    CSRFPreventionToken. Il n'est pas nécessaire avec un jeton API.

  4. Comment trouver les paramètres acceptés par /nodes/{node}/qemu/{vmid}/config ?

    Réponse

    Dans l'API Viewer ou avec pvesh usage /nodes/pve01/qemu/101/config --verbose.

Pour aller plus loin