Edu-Kit — Onboarding d’un Proxmox client
1. Vue d’ensemble
Ce document décrit les appels API et commandes SSH nécessaires pour intégrer un Proxmox VE client dans la plateforme Edu-Kit. L’onboarding configure les accès et permissions requis par VmService, et établit le contrat entre l’infrastructure (OPS) et le backend.
L’ensemble des étapes est automatisé par le script onboard-proxmox.sh. Ce document sert de référence pour comprendre ce que le script fait et pour le reproduire manuellement si besoin.
Architecture
┌──────────────────┐ ┌──────────────────────────────────────────────┐
│ Edu-Kit │ │ Proxmox Client (PVE 8.x) │
│ │ │ │
│ - VmService │ HTTPS │ edukit-api@pve │
│ (clones, VMs) │◄───────►│ └── Token vm-service │
│ │ │ └── Rôle EduKitRole (VM + SDN) │
│ - OPS (admin) │ SSH │ │
│ │◄───────►│ edukit-deploy (snippets cloud-init) │
└──────────────────┘ │ └── /var/lib/vz/snippets/ │
│ │
│ Templates cloud-init (VMID 9xxx) │
│ └── Debian 12, Ubuntu 24.04… │
└──────────────────────────────────────────────┘
Authentification
| Contexte | Mécanisme | Header |
|---|---|---|
| Onboarding (script OPS) | Ticket root@pam, valide 2h | Cookie PVEAuthCookie={ticket} + CSRFPreventionToken: {csrf} |
| VmService (runtime) | Token API, sans expiration | Authorization: PVEAPIToken=edukit-api@pve!vm-service={secret} |
L’onboarding utilise root@pam pour créer les ressources. VmService utilise ensuite exclusivement le token — root@pam ne lui est jamais transmis.
2. Onboarding initial (une seule fois par Proxmox)
Déclencheur : un nouvel établissement apporte son propre Proxmox VE. L’admin OPS exécute onboard-proxmox.sh depuis n’importe quelle machine.
bash onboard-proxmox.sh --host <IP> --password <root_password> --node <noeud>
2.1 Authentification root@pam
POST /access/ticket
{ "username": "root@pam", "password": "<password>" }
Retourne
{ data: { ticket, CSRFPreventionToken } }. Le ticket est injecté en cookie sur tous les appels suivants. LeCSRFPreventionTokenest requis en header sur toutes les requêtes mutantes (POST / PUT / DELETE).
2.2 Compte de service
Créer un user dédié dans le realm pve (authentification interne Proxmox, pas PAM). Ce user n’a pas de mot de passe — il s’authentifie uniquement via son token API.
POST /access/users
{ "userid": "edukit-api@pve", "comment": "EduKit service account (VmService)" }
Si le user existe déjà (relance du script), Proxmox retourne HTTP 500
already exists. Le script l’ignore et continue — comportement idempotent.
2.3 Rôle et permissions
Créer le rôle avec les privilèges minimaux nécessaires à VmService (principe de moindre privilège) :
POST /access/roles
{
"roleid": "EduKitRole",
"privs": "VM.Allocate,VM.Audit,VM.Clone,VM.Config.CDROM,VM.Config.CPU,VM.Config.Cloudinit,VM.Config.Disk,VM.Config.HWType,VM.Config.Memory,VM.Config.Network,VM.Config.Options,VM.Console,VM.Migrate,VM.PowerMgmt,Datastore.Allocate,Datastore.AllocateSpace,Datastore.Audit,SDN.Use"
}
SDN.Useest obligatoire dès quevmbr0appartient à une zone SDN Proxmox (config par défaut sur les installations récentes). Sans ce privilège, le clone retourne403 Permission check failed (/sdn/zones/localnetwork/vmbr0, SDN.Use).
VM.Consolecouvre également l’accès au QEMU guest agent (network-get-interfaces).VM.MonitoretVM.GuestAgent.*n’existent pas sur Proxmox VE 8.x — les inclure fait échouer la création du rôle.
Assigner le rôle sur le datacenter entier, avec propagation aux ressources enfants :
PUT /access/acl
{ "path": "/", "users": "edukit-api@pve", "roles": "EduKitRole", "propagate": 1 }
2.4 Token API
POST /access/users/edukit-api@pve/token/vm-service
{ "privsep": 0, "comment": "EduKit VmService token" }
privsep=0: le token hérite des permissions du user sans restriction supplémentaire.Le secret UUID n’est retourné qu’une seule fois. Si le script est relancé, l’ancien token est supprimé et recréé (le secret change). Stocker immédiatement dans Vaultwarden.
Le retour contient { data: { value: "<secret_uuid>" } }. VmService l’utilise avec :
Authorization: PVEAPIToken=edukit-api@pve!vm-service=<secret>
2.5 Utilisateur SSH pour les snippets cloud-init
VmService dépose les fichiers cloud-init (user-data, network-config) sur le nœud via SFTP avant chaque démarrage de VM. Un user système dédié est créé via SSH root :
# Créer le user système
useradd -m -s /bin/bash edukit-deploy
# Déployer la clé publique ed25519 générée localement
mkdir -p /home/edukit-deploy/.ssh
echo "<clé_publique>" >> /home/edukit-deploy/.ssh/authorized_keys
chmod 700 /home/edukit-deploy/.ssh
chmod 600 /home/edukit-deploy/.ssh/authorized_keys
chown -R edukit-deploy:edukit-deploy /home/edukit-deploy/.ssh
# Donner l'accès en écriture au répertoire des snippets
mkdir -p /var/lib/vz/snippets
chown edukit-deploy:edukit-deploy /var/lib/vz/snippets
chmod 755 /var/lib/vz/snippets
La paire de clés ed25519 est générée localement par le script (
ssh-keygen). La clé privée est affichée en sortie et doit être stockée dansHypervisorCluster.SshPrivateKey(chiffrée AES-256-GCM dans la base Edu-Kit).
2.6 Stockage local — content-type images
Sans ce paramètre, Proxmox ne peut pas écrire l’ISO cloud-init (ide2: local:cloudinit) au démarrage des VMs, avec l’erreur : storage 'local' does not support content-type 'images'.
Lire d’abord le contenu actuel pour ne pas écraser une configuration existante :
GET /storage/local
→ { data: { content: "iso,vztmpl,backup" } }
Ajouter images uniquement s’il est absent :
PUT /storage/local
{ "content": "iso,vztmpl,backup,images" }
2.7 Firewall datacenter et nœud
Voir doc-ops-proxmox-network-et-bastion.md — sections 2.2 et 2.3.
2.8 Installation dnsmasq
Voir doc-ops-proxmox-network-et-bastion.md — section 2.1.
Sortie — paramètres HypervisorCluster
En fin d’onboarding, le script affiche le bloc à renseigner dans l’entité HypervisorCluster de VmService :
| Champ | Valeur |
|---|---|
BaseUrl |
https://{proxmox_host}:8006 |
ApiTokenUser |
edukit-api@pve |
ApiTokenId |
vm-service |
ApiTokenSecret |
<secret_uuid> — chiffré AES-256-GCM en base |
DefaultNode |
nom du nœud (auto-détecté) |
VerifySsl |
false en lab, true avec CA valide en prod |
SshHost |
{proxmox_host} |
SshPort |
22 |
SshUsername |
edukit-deploy |
SshSnippetsPath |
/var/lib/vz/snippets |
VmBridge |
vmbr0 |
VmCloudInitStorage |
local-lvm |
VmSnippetsStorage |
local |
Résumé du flux
Admin lance onboard-proxmox.sh
│
├──► Proxmox API : authentification root@pam → ticket
│
├──► Proxmox API : créer user edukit-api@pve
│
├──► Proxmox API : créer rôle EduKitRole + assigner sur /
│
├──► Proxmox API : créer token vm-service → secret (une seule fois)
│
├──► SSH nœud : créer user edukit-deploy + déployer clé SSH
│
├──► Proxmox API : activer content-type images sur stockage local
│
├──► Proxmox API : firewall datacenter (règles ACCEPT + policy DROP)
│
├──► Proxmox API : firewall nœud (nftables + FORWARD DROP inter-zone)
│
└──► SSH nœud : installer dnsmasq (désactivé, géré par SDN)
Sortie → bloc HypervisorCluster à saisir dans Edu-Kit
3. Gestion des templates cloud-init
Les templates sont des VMs Proxmox converties en modèle immuable (qm template). VmService les clone pour créer les VMs étudiantes. Le VMID est référencé dans OsImage.ProxmoxTemplateId.
Le script manage-templates.sh automatise ces opérations.
3.1 Lister les templates existants
GET /nodes/{node}/qemu
Filtrer les VMs avec template == 1. Le VMID retourné est la valeur à renseigner dans OsImage.ProxmoxTemplateId (chaîne, ex: "9999").
3.2 Ajouter un template
Tout se passe sur le nœud via SSH root. La cloud image est téléchargée directement depuis les dépôts officiels.
# 1. Télécharger la cloud image sur le nœud
wget -q --continue \
-O /var/lib/vz/template/iso/debian-12-genericcloud-amd64.qcow2 \
https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2
# 2. Créer la VM porteuse
qm create <VMID> \
--name "debian-12-bookworm-cloud-init" \
--memory 2048 --cores 2 \
--net0 virtio,bridge=vmbr0 \
--scsihw virtio-scsi-pci \
--agent enabled=1,fstrim_cloned_disks=1 \
--serial0 socket --vga serial0
# 3. Importer le disque dans le stockage
qm importdisk <VMID> /var/lib/vz/template/iso/debian-12-genericcloud-amd64.qcow2 local-lvm
# 4. Câbler le disque comme scsi0 + attacher le lecteur cloud-init
qm set <VMID> --scsi0 local-lvm:vm-<VMID>-disk-0
qm set <VMID> --ide2 local:cloudinit
qm set <VMID> --boot order=scsi0 --ipconfig0 ip=dhcp
# 5. Convertir en template immuable
qm template <VMID>
# 6. Nettoyer l'image source
rm -f /var/lib/vz/template/iso/debian-12-genericcloud-amd64.qcow2
--agent enabled=1,fstrim_cloned_disks=1: active le QEMU guest agent dans le template. Sans ça, VmService ne peut pas récupérer l’IP de la VM viaGET /nodes/{node}/qemu/{vmid}/agent/network-get-interfaceset la VM reste inaccessible.
--ide2 local:cloudinit: le lecteur cloud-init doit être sur un stockage avec le content-typeimagesactivé (voir section 2.6). Proxmox génère une ISO à la volée à chaque démarrage en y injectant clé SSH, user, réseau.Après
qm template, la VM ne peut plus démarrer directement — elle est une source de clonage uniquement.
3.3 Supprimer un template
DELETE /nodes/{node}/qemu/{vmid}?destroy-unreferenced-disks=1
Retourne un UPID (tâche asynchrone). Attendre
status == "stopped"etexitstatus == "OK"viaGET /nodes/{node}/tasks/{upid}/statusavant de retirer le VMID deOsImage.ProxmoxTemplateIddans VmService — sinon le prochain provisionnement échoue en silence.
Catalogue des images supportées
| OS | URL officielle | VMID conseillé |
|---|---|---|
| Debian 12 Bookworm | https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2 |
9999 |
| Debian 11 Bullseye | https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2 |
9998 |
| Ubuntu 24.04 Noble | https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img |
9997 |
| Ubuntu 22.04 Jammy | https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img |
9996 |
4. Points d’attention
Token API : secret visible une seule fois
Proxmox retourne le secret UUID uniquement à la création. Si le script est relancé, l’ancien token est supprimé et recréé — le secret change. Toujours stocker dans Vaultwarden immédiatement après l’onboarding.
Tâches asynchrones Proxmox
Clone, suppression et conversion en template sont des opérations asynchrones. Elles retournent un UPID, pas un résultat direct. Toujours poller GET /nodes/{node}/tasks/{upid}/status jusqu’à status == "stopped" et exitstatus == "OK" avant de continuer.
SDN.Use obligatoire sur les installs récentes
Proxmox 8.x rattache vmbr0 à une zone SDN par défaut sur les nouvelles installations. Sans SDN.Use dans EduKitRole, le clone retourne 403 même si tous les autres privilèges VM sont présents.
Ordre des règles firewall du nœud
Les règles FORWARD ACCEPT intra-zone doivent toujours être avant la règle FORWARD DROP globale. Utiliser le paramètre pos pour insérer à la bonne position. Voir doc-ops-proxmox-network-et-bastion.md.
Changements qui cassent VmService
Se coordonner avec l’équipe backend avant d’effectuer ces actions :
- Supprimer ou renuméroter un template référencé dans
OsImage.ProxmoxTemplateId - Révoquer ou faire tourner le token
vm-servicesans mettre à jour le secret dans Edu-Kit - Retirer un privilège de
EduKitRole, en particulierVM.Clone,VM.ConsoleouSDN.Use - Changer le port SSH, le nom d’utilisateur ou les
authorized_keysdeedukit-deploy - Déplacer
/var/lib/vz/snippets/ou retirer le droit d’écriture àedukit-deploy