--- # PROUVER QU'UN LIEN EST COUPÉ — l'instrument de la quatrième ligne. # # `docs/filiation-emancipation.md` décrit quatre temps, et n'en outillait que trois : # # le lien de filiation déclaré au plan le moteur # le constat d'aptitude « tu pourrais » la machine INSTRUIT # l'acte d'émancipation retirer le lien l'HUMAIN, CONFIRMER=true # la preuve que c'est coupé ← CE PLAYBOOK la machine, APRÈS l'acte # # « Une émancipation non prouvée est une émancipation non faite. » # # ─── POURQUOI SONDER NE SUFFIT PAS ─────────────────────────────────────────── # # Vérifier que le service local répond ne prouve RIEN. Le dépôt le dit déjà, à propos du # cache : « tant qu'internet répond, un `apt update` qui réussit ne dit pas d'où vient # l'octet ». Un écosystème peut avoir monté son propre service ET continuer à tirer de # l'amont sans que personne ne le voie. # # On COUPE donc, et on refait marcher la chose. C'est le seul geste qui distingue # « j'ai un service local » de « je n'ai plus besoin du tien ». # # ─── LE MÊME ESSAI REND LES DEUX VERDICTS ──────────────────────────────────── # # Le verdict vient de la MESURE, jamais d'une déclaration : # # coupé, la fonction marche -> ÉMANCIPÉ, et c'est prouvé # coupé, la fonction casse -> PAS ÉMANCIPÉ — et la dépendance est prouvée REELLE # # Le second n'est pas un échec de l'outil : c'est son contrôle négatif, rendu par la même # commande. Une preuve d'émancipation qui ne saurait pas montrer la dépendance qu'elle # mesure ne prouverait rien le jour où elle passerait au vert. # # ─── LA COUPURE EST GARANTIE RÉVERSIBLE ────────────────────────────────────── # # Une TABLE nftables dédiée, jamais une règle glissée dans une table existante : elle se # retire d'un seul geste, et ne peut pas laisser d'état partiel si l'essai s'interrompt. # Le `always` la retire quoi qu'il arrive — y compris si la mesure échoue. # # Usage : # make emancipation-prouver SERVICE=artefacts CONFIRMER=true # make emancipation-prouver SERVICE=genome CONFIRMER=true # make emancipation-prouver SERVICE=resolveur CONFIRMER=true - name: Prouver qu'un lien de filiation est coupé hosts: "{{ emancipation_hotes | default('hotes_actifs') }}" gather_facts: false become: true vars: # CE QU'ON COUPE, ET CE QU'ON REFAIT MARCHER. Chaque service nomme son amont (lu au # plan, jamais écrit ici) et l'épreuve qui dit s'il tient sans lui. emancipation_services: artefacts: amont: "{{ serveur_artefacts_amont | default(artefacts_amorcage | default('')) }}" epreuve: "apt-get -qq update" dit: "installer des paquets" genome: amont: "{{ serveur_ops_forge_amont | default('') }}" epreuve: "git ls-remote {{ serveur_ops_forge_amont | default('') }}/genome/set-ops-public.git HEAD" dit: "cloner le génome" resolveur: amont: "{{ dns_amorcage | default('') }}" epreuve: "getent hosts deb.debian.org" dit: "résoudre un nom public" emancipation_ce_service: "{{ emancipation_services[emancipation_service] }}" # L'ADRESSE SEULE, sans schéma ni port : c'est elle qu'on bloque. emancipation_adresse: >- {{ (emancipation_ce_service.amont | regex_replace('^\w+://', '') | regex_replace('[:/].*$', '')) }} tasks: - name: Exiger un service connu et un amont déclaré ansible.builtin.assert: that: - emancipation_service is defined - emancipation_service in emancipation_services - emancipation_adresse | length > 0 fail_msg: >- SERVICE doit valoir l'un de {{ emancipation_services.keys() | join(', ') }}, et cet écosystème doit DÉCLARER l'amont correspondant. Un emprunt qu'aucune variable ne nomme ne peut pas être prouvé coupé — c'est la forme normée de `docs/filiation-emancipation.md` qui rend cette preuve possible. # PAS de `run_once` : l'amont se lit dans les variables de CHAQUE hote. Un # ecosysteme peut tres bien emprunter sur une machine et pas sur une autre — c'est # meme le cas ici, ou seul le porteur du cache chaine vers celui du site. Verifier # une fois pour toutes lirait le premier hote et parlerait au nom des autres. - name: Prouver block: # ── L'ÉTAT AVANT : la fonction marche-t-elle seulement ? ──────────── # # Sans ce témoin, une fonction déjà cassée AVANT la coupure se lirait comme une # dépendance prouvée. On mesure donc le point de départ. - name: Témoin — la fonction marche-t-elle AVANT toute coupure ? ansible.builtin.command: cmd: "{{ emancipation_ce_service.epreuve }}" register: emancipation_temoin failed_when: false changed_when: false - name: Refuser de mesurer une fonction déjà cassée ansible.builtin.assert: that: - emancipation_temoin.rc == 0 fail_msg: >- « {{ emancipation_ce_service.dit }} » ne marche DÉJÀ PAS sur cet hôte, avant qu'on ait rien coupé. Une coupure ne prouverait rien ici : on lirait une panne préexistante comme une dépendance. Réparer d'abord. # ── LA COUPURE ───────────────────────────────────────────────────── - name: Couper le lien vers l'amont ansible.builtin.command: argv: - nft - -f - "-" stdin: | table inet setops_emancipation { chain output { type filter hook output priority -10; policy accept; ip daddr {{ emancipation_adresse }} reject with icmpx type admin-prohibited } } changed_when: true # ── L'ÉPREUVE ────────────────────────────────────────────────────── - name: L'épreuve, l'amont coupé ansible.builtin.command: cmd: "{{ emancipation_ce_service.epreuve }}" register: emancipation_epreuve failed_when: false changed_when: false always: # RETIRÉE QUOI QU'IL ARRIVE — y compris si l'épreuve échoue, si le play est # interrompu, ou si la mesure lève. Une coupure qui survit à son essai serait une # panne qu'on aurait fabriquée soi-même. - name: Rétablir le lien ansible.builtin.command: argv: ["nft", "delete", "table", "inet", "setops_emancipation"] failed_when: false changed_when: true - name: Vérifier que le lien est bien rétabli ansible.builtin.command: argv: ["nft", "list", "table", "inet", "setops_emancipation"] register: emancipation_reste failed_when: emancipation_reste.rc == 0 changed_when: false - name: "✔ Émancipation — {{ emancipation_service }}" ansible.builtin.debug: msg: >- {{ (emancipation_epreuve.rc == 0) | ternary( 'ÉMANCIPÉ (prouvé) — « ' ~ emancipation_ce_service.dit ~ ' » fonctionne l amont ' ~ emancipation_adresse ~ ' COUPÉ. Le lien peut être retiré du plan : il ne sert plus.', 'PAS ÉMANCIPÉ — « ' ~ emancipation_ce_service.dit ~ ' » casse dès que l amont ' ~ emancipation_adresse ~ ' est coupé. La dépendance est REELLE, et cette mesure est le contrôle négatif de la preuve future.') }}