pve-confsync
Synchronisation d'une partie de la configuration d'un cluster Proxmox VE 9.x « référence » vers N clusters « clients », via l'API PVE et des tokens API. Sens unique référence → clients. Pas de VM, pas de disques.
État : phase 0 (CLI). Export, diff et apply en YAML pour les options datacenter et le SDN (zones VLAN/VXLAN, VNets, subnets). Testé contre un faux serveur PVE ; pas encore testé sur les clusters de labo.
Périmètre
Type (kind) |
API | Politique par défaut |
|---|---|---|
datacenter-options |
/cluster/options |
tag-style, registered-tags, user-tag-access, next-id en sync, le reste ignoré ; webauthn, u2f, http_proxy jamais synchronisés |
sdn-zone (vlan, vxlan) |
/cluster/sdn/zones |
nodes, bridge, peers, fabric, dns, reversedns, dnszone en override (mapping client) ; le reste en sync |
sdn-vnet |
/cluster/sdn/vnets |
sync |
sdn-subnet |
/cluster/sdn/vnets/{vnet}/subnets |
sync |
Hors périmètre v1 : EVPN (et les zones simple, QinQ, faucet, avec leurs VNets, ignorées avec un avertissement), firewall, storage, pools/ACL, jobs, secrets.
Détail des routes, schémas et droits, avec les sources : docs/api-pve.md.
Fonctionnement
lecture source -> normalisation -> diff -> plan -> apply -> vérification
- Lecture : la référence est lue en configuration SDN appliquée (
running=1) ; les clients en configuration courante. Chaque cluster est refusé si un nœud en ligne n'est pas en PVE 9.x (/nodes/{node}/version). - Normalisation : objets JSON génériques → champs canoniques (chaînes, listes triées, property strings à clés triées). Les champs calculés par PVE sont retirés.
- Politiques :
sync(copie de la référence),ignore,override(valeur fournie uniquement par lemappingdu client). Le mapping d'un client est prioritaire sur la référence. Résolution : politique du client → politique globale → défaut de l'adaptateur. - Plan : création / mise à jour (champs modifiés, champs à supprimer) ; suppression
d'objets uniquement avec
prune(option explicite), dépendants d'abord. Erreurs bloquantes : champ obligatoire absent à la création (ex.bridged'une zone VLAN sans mapping), champ immuable modifié (type de zone, vnet d'un subnet). - Apply SDN :
POST /cluster/sdn/lock→ écritures aveclock-token→PUT /cluster/sdn(commit + rechargement réseau, suivi de la tâche). Toute erreur avant le commit déclenchePOST /cluster/sdn/rollback. Le verrou est refusé si le client a déjà des changements SDN en attente : on ne mélange pas nos modifications avec celles de quelqu'un d'autre. - Vérification : relecture du client, nouveau plan qui doit être vide, et aucune zone en
errorsur les nœuds (/nodes/{node}/sdn/zones).
Utilisation
go build -o pve-confsync ./cmd/pve-confsync
cp examples/confsync.example.yaml confsync.yaml # puis adapter
./pve-confsync check # accès, version 9.x, droits des tokens
./pve-confsync export -o ref.yaml # état normalisé de la référence (versionnable dans Git)
./pve-confsync diff # écarts par client ; code retour 2 s'il y en a
./pve-confsync diff -format json
./pve-confsync apply # dry-run (défaut) : affiche le plan, n'écrit rien
./pve-confsync apply -client site-a -confirm # applique ; SDN : saisir le nom du client
./pve-confsync apply -source ref.yaml -confirm -yes # depuis un export Git, sans question
Avec docker compose (images et utilisateur non privilégié alignés sur Logstream) :
mkdir -p secrets && printf '%s' 'xxxxxxxx-...' > secrets/pve_ref
chmod 600 secrets/* && sudo chown 10001 secrets/* # lisibles par l'utilisateur du conteneur uniquement
docker compose run --rm confsync check
docker compose run --rm confsync apply -confirm
Sécurité
- Secrets des tokens : jamais dans le YAML (
token_secreten clair est refusé) ; lus depuis une variable d'environnement (token_secret_env) ou un fichier (token_secret_file, secret docker). Ils ne sont ni affichés ni journalisés. Le chiffrement au repos arrive avec le stockage SQLite (phase 1). - TLS :
fingerprint(pinning SHA-256 du certificat, adapté aux certificats auto-signés PVE),ca_file, ouinsecure: trueréservé au labo. - Tokens (privilege separation activée, l'ACL doit être posée sur l'utilisateur et le token) :
# référence : lecture seule
pveum role add ConfSyncRO --privs "Sys.Audit SDN.Audit"
pveum user add confsync@pve
pveum user token add confsync@pve ro --privsep 1
pveum acl modify / --users confsync@pve --roles ConfSyncRO
pveum acl modify / --tokens 'confsync@pve!ro' --roles ConfSyncRO
# clients : Sys.Modify uniquement si les options datacenter sont synchronisées
pveum role add ConfSyncRW --privs "Sys.Audit Sys.Modify SDN.Audit SDN.Allocate"
check signale un token de référence capable d'écrire et un token client à qui il manque
un droit.
Arborescence
cmd/pve-confsync/ CLI (check, export, diff, apply)
internal/pve/ client API : token, TLS, form-encoding, version, tâches
internal/pve/pvetest/ faux serveur PVE 9.x pour les tests
internal/model/ objets génériques, snapshot YAML, valeurs canoniques
internal/adapter/ un adaptateur par type : routes, champs calculés, locaux, immuables
internal/config/ configuration YAML : clusters, politiques, mappings, sélection
internal/engine/ lecture, plan, apply (verrou SDN, rollback), vérification
docs/api-pve.md routes et schémas vérifiés dans les sources PVE
Tests : go test ./... (bout en bout contre le faux serveur : synchro complète, mapping
manquant, rollback sur erreur, refus de PVE 8, prune et ordre de suppression, forme
canonique des options datacenter, CLI dry-run/apply/export).
Phasage
- CLI export / diff / apply YAML (options datacenter, tags, SDN). ← ici
- UI lecture seule : clusters, diff visuel par client. Ergonomie reprise de Logstream
(
web/index.html,style.css,app.js,login.html, auth locale + OIDC, audit) ; SQLite (clusters, profils, mappings, historique, audit), secrets chiffrés. - UI d'action : Dry-run / Synchroniser (par objet, par client, global), journal des exécutions.
- Planification, détection de dérive en lecture seule, notifications.
Reste à faire avant la phase 1
- Valider sur les deux clusters de labo : forme réelle des réponses (
nodes,dhcp-range, booléens), comportement dePUT /cluster/optionsavecdelete. - Exploiter
GET /cluster/sdn/dry-run(diff frr / interfaces, PVE ≥ 9.2 environ) pour enrichir le dry-run SDN. - Rechargement en échec après commit : aujourd'hui signalé, pas d'annulation automatique (la configuration appliquée est déjà la nouvelle).