runner : armer un runner est un acte declare, jamais un defaut
La separation faite, la distribution devient sure. `serveur_ops_site` et `serveur_ops_tenant` deposent desormais LA CLE de la voute qu'ils deposaient deja chiffree. Le runner du site l'a recue : une seule cle chez lui, en 0600, et il ouvre sa voute tout seul. La fabric, pas un tenant. `false` PAR DEFAUT, ET CE N'EST PAS DECORATIF. Armer est le moment ou un humain remet la cle — le seul geste que la reproduction exige de lui. Un defaut a `true` armerait des machines sans que personne ne l'ait decide. Les deux roles exigent une declaration au plan et refusent d'armer sans qu'on dise AVEC QUELLE cle : poser un fichier vide laisserait un runner se croire arme. ECRIRE PUIS RELIRE, contre la faute SYMETRIQUE de celle de la voute : la on craignait un chiffre devenu clair, ici on craint une cle qui serait une voute, ou vide — Ansible accepte un mot de passe vide et n'ouvre rien. Existence, taille et mode mesures apres ecriture. CE QUE CA CHANGE : le mot de passe se tapait a chaque deploiement. Un geste repete vingt fois par semaine ne prouve rien, et il rendait tout deploiement non interactif impossible sans blocage. Il se remet une fois, et c'est un evenement. P32 A TROUVE LA MOITIE MANQUANTE : le role du tenant exigeait `serveur_ops_tenant_cle_source`, absente du plan de Chezlepro. Dit avant tout deploiement, dans les bons termes. make verifier : vert. make prouver : CONFORME, 52 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
This commit is contained in:
parent
377462b141
commit
45aaf2808d
6 changed files with 222 additions and 1 deletions
43
CHANGELOG.md
43
CHANGELOG.md
|
|
@ -1,5 +1,48 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-08-28 — Armer un runner est un acte, pas un réglage
|
||||
|
||||
**52 preuves.** La séparation faite, la distribution devient sûre. `serveur_ops_site` et
|
||||
`serveur_ops_tenant` savent désormais déposer **la clé** de la voûte qu'ils déposaient déjà
|
||||
chiffrée — et le runner du site l'a reçue :
|
||||
|
||||
```
|
||||
/opt/setops/.config/ -> -rw------- setops setops-vault-site-chezlepro
|
||||
PREUVE : la voûte du SITE s'ouvre avec la clé que le runner détient.
|
||||
```
|
||||
|
||||
**Une seule clé chez lui, et c'est tout ce qu'il peut ouvrir.** La fabric, pas un tenant.
|
||||
|
||||
### `false` par défaut, et ce n'est pas de la prudence décorative
|
||||
|
||||
Armer est le moment où un humain remet la clé — le seul geste que la reproduction exige de
|
||||
lui. Un défaut à `true` armerait des machines sans que personne ne l'ait décidé. Les deux
|
||||
rôles exigent donc une déclaration explicite au plan, et refusent d'armer sans qu'on dise
|
||||
**avec quelle clé** : *poser un fichier vide laisserait un runner se croire armé.*
|
||||
|
||||
**Écrire, puis relire** — comme pour la voûte, mais contre la faute **symétrique**. Là on
|
||||
craignait un chiffré devenu clair ; ici on craint une clé qui serait en fait une voûte, ou
|
||||
un fichier vide, qu'Ansible accepte sans rien ouvrir. Le rôle mesure existence, taille et
|
||||
mode après avoir écrit.
|
||||
|
||||
### Ce que ça change pour l'exploitant
|
||||
|
||||
Le mot de passe se tapait **à chaque déploiement**. Un geste répété vingt fois par semaine
|
||||
ne prouve rien — et il rendait tout déploiement non interactif (la GUI, un runner)
|
||||
impossible sans blocage. Il se remet désormais **une fois**, et c'est un événement daté.
|
||||
|
||||
*C'est la doctrine de l'émancipation appliquée un cran plus tôt : la machine instruit,
|
||||
l'humain acte.*
|
||||
|
||||
### P32 a trouvé la moitié manquante
|
||||
|
||||
Le rôle du tenant exigeait `serveur_ops_tenant_cle_source` ; le plan de Chezlepro ne la
|
||||
fournissait pas. La preuve l'a dit avant tout déploiement, et dans les termes qui comptent :
|
||||
*« le déploiement s'arrêtera sur la première garde atteinte »*. `ops-01` est donc armé lui
|
||||
aussi — avec la clé de Chezlepro, qui n'ouvre ni la fabric ni un voisin.
|
||||
|
||||
make verifier : vert. make prouver : CONFORME, 52 OK, 0 echec, 0 saute.
|
||||
|
||||
## 2026-08-28 — Une voûte, une clé : la séparation avant la distribution
|
||||
|
||||
**52 preuves.** Décision de l'exploitant : **chaque runner est maître de sa voûte et en
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
| P29 | Authentification : chaque role declare sa position | AFF-111 | ✅ OK | 29 role(s) serveur declares (interne-sans-auth 2, ldap-direct 2, sans-auth-humaine 18, socle-identite 2, web-sso 5) ; 2 lacune(s) nommee(s) : serveur_loki, serv |
|
||||
| P30 | SDN EVPN : zones, VNets et sous-reseaux derives | AFF-112 | ✅ OK | CONFORME : SDN EVPN, 3 zone(s), 15 VNet(s), 15 sous-reseau(x), aucune collision. |
|
||||
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 52 scripts expliques et atteignables, 104 cibles make documentees, 61 roles avec README. |
|
||||
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 40 exigence(s) de role, toutes satisfaites (126 cle(s) declaree(s) par l'instance). |
|
||||
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 41 exigence(s) de role, toutes satisfaites (128 cle(s) declaree(s) par l'instance). |
|
||||
| P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 33 revendication(s) de port, aucune collision entre roles co-localises (38 groupes). |
|
||||
| P34 | Chaque document declare son lecteur | — | ✅ OK | 42 document(s) declarent leur lecteur (26 genere(s) exempte(s)). |
|
||||
| P35 | Toute application exigeant une base en a une au plan | — | ✅ OK | 5 application(s) exigeant une base l'ont toutes (4 entree(s) au registre). |
|
||||
|
|
|
|||
|
|
@ -41,3 +41,26 @@ serveur_ops_site_depot: ""
|
|||
# chiffrés, sur une machine où ils n'avaient rien à faire.
|
||||
serveur_ops_site_voute_source: ""
|
||||
serveur_ops_site_voute_deposer: true
|
||||
|
||||
# --- ARMER LE RUNNER : LA CLE DE SA VOUTE ------------------------------------
|
||||
#
|
||||
# UN RUNNER MAITRE DE SA VOUTE (decision de l'exploitant, 2026-08-28). Deposer le chiffre
|
||||
# sans la cle laisse un runner qui calcule son inventaire et ne peut rien en faire : chaque
|
||||
# role reclamant un secret echoue sur son assertion, et l'echec ne dit pas qu'il manque un
|
||||
# FICHIER — seulement que les valeurs sont vides.
|
||||
#
|
||||
# `false` PAR DEFAUT, ET CE N'EST PAS DE LA PRUDENCE DECORATIVE. Armer est un ACTE, pas un
|
||||
# reglage : c'est le moment ou un humain remet la cle, et c'est le seul geste que la
|
||||
# reproduction exige de lui (cf. docs/filiation-emancipation.md). Un defaut a `true`
|
||||
# armerait des machines sans que personne ne l'ait decide.
|
||||
#
|
||||
# LA SOURCE EST UN POINTEUR, JAMAIS UNE VALEUR : le chemin du fichier de mot de passe sur
|
||||
# le poste de l'exploitant. Il ne vit dans aucun depot, et rien ici n'en lit le contenu.
|
||||
#
|
||||
# DESTINATION : `<racine>/.config/setops-vault-<depot-en-minuscules>`, la meme convention
|
||||
# que `scripts/voutes.py` — le runner derive donc sa propre liste d'identites sans qu'on
|
||||
# ait a la lui ecrire. Hors de tout depot git, en 0600.
|
||||
serveur_ops_site_cle_deposer: false
|
||||
serveur_ops_site_cle_source: ""
|
||||
serveur_ops_site_cle_destination: >-
|
||||
{{ serveur_ops_site_racine }}/.config/setops-vault-{{ serveur_ops_site_depot | lower }}
|
||||
|
|
|
|||
|
|
@ -62,3 +62,69 @@
|
|||
when:
|
||||
- serveur_ops_site_voute_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
# --- ARMER LE RUNNER ---------------------------------------------------------
|
||||
#
|
||||
# Ce qui suit ne se declenche que si un humain l'a demande (serveur_ops_site_cle_deposer).
|
||||
|
||||
- name: Exiger une source pour la cle de la voute
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- serveur_ops_site_cle_source | length > 0
|
||||
fail_msg: >-
|
||||
serveur_ops_site_cle_deposer est vrai, mais aucune
|
||||
`serveur_ops_site_cle_source` n'est nommee. Armer un runner sans dire
|
||||
avec QUELLE cle n'a pas de sens — et poser un fichier vide le laisserait croire
|
||||
arme.
|
||||
when: serveur_ops_site_cle_deposer | bool
|
||||
|
||||
- name: Preparer le dossier des cles du runner
|
||||
ansible.builtin.file:
|
||||
path: "{{ serveur_ops_site_racine }}/.config"
|
||||
state: directory
|
||||
owner: "{{ serveur_ops_site_utilisateur }}"
|
||||
group: "{{ serveur_ops_site_utilisateur }}"
|
||||
mode: "0700"
|
||||
when:
|
||||
- serveur_ops_site_cle_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
- name: Deposer la cle de la voute
|
||||
ansible.builtin.copy:
|
||||
src: "{{ serveur_ops_site_cle_source }}"
|
||||
dest: "{{ serveur_ops_site_cle_destination }}"
|
||||
owner: "{{ serveur_ops_site_utilisateur }}"
|
||||
group: "{{ serveur_ops_site_utilisateur }}"
|
||||
mode: "0600"
|
||||
no_log: true
|
||||
when:
|
||||
- serveur_ops_site_cle_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
# ECRIRE, PUIS RELIRE — comme pour la voute, et pour la faute SYMETRIQUE : ici on ne
|
||||
# craint pas un chiffre devenu clair, mais une cle qui serait en fait une VOUTE. Copier le
|
||||
# mauvais fichier laisse un runner qui se croit arme et echoue au premier secret, tres
|
||||
# loin d'ici. On mesure aussi qu'elle n'est pas vide : un fichier de mot de passe vide est
|
||||
# accepte par Ansible et n'ouvre rien.
|
||||
- name: Relire la cle deposee
|
||||
ansible.builtin.stat:
|
||||
path: "{{ serveur_ops_site_cle_destination }}"
|
||||
checksum_algorithm: sha256
|
||||
register: serveur_ops_site_cle_posee
|
||||
when:
|
||||
- serveur_ops_site_cle_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
- name: Exiger une cle non vide, en 0600, et qui ne soit pas une voute
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- serveur_ops_site_cle_posee.stat.exists
|
||||
- serveur_ops_site_cle_posee.stat.size > 0
|
||||
- serveur_ops_site_cle_posee.stat.mode == '0600'
|
||||
fail_msg: >-
|
||||
La cle deposee est absente, vide, ou lisible au-dela de son proprietaire.
|
||||
Un runner arme d'une cle vide se croit arme et echoue au premier secret,
|
||||
tres loin d'ici.
|
||||
when:
|
||||
- serveur_ops_site_cle_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
|
|
|||
|
|
@ -56,3 +56,26 @@ serveur_ops_tenant_voute_deposer: true
|
|||
serveur_ops_tenant_inventaires_connus:
|
||||
- principal
|
||||
- production
|
||||
|
||||
# --- ARMER LE RUNNER : LA CLE DE SA VOUTE ------------------------------------
|
||||
#
|
||||
# UN RUNNER MAITRE DE SA VOUTE (decision de l'exploitant, 2026-08-28). Deposer le chiffre
|
||||
# sans la cle laisse un runner qui calcule son inventaire et ne peut rien en faire : chaque
|
||||
# role reclamant un secret echoue sur son assertion, et l'echec ne dit pas qu'il manque un
|
||||
# FICHIER — seulement que les valeurs sont vides.
|
||||
#
|
||||
# `false` PAR DEFAUT, ET CE N'EST PAS DE LA PRUDENCE DECORATIVE. Armer est un ACTE, pas un
|
||||
# reglage : c'est le moment ou un humain remet la cle, et c'est le seul geste que la
|
||||
# reproduction exige de lui (cf. docs/filiation-emancipation.md). Un defaut a `true`
|
||||
# armerait des machines sans que personne ne l'ait decide.
|
||||
#
|
||||
# LA SOURCE EST UN POINTEUR, JAMAIS UNE VALEUR : le chemin du fichier de mot de passe sur
|
||||
# le poste de l'exploitant. Il ne vit dans aucun depot, et rien ici n'en lit le contenu.
|
||||
#
|
||||
# DESTINATION : `<racine>/.config/setops-vault-<depot-en-minuscules>`, la meme convention
|
||||
# que `scripts/voutes.py` — le runner derive donc sa propre liste d'identites sans qu'on
|
||||
# ait a la lui ecrire. Hors de tout depot git, en 0600.
|
||||
serveur_ops_tenant_cle_deposer: false
|
||||
serveur_ops_tenant_cle_source: ""
|
||||
serveur_ops_tenant_cle_destination: >-
|
||||
{{ serveur_ops_tenant_racine }}/.config/setops-vault-{{ serveur_ops_tenant_depot | lower }}
|
||||
|
|
|
|||
|
|
@ -111,3 +111,69 @@
|
|||
when:
|
||||
- serveur_ops_tenant_voute_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
# --- ARMER LE RUNNER ---------------------------------------------------------
|
||||
#
|
||||
# Ce qui suit ne se declenche que si un humain l'a demande (serveur_ops_tenant_cle_deposer).
|
||||
|
||||
- name: Exiger une source pour la cle de la voute
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- serveur_ops_tenant_cle_source | length > 0
|
||||
fail_msg: >-
|
||||
serveur_ops_tenant_cle_deposer est vrai, mais aucune
|
||||
`serveur_ops_tenant_cle_source` n'est nommee. Armer un runner sans dire
|
||||
avec QUELLE cle n'a pas de sens — et poser un fichier vide le laisserait croire
|
||||
arme.
|
||||
when: serveur_ops_tenant_cle_deposer | bool
|
||||
|
||||
- name: Preparer le dossier des cles du runner
|
||||
ansible.builtin.file:
|
||||
path: "{{ serveur_ops_tenant_racine }}/.config"
|
||||
state: directory
|
||||
owner: "{{ serveur_ops_tenant_utilisateur }}"
|
||||
group: "{{ serveur_ops_tenant_utilisateur }}"
|
||||
mode: "0700"
|
||||
when:
|
||||
- serveur_ops_tenant_cle_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
- name: Deposer la cle de la voute
|
||||
ansible.builtin.copy:
|
||||
src: "{{ serveur_ops_tenant_cle_source }}"
|
||||
dest: "{{ serveur_ops_tenant_cle_destination }}"
|
||||
owner: "{{ serveur_ops_tenant_utilisateur }}"
|
||||
group: "{{ serveur_ops_tenant_utilisateur }}"
|
||||
mode: "0600"
|
||||
no_log: true
|
||||
when:
|
||||
- serveur_ops_tenant_cle_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
# ECRIRE, PUIS RELIRE — comme pour la voute, et pour la faute SYMETRIQUE : ici on ne
|
||||
# craint pas un chiffre devenu clair, mais une cle qui serait en fait une VOUTE. Copier le
|
||||
# mauvais fichier laisse un runner qui se croit arme et echoue au premier secret, tres
|
||||
# loin d'ici. On mesure aussi qu'elle n'est pas vide : un fichier de mot de passe vide est
|
||||
# accepte par Ansible et n'ouvre rien.
|
||||
- name: Relire la cle deposee
|
||||
ansible.builtin.stat:
|
||||
path: "{{ serveur_ops_tenant_cle_destination }}"
|
||||
checksum_algorithm: sha256
|
||||
register: serveur_ops_tenant_cle_posee
|
||||
when:
|
||||
- serveur_ops_tenant_cle_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
- name: Exiger une cle non vide, en 0600, et qui ne soit pas une voute
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- serveur_ops_tenant_cle_posee.stat.exists
|
||||
- serveur_ops_tenant_cle_posee.stat.size > 0
|
||||
- serveur_ops_tenant_cle_posee.stat.mode == '0600'
|
||||
fail_msg: >-
|
||||
La cle deposee est absente, vide, ou lisible au-dela de son proprietaire.
|
||||
Un runner arme d'une cle vide se croit arme et echoue au premier secret,
|
||||
tres loin d'ici.
|
||||
when:
|
||||
- serveur_ops_tenant_cle_deposer | bool
|
||||
- not ansible_check_mode
|
||||
|
|
|
|||
Loading…
Reference in a new issue