Set-OPS-Public/playbooks/modeles_vm/debian13_proxmox_preparer.yml

129 lines
6.7 KiB
YAML
Raw Normal View History

---
- name: Préparer le template Debian 13 Proxmox
# Le gabarit n'est pas un hote du tenant : son adresse vit sur le reseau de
# fabrication, donc il ne peut pas venir du plan et le groupe `modeles_vm` reste vide.
# `MODELE_HOTE` passe alors `cible_modele`, et l'inventaire d'un seul hote (`-i "<ip>,"`)
# place la machine dans `all` — PAS dans `modeles_vm`. Sans cette indirection, la
# commande etait juste et la cible introuvable : « skipping: no hosts matched ».
hosts: "{{ cible_modele | default('modeles_vm') }}"
become: true
gather_facts: true
pre_tasks:
gabarit : refabrique, minimal, et puise aux ressources du SITE REFABRIQUE (VMID 9006, modeleSetOPS-minimal). Quatre roles au lieu de dix-sept : qemu_guest_agent, cloud_init, sudo_ansible, ssh_baseline — des conditions d existence, pas des choix d efficacite. Tout le reste vient du socle, et P56 refuse qu un role retire ne soit repris par personne. FABRIQUE CHEZ LE SITE, ET C EST LA DECISION QUI COMPTE. « Les ressources du SITE font autorite pour tous ses artefacts ; elles servent les tenants jusqu a ce qu ils s emancipent. » Il se fabriquait DEHORS : `-i "<ip>,"` ne porte aucun group_vars, donc ni mandataire ni resolveur. L ancien gabarit allait chercher ses paquets chez Debian et resolvait chez l ancien LAN — 192.168.10.10, lu sur la VM 99998. Le site avait son cache et son resolveur, et son propre artefact les ignorait. Desormais la fabrication DERIVE ses ressources du plan du site (underlay --adresses) et tourne sur le reseau du genome. PROUVE : dix requetes de 10.0.33.31 servies par site-cache-01, resolveur pose a 10.0.34.11. L IDENTITE DU GABARIT VIENT DU SITE, PLUS DU TENANT. `proxmox_clone_vmid_modele` vivait dans les group_vars de l ecosysteme : deux tenants pouvaient cloner deux gabarits differents sans que rien ne le dise, et un tenant decidait d un objet dont descend chaque VM de chaque ecosysteme. Meme mouvement que l INDEX (2026-08-25) : le site ALLOUE, le tenant RECOIT. Cle `gabarit` du plan du site, lue par underlay --gabarit. PIEGE FERME EN CHEMIN : creer-vm passait VMID_MODELE="$SETOPS_VMID_MODELE" a cloner-vm, or inventory_host.py n emet PAS cette variable. Elle valait donc le VIDE, et ce vide ECRASAIT la valeur derivee — le gabarit du tenant reprenait la main sans bruit. ET UN PIEGE DEJA DOCUMENTE, PAYE UNE TROISIEME FOIS : le chemin du controleur contient une espace, et `lookup('pipe', ...)` le decoupait. Guillemets. EPROUVE DE BOUT EN BOUT : VM clonee du gabarit minimal — nom, adresse, machine-id neuf, cle d hote regeneree, agent invite actif ; puis socle applique dessus, changed=5, 0 echec, auditd compris. VM d essai retiree. make verifier : vert. make prouver : CONFORME, 56 OK, 0 echec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-09-01 13:46:31 -04:00
# ─── LE GABARIT EST UN ARTEFACT DU SITE, ET IL SE FABRIQUE CHEZ LUI ──────────
#
# « Les ressources du SITE font autorité pour tous les artefacts du site » (décision
# de l'exploitant, 2026-09-01). Le gabarit en est un — c'est de lui que descend
# chaque VM de chaque tenant.
#
# Il se fabriquait pourtant DEHORS : `-i "<ip>,"` ne porte aucun `group_vars`, donc
# ni mandataire ni résolveur. La machine allait chercher ses paquets chez Debian et
# résolvait chez l'ancien LAN (`192.168.10.10`, lu sur le gabarit du 2026-08-09).
# Le site avait son cache et son résolveur, et son propre artefact les ignorait.
#
# DÉRIVÉ, JAMAIS ÉCRIT : les adresses viennent du plan du site, par le groupe que la
# machine porte. Le jour où le cache déménage, la fabrication suit — c'est déjà
# arrivé une fois, au découpage du site en zones.
- name: Où le SITE sert-il ses paquets et ses noms ?
ansible.builtin.set_fact:
# LE CHEMIN DU CONTROLEUR PEUT CONTENIR UNE ESPACE — « Espace Chezlepro/… »
# chez le mainteneur — et `pipe` passe sa chaine au shell. Sans guillemets, il
# decoupe le chemin et rend 2. Meme piege que `ansible-galaxy` le 2026-08-23 et
# que `git bundle` le 2026-08-26 : ce depot l'a paye trois fois.
modele_cache_site: >-
{{ (lookup('pipe', 'python3 "' ~ playbook_dir ~ '/../../scripts/underlay.py" --adresses serveur_artefacts')
| trim | split('\n') | first | default('', true)) }}
modele_resolveur_site: >-
{{ (lookup('pipe', 'python3 "' ~ playbook_dir ~ '/../../scripts/underlay.py" --adresses serveur_resolveur')
| trim | split('\n') | first | default('', true)) }}
delegate_to: localhost
become: false
# PAS de `run_once` : la fabrication ne vise qu'une machine de toute facon, et
# `run_once` se comporte autrement sous la strategie `free` — une garde qui depend
# de la strategie n'en est pas une.
- name: Exiger que le site offre ce qu'il faut pour fabriquer son gabarit
ansible.builtin.assert:
that:
- modele_cache_site | length > 0
- modele_resolveur_site | length > 0
fail_msg: >-
Le plan du SITE ne déclare pas de `serveur_artefacts` et/ou de
`serveur_resolveur`. Le gabarit est un artefact du site : le fabriquer sans eux
le ferait dépendre d'Internet et de l'ancien LAN, alors que tout ce dont il a
besoin doit venir du site.
# UNE ADRESSE, PAS UN NOM : au moment où ces deux fichiers servent, la machine ne
# résout encore rien — c'est justement ce qu'on est en train de lui donner.
- name: Poser le résolveur du SITE
ansible.builtin.copy:
dest: /etc/resolv.conf
owner: root
group: root
mode: "0644"
content: |
# Géré par Set-OPS pendant la FABRICATION du gabarit — le résolveur du SITE.
# `template_cleanup` le remet à zéro : un gabarit ne transporte pas d'adresse.
nameserver {{ modele_resolveur_site }}
- name: Poser le cache d'artefacts du SITE
ansible.builtin.copy:
dest: /etc/apt/apt.conf.d/00-setops-amorcage-artefacts
owner: root
group: root
mode: "0644"
content: |
// Géré par Set-OPS pendant la FABRICATION du gabarit — le cache du SITE.
// Les VM clonées le remplacent par celui de leur écosystème (client_artefacts).
Acquire::http::Proxy "http://{{ modele_cache_site }}:3142";
// `DIRECT` obligatoire : apt fait HÉRITER la valeur HTTPS de la valeur HTTP.
Acquire::https::Proxy "DIRECT";
- name: Vérifier que la cible est Debian
ansible.builtin.assert:
that:
- ansible_facts.distribution == "Debian"
fail_msg: "Ce playbook est prévu pour Debian."
- name: Avertir si la version Debian n'est pas 13
ansible.builtin.debug:
msg: "Attention : Debian {{ ansible_facts.distribution_version }} détecté. Le modèle cible est Debian 13."
when: ansible_facts.distribution_major_version != "13"
gabarit : minimal — il etait un cache du socle, et il perimait sans le dire Il portait DIX-SEPT roles : exactement ceux du socle et du durcissement, que le deploiement rejoue a l identique. C etait donc un CACHE — et comme tout cache, il perimait sans le dire. MESURE : derniere recapture le 2026-08-09, et SIX de ses roles avaient change depuis — common_packages, cloud_init, ssh_baseline, ssh_hardening, auditd, nftables_baseline. Rien ne le signalait : le deploiement masquait la derive en reappliquant tout, donc personne ne pouvait la voir. Aucune preuve du harnais ne regardait sa fraicheur. IL NE GARDE QUE CE QUI DOIT EXISTER AVANT QU ANSIBLE PUISSE AGIR : qemu_guest_agent l agent repond AVANT SSH — P52 s en sert cloud_init le seul chemin vers la premiere seconde sudo_ansible la porte par ou tout entre ssh_baseline le serveur SSH Ce ne sont pas des choix d efficacite, ce sont des conditions d existence. CE QUE CA COUTE, ET QUI EST COUVERT : une VM neuve n est plus durcie a la naissance. Elle nait cependant DERRIERE LE PARE-FEU DE L HYPERVISEUR, policy_in=REJECT arme au clonage — verifie sur obs-01. La fenetre d exposition est fermee par la fabric, pas par le gabarit. Mon objection initiale tombait devant la mesure. P56 GARDE LES DEUX MOITIES. Qu il ne REGROSSISSE pas : un role ajoute recree le cache, donc la peremption invisible. Et que rien de retire ne soit PERDU : un role absent du gabarit ET du socle disparaitrait de toutes les machines neuves, sans erreur ni trace, et la panne arriverait des mois plus tard sur une machine qu on croyait durcie. Verifie : 14 retires, 14 repris, zero orphelin. Deux controles negatifs. make verifier : vert. make prouver : CONFORME, 56 OK, 0 echec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-09-01 10:35:20 -04:00
# ─── LE GABARIT EST MINIMAL, ET C'EST UNE DECISION (2026-09-01) ──────────────
#
# Il portait DIX-SEPT roles : exactement ceux du socle et du durcissement, que le
# deploiement rejoue ensuite a l'identique. Le gabarit etait donc un CACHE du socle —
# et comme tout cache, il perimait sans le dire.
#
# Mesure du 2026-09-01 : derniere recapture le 2026-08-09, et SIX de ses roles avaient
# change depuis (common_packages, cloud_init, ssh_baseline, ssh_hardening, auditd,
# nftables_baseline). Rien ne le signalait — le deploiement masquait la derive en
# reappliquant tout, donc personne ne pouvait la voir.
#
# CE QUI RESTE ICI N'EST PAS UN CHOIX D'EFFICACITE, C'EST UNE CONDITION D'EXISTENCE :
# chacun doit etre en place AVANT qu'Ansible puisse agir. Tout le reste appartient au
# socle, qui l'applique de toute facon — et P56 refuse qu'un role retire ne soit repris
# par personne.
#
# `qemu_guest_agent` l'agent invite repond AVANT SSH. C'est par lui que `creer-vm`
# confirme la materialisation sans entrer chez le tenant (P52).
# `cloud_init` le seul chemin vers la premiere seconde — adresse, nom d'hote,
# cles de naissance. Sans lui, personne ne peut joindre la VM.
# `sudo_ansible` le compte technique et son sudo : la porte par ou tout entre.
# `ssh_baseline` le serveur SSH. Meme raison, un cran plus bas.
#
# CE QUE LA REDUCTION COUTE, ET QUI EST COUVERT : une VM neuve n'est plus durcie a la
# naissance. Elle nait cependant DERRIERE LE PARE-FEU DE L'HYPERVISEUR,
# `policy_in=REJECT` arme au clonage (verifie le 2026-09-01 sur `obs-01`) : seuls les
# flux declares l'atteignent, avant meme son premier paquet. La fenetre d'exposition est
# fermee par la fabric, pas par le gabarit.
#
# CE QU'ELLE RAPPORTE : un gabarit qui ne contient presque rien ne peut presque pas
# perimer.
roles:
- qemu_guest_agent
- cloud_init
- sudo_ansible
- ssh_baseline