proxmox : pools créés, jeton normalisé, reliquat de voûte supprimé
Reconnaissance en lecture seule de l'API du cluster, avec le jeton de la voûte.
Trois valeurs devinées étaient fausses, et deux défauts bloquants sont apparus.
Corrigé d'après le cluster
- stockages : truenas-dbsql manquait ; le catalogue ne garde que ceux qui
portent `images` (PBS, cephFS, local et truenas iSCSI n'accueillent pas de
disque de VM) ;
- ponts : vmbr0 avait été omis, et l'uniformité sur les trois nœuds n'avait pas
été vérifiée — un pont partiel empêche la VM de démarrer sur certains nœuds.
Pools
Chezlepro-17 et Technolibre-11 créés, dérivés comme le reste. Les pools
Env.Tenant antérieurs (Prod.Chezlepro, Lab.KBR...) sont l'ancien monde : on n'y
touche pas et on n'y verse pas la flotte générée. Diff réel : 2 pools ajoutés,
0 retiré, 1 VM sur 38 déplacée — infra-pki-01, qui n'avait aucun pool.
Défaut bloquant : make creer-vm aurait échoué en 401
proxmoxer recompose `utilisateur!nom` à partir d'api_user et d'api_token_id. La
voûte stocke la forme complète, que les playbooks passaient telle quelle, d'où
un 401 muet — alors que le même jeton fonctionne en curl. Mesuré des deux côtés
avec un module en lecture seule : forme complète = 401, forme courte = OK.
Normalisation par split('!') | last, qui accepte les deux écritures.
Reliquat proxmox.vault.yml supprimé
Toléré « en compatibilité », il restait le seul porteur du jeton chez
Technolibre — et comme *.vault.yml est gitignoré, ce jeton ne voyageait avec
aucun dépôt : une voûte unique (D-19) qui ne l'était pas. Migration faite en
mémoire, avec relecture et aller-retour de chiffrement vérifiés avant écriture ;
fichier supprimé, listes de chargement des playbooks nettoyées, validé par un
appel API réel ne chargeant que all/vault.yml.
La garde qui manquait
voute.py verifier ne comparait que le gabarit — il disait « complet » pendant
qu'un secret vivait ailleurs. Il contrôle maintenant aussi la voûte réelle quand
ANSIBLE_VAULT_PASSWORD_FILE la rend déchiffrable : noms de clés seulement,
jamais de valeur, et vérification sautée sans mot de passe.
Elle a trouvé un second trou dès son premier passage : la voûte réelle de
Technolibre n'a ni vault_nextcloud_admin ni vault_nextcloud_oidc, que le plan
exige. Non corrigé — générer ces secrets est une décision, et celui d'OIDC doit
correspondre à ce que Keycloak connaîtra.
27 preuves OK. --syntax-check et ansible-lint (production) sur les playbooks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
60a60b6fb1
commit
4dd3d46412
9 changed files with 182 additions and 26 deletions
66
CHANGELOG.md
66
CHANGELOG.md
|
|
@ -1,5 +1,71 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-08-03 (suite 13) — le cluster répond, et il contredit trois hypothèses
|
||||
|
||||
Reconnaissance **en lecture seule** de l'API Proxmox, avec le jeton de la voûte. Trois
|
||||
valeurs que j'avais devinées étaient fausses, et deux défauts bloquants sont apparus.
|
||||
|
||||
### Ce que le cluster a corrigé
|
||||
|
||||
**Stockages** : `truenas-dbsql` manquait à ma liste. Et le catalogue ne doit offrir que
|
||||
ceux qui portent `images` — `PBS`, `cephFS`, `local` et `truenas` (iSCSI brut,
|
||||
`content=none`) n'accueillent pas de disque de VM.
|
||||
|
||||
**Ponts** : `vmbr0` à `vmbr3`, vérifiés présents sur les **trois** nœuds. J'avais omis
|
||||
`vmbr0` et je n'avais pas contrôlé l'uniformité — un pont partiel est un piège, la VM ne
|
||||
démarre que sur certains nœuds.
|
||||
|
||||
**Un troisième homonyme** : `web-frontal-01` (vmid 911401) existe déjà hors Set-OPS, sans
|
||||
pool. Les deux tenants en planifient un chacun.
|
||||
|
||||
### Les pools sont créés
|
||||
|
||||
`Chezlepro-17` et `Technolibre-11`, dérivés comme le reste. Les pools `Env.Tenant`
|
||||
antérieurs (`Prod.Chezlepro`, `Lab.KBR`…) sont **l'ancien monde : on n'y touche pas**, et
|
||||
on n'y verse pas la flotte générée — les mélanger effacerait la frontière que Set-OPS
|
||||
établit.
|
||||
|
||||
Diff constaté sur le cluster : 2 pools ajoutés, 0 retiré, **1 VM sur 38** déplacée —
|
||||
`infra-pki-01`, qui n'appartenait à aucun pool.
|
||||
|
||||
### Défaut bloquant : `make creer-vm` aurait échoué en 401
|
||||
|
||||
`proxmoxer` recompose `utilisateur!nom` à partir d'`api_user` et d'`api_token_id`. La
|
||||
voûte stocke la forme complète, que les playbooks passaient telle quelle — d'où
|
||||
`ansible@pve!ansible@pve!nom` et un **401 muet**, alors que le même jeton fonctionne en
|
||||
`curl`. Le diagnostic aurait coûté cher.
|
||||
|
||||
Mesuré des deux côtés avec un module en lecture seule : forme complète = 401, forme
|
||||
courte = OK, 3 nœuds. Les playbooks normalisent désormais (`split('!') | last`), ce qui
|
||||
accepte les deux écritures.
|
||||
|
||||
### Le reliquat `proxmox.vault.yml` est supprimé
|
||||
|
||||
Toléré « en compatibilité », il restait le **seul** porteur du jeton chez Technolibre. Et
|
||||
comme `*.vault.yml` est gitignoré, ce jeton ne voyageait avec aucun dépôt : une voûte
|
||||
unique (D-19) qui ne l'était pas.
|
||||
|
||||
Migration faite **en mémoire** — aucune valeur en clair sur disque ni affichée — avec
|
||||
relecture et aller-retour de chiffrement vérifiés avant écriture. Puis suppression du
|
||||
fichier et retrait des listes de chargement des deux playbooks. Validé par un appel API
|
||||
réel ne chargeant que `all/vault.yml`.
|
||||
|
||||
### Et la garde qui manquait
|
||||
|
||||
`voute.py verifier` ne comparait que le **gabarit**. C'est pourquoi il annonçait
|
||||
« complet » pendant qu'un secret vivait ailleurs : le gabarit dit ce qu'il *faudrait*, pas
|
||||
ce qui *est*.
|
||||
|
||||
Il contrôle maintenant aussi la voûte **réelle**, quand `ANSIBLE_VAULT_PASSWORD_FILE` la
|
||||
rend déchiffrable — noms de clés seulement, jamais de valeur. Sans mot de passe, la
|
||||
vérification se **saute** : le harnais reste utilisable sans accès aux secrets.
|
||||
|
||||
Dès son premier passage, elle a trouvé un second trou : la voûte réelle de Technolibre
|
||||
n'a ni `vault_nextcloud_admin` ni `vault_nextcloud_oidc`, que le plan exige depuis
|
||||
l'arrivée de Nextcloud. Le déploiement aurait cassé sur une variable indéfinie. **Non
|
||||
corrigé** : générer ces deux secrets est une décision, et le secret OIDC doit
|
||||
correspondre à ce que Keycloak connaîtra.
|
||||
|
||||
## 2026-08-03 (suite 12) — un pool Proxmox par tenant
|
||||
|
||||
Onze des quatorze serveurs portent le **même nom court** chez Chezlepro et chez
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ les 🟡 relèvent de la **Phase 3 (arbitrage)**.
|
|||
Messages de tâche/rescousse/assert rendus génériques. **Validé** : `--syntax-check` OK,
|
||||
`ansible-lint` 0 échec sur le playbook, et **test fonctionnel** (mini-instance en clair) —
|
||||
le token est bien chargé depuis `all/vault.yml` et l'hôte depuis `proxmox.yml`
|
||||
(assert vert). `proxmox.vault.yml` reste accepté en compatibilité.
|
||||
(assert vert). **Suite, 2026-08-03** : `proxmox.vault.yml` n'est plus chargée du tout — tolérée, elle restait le seul porteur du jeton chez un tenant, dans un fichier gitignoré. Migrée vers `all/vault.yml`, supprimée, et `voute.py verifier` contrôle désormais la voûte RÉELLE quand elle est déchiffrable (ce que la seule vérification du gabarit ne pouvait pas voir).
|
||||
- **AFF-097 (🟡 → résolu, A)** — `lab/` codé en dur retiré des docs Proxmox/template :
|
||||
`playbooks/proxmox/README.md`, `docs/procedure-template-debian13-proxmox.md`,
|
||||
`docs/vm-lifecycle.md`, `docs/modeles_vm/debian13-proxmox.md` → `production/` + voûte
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
| P15 | Modele public socle valide | AFF-022, AFF-099 | ✅ OK | Modele public socle : domaines/serveurs/applications/bases valides. |
|
||||
| P16 | Inventaire Ansible complet (--list) | AFF-030 | ⚪ SAUTE | Voute chiffree sans ANSIBLE_VAULT_PASSWORD_FILE (prerequis AFF-026). |
|
||||
| P17 | Tous les modeles valident (registres + underlay) | AFF-022, AFF-099 | ✅ OK | Les 1 modele(s) decouvert(s) valident. |
|
||||
| P18 | Gabarit de voute complet | AFF-026 | ✅ OK | Gabarit de voute complet : 21 secret(s) exige(s), tous presents. |
|
||||
| P18 | Gabarit de voute complet | AFF-026 | ✅ OK | Gabarit de voute complet : 21 secret(s) exige(s), tous presents. (Voute reelle non lisible ici : verification sautee.) |
|
||||
| P19 | Le GUI couvre le schema du plan | AFF-002, AFF-095 | ✅ OK | GUI : les 27 champ(s) des plans reels sont editables (2 plan(s) inspecte(s)), registres toleres : nomenclature. |
|
||||
| P20 | Adressage 100% derive du seed (aucun stocke) | AFF-001, AFF-003 | ✅ OK | 2 nomenclature(s) : adressage 100% derive du seed index. |
|
||||
| P21 | Federation : aucun index en collision | AFF-102 | ✅ OK | Federation coherente : 2 instance(s) federee(s), aucun index en collision. |
|
||||
|
|
|
|||
|
|
@ -86,19 +86,27 @@ L'assistant demande « Configurer la voûte de secrets maintenant ». Si `oui` :
|
|||
- Ces secrets ne transitent **jamais** par le GUI ni par aucun fichier en clair ;
|
||||
le GUI n'en affiche que les **noms** (panneau « Intrants »).
|
||||
|
||||
### Migration depuis l'ancienne `proxmox.vault.yml`
|
||||
### `proxmox.vault.yml` n'est plus lue (retirée le 2026-08-03)
|
||||
|
||||
Si tu as déjà une `proxmox.vault.yml`, déplace son contenu dans la voûte unique :
|
||||
Les playbooks ne chargent plus ce fichier. Tolérée « en compatibilité », elle était
|
||||
restée le **seul** porteur du jeton chez un tenant — et comme `*.vault.yml` est
|
||||
gitignoré, ce jeton ne voyageait avec aucun dépôt. Une voûte unique qui ne l'était pas.
|
||||
|
||||
Si tu en as encore une :
|
||||
|
||||
```bash
|
||||
cd instance/inventories/production/group_vars
|
||||
cp ../../../../exemples/vault.exemple.yml all/vault.yml
|
||||
cd instance/inventories/<env>/group_vars
|
||||
ansible-vault view proxmox.vault.yml # relève token_id + secret
|
||||
ansible-vault edit all/vault.yml # colle-les, renseigne le reste
|
||||
ansible-vault encrypt all/vault.yml # si pas déjà chiffrée
|
||||
git rm --cached --ignore-unmatch proxmox.vault.yml 2>/dev/null; rm proxmox.vault.yml proxmox.vault.yml.example
|
||||
ansible-vault edit all/vault.yml # colle-les
|
||||
rm proxmox.vault.yml proxmox.vault.yml.example
|
||||
python3 ../../../../scripts/voute.py verifier # confirme : plus rien ne manque
|
||||
```
|
||||
|
||||
> **Le jeton se stocke tel que Proxmox l'affiche** (`utilisateur@realm!nom`). Les
|
||||
> playbooks n'en gardent que la partie après `!` : `proxmoxer` recompose l'identifiant
|
||||
> à partir d'`api_user`, et lui passer la forme complète produit un **401 muet** —
|
||||
> alors que le même jeton fonctionne en `curl`. Les deux écritures sont acceptées.
|
||||
|
||||
---
|
||||
|
||||
## Comment créer le token API côté Proxmox
|
||||
|
|
|
|||
|
|
@ -9,10 +9,14 @@
|
|||
# Config Proxmox de l'instance : on cherche dans l'inventaire de l'instance,
|
||||
# quel que soit son nom (lab > principal > production). Compatible « par instance ».
|
||||
setops_inventaires: [lab, principal, production]
|
||||
# Voute Proxmox : la voute UNIFIEE de l'instance (all/vault.yml, ou `make config`
|
||||
# ecrit le token) est autoritaire ; `proxmox.vault.yml` reste accepte en compat
|
||||
# legacy. all/vault.yml en dernier => il l'emporte s'il definit les memes cles.
|
||||
setops_gv_proxmox: [proxmox.yml, proxmox.vault.yml, proxmox.local.yml, all/vault.yml]
|
||||
# Voute UNIQUE de l'instance : all/vault.yml porte TOUS les secrets, jeton
|
||||
# d'hyperviseur compris (D-19). `proxmox.vault.yml` a ete retire le 2026-08-03 :
|
||||
# tolere "en compatibilite", il restait le SEUL porteur du jeton chez un tenant,
|
||||
# et il etait gitignore — une voute unique qui ne l'etait pas, dans un fichier
|
||||
# qui ne voyageait avec aucun depot. P18 ne pouvait pas le voir : il verifie le
|
||||
# gabarit, pas le contenu reel.
|
||||
# `proxmox.local.yml` reste une surcharge locale volontaire, non versionnee.
|
||||
setops_gv_proxmox: [proxmox.yml, proxmox.local.yml, all/vault.yml]
|
||||
# Le CLUSTER appartient a l'HEBERGEUR (API, noeuds, stockages, ponts). Son fichier
|
||||
# vit dans le depot de l'hebergeur, que le symlink `underlay.yml` designe deja
|
||||
# (D-14/D-17) : on en DERIVE le chemin plutot que de redeclarer l'hebergeur. Absent
|
||||
|
|
@ -68,7 +72,13 @@
|
|||
ansible.builtin.set_fact:
|
||||
proxmox_api_host_effectif: "{{ proxmox_api_host | default(lookup('env', 'PROXMOX_API_HOST'), true) }}"
|
||||
proxmox_api_user_effectif: "{{ proxmox_api_user | default(lookup('env', 'PROXMOX_API_USER'), true) }}"
|
||||
proxmox_api_token_id_effectif: "{{ proxmox_api_token_id | default(lookup('env', 'PROXMOX_API_TOKEN_ID'), true) }}"
|
||||
# `split('!')[-1]` : proxmoxer recompose lui-meme `utilisateur!nom` a partir de
|
||||
# `api_user` et `api_token_id`. Lui passer la forme COMPLETE produit
|
||||
# `ansible@pve!ansible@pve!nom` et un 401 muet — le meme jeton fonctionne en
|
||||
# HTTP direct, ce qui rend le diagnostic trompeur. Verifie contre le cluster le
|
||||
# 2026-08-03 : forme complete = 401, forme courte = OK. Sans effet si la voute
|
||||
# stocke deja le nom seul, donc les deux ecritures restent acceptees.
|
||||
proxmox_api_token_id_effectif: "{{ (proxmox_api_token_id | default(lookup('env', 'PROXMOX_API_TOKEN_ID'), true)) | string | split('!') | last }}"
|
||||
proxmox_api_token_secret_effectif: "{{ proxmox_api_token_secret | default(lookup('env', 'PROXMOX_API_TOKEN_SECRET'), true) }}"
|
||||
proxmox_api_port_effectif: "{{ proxmox_api_port | default(lookup('env', 'PROXMOX_API_PORT'), true) }}"
|
||||
no_log: true
|
||||
|
|
|
|||
|
|
@ -10,10 +10,14 @@
|
|||
|
||||
vars:
|
||||
setops_inventaires: [lab, principal, production]
|
||||
# Voute Proxmox : la voute UNIQUE de l'instance (all/vault.yml) est autoritaire ;
|
||||
# `proxmox.vault.yml` reste accepte en compat legacy pour les instances qui en
|
||||
# ont encore une. all/vault.yml en dernier => il l'emporte sur les memes cles.
|
||||
setops_gv_proxmox: [proxmox.yml, proxmox.vault.yml, proxmox.local.yml, all/vault.yml]
|
||||
# Voute UNIQUE de l'instance : all/vault.yml porte TOUS les secrets, jeton
|
||||
# d'hyperviseur compris (D-19). `proxmox.vault.yml` a ete retire le 2026-08-03 :
|
||||
# tolere "en compatibilite", il restait le SEUL porteur du jeton chez un tenant,
|
||||
# et il etait gitignore — une voute unique qui ne l'etait pas, dans un fichier
|
||||
# qui ne voyageait avec aucun depot. P18 ne pouvait pas le voir : il verifie le
|
||||
# gabarit, pas le contenu reel.
|
||||
# `proxmox.local.yml` reste une surcharge locale volontaire, non versionnee.
|
||||
setops_gv_proxmox: [proxmox.yml, proxmox.local.yml, all/vault.yml]
|
||||
# Le CLUSTER appartient a l'HEBERGEUR (API, noeuds, stockages, ponts). Son fichier
|
||||
# vit dans le depot de l'hebergeur, que le symlink `underlay.yml` designe deja
|
||||
# (D-14/D-17) : on en DERIVE le chemin plutot que de redeclarer l'hebergeur. Absent
|
||||
|
|
@ -63,7 +67,10 @@
|
|||
api_host: "{{ proxmox_api_host | default(lookup('env', 'PROXMOX_API_HOST'), true) }}"
|
||||
api_port: "{{ proxmox_api_port | default('8006', true) }}"
|
||||
api_user: "{{ proxmox_api_user | default(lookup('env', 'PROXMOX_API_USER'), true) }}"
|
||||
api_tid: "{{ proxmox_api_token_id | default(lookup('env', 'PROXMOX_API_TOKEN_ID'), true) }}"
|
||||
# `split('!')[-1]` : proxmoxer recompose `utilisateur!nom` a partir d'api_user
|
||||
# et d'api_token_id. La forme COMPLETE donne un 401 muet (verifie contre le
|
||||
# cluster le 2026-08-03). Sans effet si la voute stocke deja le nom seul.
|
||||
api_tid: "{{ (proxmox_api_token_id | default(lookup('env', 'PROXMOX_API_TOKEN_ID'), true)) | string | split('!') | last }}"
|
||||
api_secret: "{{ proxmox_api_token_secret | default(lookup('env', 'PROXMOX_API_TOKEN_SECRET'), true) }}"
|
||||
no_log: true
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ def rendre(devis: dict) -> str:
|
|||
out += [
|
||||
f"## {b['tenant']} — pool `{b['pool']}` (index {b['index']})",
|
||||
f"# {len(b['membres'])} VM au plan, dont {len(actifs)} active(s).",
|
||||
"# Nom derive du seed, comme tout le reste. Distinct des pools "
|
||||
"`Env.Tenant` anterieurs a Set-OPS, qu'on ne touche pas.",
|
||||
"",
|
||||
"### 1. Creer le pool (sans effet s'il existe)",
|
||||
f"pvesh create /pools --poolid {b['pool']} \\",
|
||||
|
|
|
|||
|
|
@ -95,11 +95,18 @@ def integrations_de(srv: dict, services_hote: set[str] | None = None,
|
|||
def pool_de(nom_instance: str, index: int) -> str:
|
||||
"""Nom du pool Proxmox d'un tenant. DERIVE, jamais saisi.
|
||||
|
||||
Onze des quatorze serveurs portent le meme nom court chez deux tenants : c'est
|
||||
la preuve que la nomenclature est un vrai gabarit, et il ne faut pas la casser.
|
||||
Mais la console Proxmox, elle, affiche le NOM — deux `infra-pki-01` y sont
|
||||
indiscernables a l'oeil, alors que tout le reste (IP, VMID, VLAN, FQDN) differe.
|
||||
Le pool restitue l'appartenance la ou elle manquait : dans l'arbre du cluster.
|
||||
Pourquoi le pool. Onze des quatorze serveurs portent le meme nom court chez deux
|
||||
tenants : c'est la preuve que la nomenclature est un vrai gabarit, et il ne faut
|
||||
pas la casser. Mais la console Proxmox affiche le NOM — deux `infra-pki-01` y
|
||||
sont indiscernables a l'oeil, alors que tout le reste (IP, VMID, VLAN, FQDN)
|
||||
differe. Le pool restitue l'appartenance sans rien renommer.
|
||||
|
||||
Pourquoi DERIVE malgre les pools existants. Le cluster porte deja une convention
|
||||
`Env.Tenant` (`Prod.Chezlepro`, `Lab.KBR`...) qui regroupe des VM anterieures a
|
||||
Set-OPS — ZIMBRA, erplibre, eregion... Ces pools-la sont l'ANCIEN MONDE : on n'y
|
||||
touche pas, et on n'y verse pas la flotte generee. Melanger les deux effacerait
|
||||
justement la frontiere que Set-OPS etablit. La flotte derivee a donc ses propres
|
||||
pools, nommes comme tout le reste : depuis le seed.
|
||||
|
||||
`index` est deja garanti unique dans la federation par P21 : le nom l'est donc
|
||||
aussi, sans registre supplementaire. Forme : `Chezlepro-17`, `Technolibre-11`.
|
||||
|
|
|
|||
|
|
@ -116,6 +116,44 @@ def cles_gabarit(path: Path) -> set[str]:
|
|||
return set(data) if isinstance(data, dict) else set()
|
||||
|
||||
|
||||
def cles_voute_reelle() -> set[str] | None:
|
||||
"""Noms des cles de la VRAIE voute, si elle est dechiffrable ici. Sinon None.
|
||||
|
||||
Le gabarit dit ce qu'il FAUDRAIT ; il ne dit pas ce qui EST. Un tenant a vecu
|
||||
avec son jeton d'hyperviseur dans `proxmox.vault.yml` — un fichier gitignore,
|
||||
hors de la voute unique — pendant que le gabarit affichait « complet ». La
|
||||
verification du gabarit ne pouvait pas le voir.
|
||||
|
||||
On ne lit QUE les noms de cles ; aucune valeur n'est retournee ni affichee.
|
||||
None (et non un ensemble vide) quand la voute est absente ou le mot de passe
|
||||
indisponible : c'est une verification qui se SAUTE, jamais une qui echoue —
|
||||
le harnais doit rester utilisable sans acces aux secrets.
|
||||
"""
|
||||
chemin = None
|
||||
for nom in ("principal", "production", "lab"):
|
||||
p = INSTANCE / "inventories" / nom / "group_vars" / "all" / "vault.yml"
|
||||
if p.is_file():
|
||||
chemin = p
|
||||
break
|
||||
if chemin is None:
|
||||
return None
|
||||
brut = chemin.read_bytes()
|
||||
if not brut.startswith(b"$ANSIBLE_VAULT"):
|
||||
data = yaml.safe_load(brut.decode("utf-8", "ignore")) or {}
|
||||
return set(data) if isinstance(data, dict) else set()
|
||||
mdp_fichier = os.environ.get("ANSIBLE_VAULT_PASSWORD_FILE")
|
||||
if not mdp_fichier or not Path(os.path.expanduser(mdp_fichier)).is_file():
|
||||
return None
|
||||
try:
|
||||
from ansible.parsing.vault import VaultLib, VaultSecret
|
||||
mdp = Path(os.path.expanduser(mdp_fichier)).read_bytes().strip()
|
||||
clair = VaultLib([("default", VaultSecret(mdp))]).decrypt(brut)
|
||||
data = yaml.safe_load(clair.decode("utf-8")) or {}
|
||||
return set(data) if isinstance(data, dict) else set()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Couverture du gabarit de voute Set-OPS.")
|
||||
sub = parser.add_subparsers(dest="commande", required=True)
|
||||
|
|
@ -153,9 +191,27 @@ def main() -> int:
|
|||
print(f"{'erreur' if args.strict else 'note'}: {len(inutiles)} cle(s) du gabarit "
|
||||
f"que le plan n'exige plus : {', '.join(inutiles)}", file=flux)
|
||||
|
||||
if manquants or (inutiles and args.strict):
|
||||
# Deuxieme volet : la voute REELLE, quand elle est lisible ici. Le gabarit dit
|
||||
# ce qu'il faudrait ; lui seul ne prouve rien sur ce qui est reellement en place.
|
||||
reelles = cles_voute_reelle()
|
||||
absentes_reelles: list[str] = []
|
||||
if reelles is not None:
|
||||
attendues = set(exiges) | SECRETS_HORS_MOTIF
|
||||
absentes_reelles = sorted(attendues - reelles)
|
||||
if absentes_reelles:
|
||||
print(f"erreur: {len(absentes_reelles)} secret(s) absent(s) de la VOUTE REELLE "
|
||||
f"(group_vars/all/vault.yml) : {', '.join(absentes_reelles)}", file=sys.stderr)
|
||||
print(" Un secret servi depuis un autre fichier (proxmox.vault.yml, "
|
||||
"proxmox.local.yml) n'est pas dans la voute unique — cf. D-19.", file=sys.stderr)
|
||||
|
||||
if manquants or absentes_reelles or (inutiles and args.strict):
|
||||
return 2
|
||||
print(f"Gabarit de voute complet : {len(exiges)} secret(s) exige(s), tous presents.")
|
||||
if reelles is None:
|
||||
print(f"Gabarit de voute complet : {len(exiges)} secret(s) exige(s), tous presents. "
|
||||
f"(Voute reelle non lisible ici : verification sautee.)")
|
||||
else:
|
||||
print(f"Gabarit de voute complet : {len(exiges)} secret(s) exige(s), tous presents. "
|
||||
f"Voute reelle : {len(reelles)} cle(s), aucun manque.")
|
||||
return 0
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue