--- - 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 ","`) # 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: # ─── 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 ","` 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" # ─── 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