step-ca : la cle de signature versionnee — plus aucun appel sortant pour l obtenir

Le deploiement de Chezlepro depuis son propre runner a franchi le socle et le
durcissement sur les quinze machines, et s est arrete sur une seule :

    infra-pki-01 : Echec temporaire dans la resolution du nom
    url: https://packages.smallstep.com/keys/apt/repo-signing-key.gpg

UN TENANT N A PAS DE DNS SORTANT, ET C EST VOULU. Il resout chez lui, sa requete ne
traverse jamais la frontiere. apt s en sort par le mandataire du cache, qui resout a
sa place ; get_url n a pas de mandataire. Mesure sur la machine : DNS bloque, 443
sortant OK par adresse, apt via le cache OK.

Les cinq reprises du role ne pouvaient rien : elles etaient ecrites pour un serveur
INTERMITTENT (2026-08-23), pas pour une resolution fermee. Une reprise ne repare que
ce qui est passager.

UNE DETTE NOMMEE, APPELEE. client_artefacts le disait : les depots tiers en HTTPS
vont en direct, la seconde voie est propre et RESTE A FAIRE. Elle a ete appelee le
jour ou un ecosysteme s est reconstruit derriere une frontiere qui fait son travail.

La cle est versionnee, avec son empreinte et sa procedure de rafraichissement. Meme
idiome que les collections et les roues : le depot porte, la cible n ouvre rien.
C est ce qui rend une lignee reproductible SANS INTERNET.

Cout ecrit : une rotation amont n est plus recuperee toute seule, mais elle ne passe
pas inapercue — apt refuse alors le depot, bruyamment.

TROUVE EN LA RECUPERANT : l URL publique REDIRIGE vers pkgs.infra.smallstep.com.
Sans suivre les redirections on obtient un fichier VIDE, et curl -f sans -L sort en
succes. La procedure le dit, parce que ce piege ne se voit qu au deploiement suivant.

Le correctif du pare-feu a tenu : plus une seule suspension, quinze machines a
ok=66 et 0 unreachable.

make verifier : vert. make prouver : CONFORME, 55 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:
Daniel Allaire 2026-08-30 12:13:39 -04:00
parent 6f4833e65c
commit fc76a4e252
4 changed files with 154 additions and 35 deletions

View file

@ -1,5 +1,59 @@
# CHANGELOG — Set-OPS # CHANGELOG — Set-OPS
## 2026-08-30 — La cle de signature est versionnee : une lignee qui se reproduit sans Internet
**55 preuves.** Le deploiement de Chezlepro depuis son propre runner a franchi le socle et
le durcissement sur les quinze machines, et s'est arrete sur une seule :
```
infra-pki-01 : Request failed: <urlopen error [Errno -3]
Echec temporaire dans la resolution du nom>
url: https://packages.smallstep.com/keys/apt/repo-signing-key.gpg
```
**Un tenant n'a pas de DNS sortant, et c'est voulu.** Il resout chez lui, sa requete ne
traverse jamais la frontiere. `apt` s'en sort par le mandataire du cache — qui resout a sa
place ; `get_url` n'a pas de mandataire. Mesure sur la machine :
```
resolv.conf 9.9.9.9, 149.112.112.112
DNS BLOQUE
443 sortant OK (par adresse)
apt via le cache OK
```
Les cinq reprises du role ne pouvaient rien : elles etaient ecrites pour un serveur
**intermittent** (mesure du 2026-08-23), pas pour une resolution fermee. *Une reprise ne
repare que ce qui est passager.*
### Une dette nommee, appelee
C'etait ecrit dans `client_artefacts` : *« les depots tiers en HTTPS continuent d'aller en
direct […] la seconde voie est propre et **reste a faire** — et le dire vaut mieux que le
laisser croire »*. Elle a ete appelee le jour ou un ecosysteme s'est reconstruit derriere
une frontiere qui fait son travail.
**La cle est desormais versionnee**, avec son empreinte et sa procedure de rafraichissement.
Meme idiome que les collections Ansible et les roues Python : le depot porte, la cible
n'ouvre rien. C'est ce qui rend une lignee reproductible **sans Internet**.
*Ce que ca coute, et qui est ecrit : une rotation amont n'est plus recuperee toute seule.
Elle ne passe pas inapercue pour autant — `apt` refuse alors le depot, bruyamment. Mieux
vaut un refus lisible qu'un telechargement qui reussit depuis n'importe ou.*
**Trouve en la recuperant** : l'URL publique **redirige** vers `pkgs.infra.smallstep.com`.
Sans suivre les redirections, on obtient un fichier VIDE que rien ne signale — un `curl -f`
sans `-L` rend zero octet et sort en succes. La procedure de mise a jour le dit, parce que
ce piege-la ne se voit qu'au deploiement suivant.
### Le correctif du pare-feu a tenu
Plus une seule suspension : les quinze machines ont franchi le durcissement (`ok=66`
chacune, `0 unreachable`) et repris la main apres s'etre armees. C'est la vraie nouvelle
de ce passage — le defaut d'hier soir ne se reproduit plus.
make verifier : vert. make prouver : CONFORME, 55 OK, 0 echec, 0 saute.
## 2026-08-30 — Le terrain etait inoccupable : la cle du tenant nait avec ses machines ## 2026-08-30 — Le terrain etait inoccupable : la cle du tenant nait avec ses machines
**55 preuves.** Le deploiement lance depuis `ops-01` s'est arrete au premier geste, sur les **55 preuves.** Le deploiement lance depuis `ops-01` s'est arrete au premier geste, sur les

View file

@ -0,0 +1,51 @@
# La clé de signature du dépôt Smallstep — versionnée, et pourquoi
```
pub rsa2048 2021-05-04 [SC]
35BA A0B3 3E9E B396 F59C A838 C0BA 5CE6 DC63 15A3
uid Artifact Registry Repository Signer <artifact-registry-repository-signer@google.com>
```
## Pourquoi elle est ici et non téléchargée
**Un tenant n'a pas de DNS sortant, et c'est voulu** — il résout chez lui, sa requête ne
traverse jamais la frontière. `apt` s'en sort par le mandataire du cache, qui résout à sa
place ; `get_url` n'a pas de mandataire.
Mesuré le 2026-08-30 sur `infra-pki-01`, première machine à porter l'autorité de
certification de Chezlepro :
```
Request failed: <urlopen error [Errno -3] Échec temporaire dans la résolution du nom>
url: https://packages.smallstep.com/keys/apt/repo-signing-key.gpg
```
La dette était déjà nommée dans `roles/client_artefacts/defaults/main.yml` : *« les dépôts
tiers en HTTPS continuent d'aller en direct […] la seconde voie est propre et reste à
faire »*. Elle a été appelée le jour où un écosystème s'est reconstruit derrière une
frontière qui fait son travail.
**Ce que ça achète : une lignée qui se reproduit sans Internet.** C'est le même principe
que les collections Ansible et les roues Python — le contrôleur récupère une fois, le
dépôt porte, la cible n'ouvre rien.
## Ce que ça coûte, et qu'il faut savoir
Cette clé **expirera ou tournera** un jour. Le dépôt apt échouera alors bruyamment, à la
vérification de signature — un échec clair, pas un silence. C'est le bon sens de la panne :
mieux vaut un refus lisible qu'un téléchargement qui réussit depuis n'importe où.
## La remettre à jour
Depuis une machine qui a le DNS (le poste de l'exploitant), **et en suivant les
redirections** — l'URL publique renvoie vers `pkgs.infra.smallstep.com`, et sans `-L` on
récupère un fichier VIDE que rien ne signale :
```sh
curl -fsSL https://packages.smallstep.com/keys/apt/repo-signing-key.gpg \
-o roles/serveur_step_ca/files/smallstep-repo-signing-key.asc
gpg --show-keys --with-fingerprint roles/serveur_step_ca/files/smallstep-repo-signing-key.asc
```
Comparer l'empreinte à celle du haut de ce fichier avant de committer. Une clé qu'on
remplace sans regarder son empreinte n'est plus une clé, c'est un fichier.

View file

@ -0,0 +1,19 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
xsBNBGCRt7MBCADkYJHHQQoL6tKrW/LbmfR9ljz7ib2aWno4JO3VKQvLwjyUMPpq
/SXXMOnx8jXwgWizpPxQYDRJ0SQXS9ULJ1hXRL/OgMnZAYvYDeV2jBnKsAIEdiG/
e1qm8P4W9qpWJc+hNq7FOT13RzGWRx57SdLWSXo0KeY38r9lvjjOmT/cuOcmjwlD
T9XYf/RSO+yJ/AsyMdAr+ZbDeQUd9HYJiPdI04lGaGM02MjDMnx+monc+y54t+Z+
ry1WtQdzoQt9dHlIPlV1tR+xV5DHHsejCZxu9TWzzSlL5wfBBeEz7R/OIzivGJpW
QdJzd+2QDXSRg9q2XYWP5ZVtSgjVVJjNlb6ZABEBAAHNVEFydGlmYWN0IFJlZ2lz
dHJ5IFJlcG9zaXRvcnkgU2lnbmVyIDxhcnRpZmFjdC1yZWdpc3RyeS1yZXBvc2l0
b3J5LXNpZ25lckBnb29nbGUuY29tPsLAjgQTAQoAOBYhBDW6oLM+nrOW9ZyoOMC6
XObcYxWjBQJgkbezAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEMC6XObc
YxWj+igIAMFh6DrAYMeq9sbZ1ZG6oAMrinUheGQbEqe76nIDQNsZnhDwZ2wWqgVC
7DgOMqlhQmOmzm7M6Nzmq2dvPwq3xC2OeI9fQyzjT72deBTzLP7PJok9PJFOMdLf
ILSsUnmMsheQt4DUO0jYAX2KUuWOIXXJaZ319QyoRNBPYa5qz7qXS7wHLOY89IDq
fHt6Aud8ER5zhyOyhytcYMeaGC1g1IKWmgewnhEq02FantMJGlmmFi2eA0EPD02G
C3742QGqRxLwjWsm5/TpyuU24EYKRGCRm7QdVIo3ugFSetKrn0byOxWGBvtu4fH8
XWvZkRT+u+yzH1s5yFYBqc2JTrrJvRU=
=QnvN
-----END PGP PUBLIC KEY BLOCK-----

View file

@ -16,47 +16,42 @@
group: root group: root
mode: "0755" mode: "0755"
# Recuperee UNE FOIS. Sans garde, chaque deploiement recontactait le serveur du # LA GARDE « RECUPEREE UNE FOIS » A DISPARU AVEC CE QU'ELLE GARDAIT (2026-08-30).
# fournisseur : cinq cles x quatorze hotes = soixante-dix allers-retours externes pour
# des cles deja installees, et autant d'occasions qu'un tiers lent fasse tomber le
# deploiement. Arbitrage rendu le 2026-08-09 : une plateforme souveraine ne depend pas
# de six serveurs etrangers pour redeployer ce qu'elle possede deja.
# #
# CONSEQUENCE ASSUMEE : une rotation de cle amont n'est plus recuperee toute seule. Elle # Elle evitait de recontacter le fournisseur a chaque passage — soixante-dix allers-retours
# ne passe pas inapercue pour autant — `apt` refuse alors le depot, bruyamment. Pour # externes pour des cles deja installees (arbitrage du 2026-08-09). La cle etant desormais
# forcer le rafraichissement : supprimer le fichier et rejouer le role. # VERSIONNEE, il n'y a plus d'aller-retour a eviter : `copy` ne sort pas, et son
- name: Cette ressource est-elle deja recuperee ? (Telecharger la cle de signature Sm) # idempotence vient de la comparaison d'empreintes, pas d'un `stat` qu'on ecrit soi-meme.
ansible.builtin.stat: #
path: "{{ serveur_step_ca_depot_cle_fichier }}" # Le meme arbitrage est donc honore plus completement : la plateforme ne depend plus du
register: telecharger_la_cle_de_signature_smallste_present # tout de serveurs etrangers pour redeployer ce qu'elle possede deja.
- name: Telecharger la cle de signature Smallstep # LA CLE DE SIGNATURE EST VERSIONNEE, PLUS TELECHARGEE (2026-08-30).
# UN SERVEUR TIERS QUI REPOND UNE FOIS SUR DEUX NE DOIT PAS ARRETER UN DEPLOIEMENT DE #
# QUARANTE MINUTES (mesure du 2026-08-23, premier deploiement de patient 0). # Elle etait tiree de `packages.smallstep.com` par son NOM. Un tenant n'a pas de DNS
# # sortant — il resout chez lui, sa requete ne traverse jamais la frontiere — et
# `packages.smallstep.com` est intermittent : la meme URL pend au premier essai et rend # `get_url` n'a pas de mandataire, la ou `apt` s'en sort par le cache qui resout a sa
# 200 en 0,48 s au second. Le defaut de `get_url` est un delai de 10 secondes et AUCUNE # place. Mesure sur `infra-pki-01`, premiere machine a porter l'autorite de Chezlepro :
# reprise — le socle echouait donc sur la premiere machine, avant meme d'avoir pose le #
# resolveur des autres. # Request failed: <urlopen error [Errno -3] Echec temporaire dans la resolution du nom>
# #
# Mesure faite avant d'accuser : DNS resolvait, la poignee TLS aboutissait # Les cinq reprises de l'ancienne version ne pouvaient rien : elles etaient ecrites pour
# (`Verify return code: 0`), un transfert de 138 Ko depuis deb.debian.org passait en # un serveur INTERMITTENT (mesure du 2026-08-23), pas pour une resolution fermee. Une
# 0,09 s, et le chemin acceptait 1450 octets et refusait 1500 — exactement l'attendu en # reprise ne repare que ce qui est passager.
# overlay. Le reseau n'y etait pour rien. #
# # MEME IDIOME QUE LES COLLECTIONS ET LES ROUES : le depot porte, la cible n'ouvre rien.
# Meme idiome que les roles Keycloak et Forgejo devant leurs propres tiers. # C'est ce qui rend une lignee reproductible sans Internet. Empreinte, raison et
when: not telecharger_la_cle_de_signature_smallste_present.stat.exists # procedure de mise a jour dans `files/README-cle-smallstep.md`.
ansible.builtin.get_url: #
url: "{{ serveur_step_ca_depot_cle_url }}" # `serveur_step_ca_depot_cle_url` reste declaree : elle documente la provenance et sert
# a rafraichir le fichier depuis un poste qui a le DNS. Elle n'est plus lue au deploiement.
- name: Poser la cle de signature Smallstep (versionnee, aucun appel sortant)
ansible.builtin.copy:
src: smallstep-repo-signing-key.asc
dest: "{{ serveur_step_ca_depot_cle_fichier }}" dest: "{{ serveur_step_ca_depot_cle_fichier }}"
owner: root owner: root
group: root group: root
mode: "0644" mode: "0644"
timeout: 30
register: serveur_step_ca_cle
retries: 5
delay: 6
until: serveur_step_ca_cle is succeeded
- name: Ajouter le depot apt Smallstep - name: Ajouter le depot apt Smallstep
ansible.builtin.template: ansible.builtin.template: