diff --git a/CHANGELOG.md b/CHANGELOG.md index 701d0a6..e55b050 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # CHANGELOG — Set-OPS +## 2026-08-24 — Quinze invites pour un seul mot de passe + +`flotte-creer` appelait `make creer-vm` **une fois par hôte**, et chaque appel ajoutait +`--ask-vault-pass`. Quinze machines, donc quinze invites — **quatre en parallèle**, avec la +sortie redirigée vers des journaux : l'exploitant est harcelé par des invites qu'il ne voit +même pas. + +Mesuré en reconstruisant Chezlepro. Ce n'est pas une fatalité de l'outil, c'est une faute +de l'outil. + +### L'idiome existait déjà — je ne l'avais pas cherché + +`deployer-tout` demande **une seule fois** depuis longtemps, et refuse proprement quand +personne n'est au clavier. Ma première correction inventait une **seconde** façon de +manipuler un secret, à côté de la première. + +C'est exactement la faute que P41 combat : deux résolutions d'une même question finissent +par diverger, et pour un secret la divergence ne se remarque qu'après. + +Les deux cibles partagent désormais **un seul bloc**, `VAULT_UNE_FOIS` : lecture unique, +fichier `mktemp` en `0600`, `trap` au retrait, et refus explicite en entrée non +interactive. + +### Une garde que ma première version n'avait pas + +`-t 0` : ne demander que si un humain est au clavier. Sans elle, un appel non interactif — +CI, ordonnanceur, agent — resterait **bloqué sur une invite que personne ne lit**. Je m'en +suis aperçu en vérifiant ma propre correction : la commande a pendu deux minutes. + +Vérifié : `flotte-creer` sans mot de passe et sans terminal refuse maintenant en une +ligne, au lieu d'attendre indéfiniment. + ## 2026-08-24 — Le dénominateur extrait : `origine` devient un modèle La hiérarchie se lit maintenant sans ambiguïté : diff --git a/Makefile b/Makefile index 7de4a87..1003435 100644 --- a/Makefile +++ b/Makefile @@ -368,18 +368,7 @@ deployer: _instance-requise ## Deploie un hote, couche par couche, dans l'ordre printf '%s\n' 'Refus: aucun playbook applicable pour HOTE=$(HOTE).'; \ exit 2; \ fi; \ - vault_chiffre="$$(grep -rlsIF '$$ANSIBLE_VAULT' $(dir $(INVENTAIRE_PRODUCTION))group_vars 2>/dev/null | head -1 || true)"; \ - if [[ -n "$$vault_chiffre" && -z "$${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then \ - if [[ -t 0 ]]; then \ - read -r -s -p 'Mot de passe du vault Ansible: ' mdp; echo; \ - vf="$$(mktemp)"; printf '%s' "$$mdp" > "$$vf"; chmod 600 "$$vf"; \ - export ANSIBLE_VAULT_PASSWORD_FILE="$$vf"; \ - trap 'rm -f "$$vf"' EXIT; \ - else \ - printf '%s\n' 'Refus: vault chiffre detecte mais aucun mot de passe (entree non interactive). Fournir ANSIBLE_VAULT_PASSWORD_FILE ou le champ vault de la GUI.'; \ - exit 2; \ - fi; \ - fi; \ + $(VAULT_UNE_FOIS) \ $(MAKE) _verifier-acces-hote LIMITE="$(HOTE)"; \ $(MAKE) _verifier-privileges-hote LIMITE="$(HOTE)"; \ for playbook in $$playbooks; do \ @@ -651,6 +640,35 @@ deployer-tout: _instance-requise ## Deploie TOUTE la flotte dans l'ordre des cou # Un echec n'est pas avale : le code de retour de chaque hote est relu, et la cible sort # en erreur si l'un d'eux a echoue — sinon `_attendre-flotte` partirait sur une flotte # incomplete. +# --- LE MOT DE PASSE DE LA VOUTE, DEMANDE UNE SEULE FOIS ---------------------- +# +# Deux cibles longues en ont besoin : `deployer-tout` (une invocation ansible) et +# `flotte-creer` (une invocation PAR MACHINE). La seconde redemandait le mot de passe a +# chaque VM — quinze fois sur la reconstruction de Chezlepro, quatre en parallele, avec +# la sortie redirigee vers des journaux : l'exploitant est harcele par des invites qu'il +# ne voit meme pas. +# +# UN SEUL BLOC POUR LES DEUX. Deux facons de manipuler un secret finiraient par diverger, +# et c'est le genre de divergence qu'on ne remarque qu'apres. +# +# `-t 0` : ne demander que si un humain est au clavier. Un appel non interactif refuse +# clairement plutot que de pendre sur une invite que personne ne lit. +define VAULT_UNE_FOIS + vault_chiffre="$$(grep -rlsIF '$$ANSIBLE_VAULT' $(dir $(INVENTAIRE_PRODUCTION))group_vars 2>/dev/null | head -1 || true)"; \ + if [[ -n "$$vault_chiffre" && -z "$${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then \ + if [[ -t 0 ]]; then \ + read -r -s -p 'Mot de passe du vault Ansible (demande une seule fois): ' mdp; echo; \ + vf="$$(mktemp)"; printf '%s' "$$mdp" > "$$vf"; chmod 600 "$$vf"; \ + export ANSIBLE_VAULT_PASSWORD_FILE="$$vf"; \ + trap 'rm -f "$$vf"' EXIT; \ + else \ + printf '%s\n' 'Refus: vault chiffre detecte mais aucun mot de passe (entree non interactive). Fournir ANSIBLE_VAULT_PASSWORD_FILE ou le champ vault de la GUI.'; \ + exit 2; \ + fi; \ + fi; +endef + + flotte-creer: _instance-requise ## Cree les VM manquantes de la flotte depuis le plan — PARALLELE=n @set -e; \ if [[ "$(CONFIRMER)" != "true" ]]; then \ @@ -662,6 +680,7 @@ flotte-creer: _instance-requise ## Cree les VM manquantes de la flotte depuis le if [[ -z "$$hotes" ]]; then printf '%s\n' 'Refus: aucun hote actif dans le plan.'; exit 2; fi; \ par="$(PARALLELE)"; par="$${par:-4}"; \ tmp="$$(mktemp -d)"; trap 'rm -rf "$$tmp"' EXIT; \ + $(VAULT_UNE_FOIS) \ printf 'Creation de %s VM, %s a la fois.\n' "$$(echo $$hotes | wc -w)" "$$par"; \ n=0; \ for h in $$hotes; do \