feat(openbao) : le magasin de certificats du tier d'ingress #13
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/dn42-ingress-tier"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Les trois nœuds qui ne savent pas résoudre le challenge dns-01 servent enfin en TLS. Un cluster OpenBao à quatre nœuds remplace caddy.storage.swytch, tombé en panne franche : il persiste sur disque, se réplique par raft et se descelle seul auprès du moteur transit de ca1.
Mesuré après bascule : une émission sur fr-rbx1, zéro sur les trois autres, les quatre servant le même certificat avec Verify return code: 0 (ok). Silence Alertmanager levé.
Six pièges mesurés plutôt que supposés sont documentés dans les READMEs des rôles — le plus vicieux étant qu'un bloc bao { } dans la configuration d'un bao agent parse sans erreur et est ignoré, l'agent retombant sur 127.0.0.1.
Les deux listes de CIDR partent identiques et ne reviennent pas pareil : secret_id_bound_cidrs : "10.2.242.202/32" ← le /32 conservé token_bound_cidrs : "10.2.242.202" ← le /32 retiré `token_bound_cidrs` traverse le parseur d'adresses de sockaddr, qui réduit un /32 à sa forme nue ; `secret_id_bound_cidrs` est stocké tel quel. Le test de sous-ensemble par `combine()` y voyait une dérive éternelle sur une valeur pourtant juste. La comparaison retire le /32 des DEUX côtés plutôt que d'envoyer d'emblée une forme nue en pariant sur le comportement du parseur : on compare ce qu'on veut dire, pas ce que la bibliothèque en a fait. La leçon dépasse OpenBao et vaut d'être écrite : `combine()` en test de sous-ensemble suppose que l'API rend ce qu'on lui donne, et un champ normalisé à l'écriture casse cette hypothèse dans le sens le plus bénin — du bruit permanent, qui finit par faire ignorer un vrai changement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FGwvXLVXJ2PrRFwJTB3Xp9Le module de stockage ne sait pas s'authentifier — il SURVEILLE un fichier de token par fsnotify, ce qui fait d'un token changeant le mode de fonctionnement prévu plutôt qu'un contournement. Un token vaulté aurait été soit éternel, soit une panne à date fixe. L'agent tourne sous SON PROPRE compte, et c'est le cœur du montage : un Caddy compromis rend un token d'une heure, pas le couple (role_id, secret_id) qui vaut un accès permanent. La jonction passe par le bit SETGID du répertoire de sortie — le sink d'OpenBao sait poser un mode, pas un propriétaire, et sans ce bit la seule sortie aurait été de faire tourner l'agent sous `caddy`, c'est-à-dire d'abandonner la séparation qu'on venait de construire. Deux pièges mesurés sur fr-rbx1 plutôt que supposés : - LE BLOC S'APPELLE `vault`, PAS `bao`. Sur un produit qui a renommé sa CLI en `bao` et ses variables en BAO_*, un bloc `bao { address = … }` parse sans erreur et est IGNORÉ : l'agent retombe sur 127.0.0.1:8200, où rien n'écoute. Vérifié en pointant les deux variantes vers une adresse volontairement fausse — `vault` la reprend, `bao` ne la voit jamais. - `remove_secret_id_file_after_reading` vaut `true` PAR DÉFAUT. L'agent supprime son secret_id après lecture ; tout marche jusqu'au premier redémarrage de l'unité, où Caddy perd son magasin. Une panne différée que déclenche le geste le plus banal qui soit. Le rôle ne réclame un token d'administration que si le secret_id manque, donc au premier passage sur un nœud et jamais ensuite — c'est ce qui lui permet de vivre dans le playbook principal. Et il ATTEND que le fichier de token apparaisse : un agent qui échoue en boucle s'affiche `active (running)`, et rien d'autre ne le dirait. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FGwvXLVXJ2PrRFwJTB3Xp9Binaire reconstruit avec `caddy.storage.vault` (gerolf-vent/caddy-vault-storage v1.2.3) à la place de `caddy.storage.swytch`. Somme identique sur deux téléchargements, modules vérifiés dans le binaire : plus aucune trace de Swytch. Ce que le nouveau module fait différemment, et qui a décidé du choix : il ne stocke rien lui-même. Il parle à un coffre qui persiste, réplique et se sauvegarde, et il accepte une LISTE d'adresses avec bascule — la disponibilité vient du coffre plutôt que d'un protocole de cluster embarqué dans un serveur web, ce qui est exactement ce qui avait lâché. Trois pièges de son parseur, lus dans `module.go` : - `addresses` prend UNE chaîne séparée par des virgules. `addresses "a" "b"` n'est pas une erreur : le second argument est lu comme une clé, et le switch n'ayant pas de branche par défaut, il est ignoré en silence. Une option mal orthographiée disparaît pareillement. - `lock_timeout` et `lock_check_interval` sont des entiers nus en secondes. `60s` fait échouer strconv.Atoi et arrête le chargement sur un message qui ne nomme pas la clé. - le vrai filet est son contrôle de capacités au démarrage, qui rend un mount ou un préfixe désaccordé de la politique franchement fatal. `ingress_shared_storage` REVIENT dans les defaults du rôle. Il vivait dans group_vars/all/ parce que nftables en dépendait — le flux QUIC 7380 n'avait de raison d'être que si le magasin était actif. Ce flux disparaît avec Swytch : la ligne 18 de la matrice est retirée, celle du coffre prend son numéro, et un drapeau documentant une dépendance morte est pire qu'inutile. Retirés au passage : la passphrase Swytch du vault, le nom de cluster dans le /etc/hosts privé, et `nftables_ingress_cluster_port`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FGwvXLVXJ2PrRFwJTB3Xp9Trois défauts trouvés en déroulant, dont le premier empêchait Caddy de démarrer. L'AC D'ATNET PAR L'ENVIRONNEMENT. `caddy.storage.vault` n'expose aucune option `ca_cert` : il construit son client avec `vault.DefaultConfig()`, qui lit l'environnement. Sans `VAULT_CACERT`, Caddy refuse de démarrer — « all servers are unavailable », précédé d'un `x509: certificate signed by unknown authority` par adresse. Et c'est `VAULT_CACERT`, pas `BAO_CACERT` : le module embarque github.com/hashicorp/vault/api, et c'est la bibliothèque qui nomme la variable. Que l'échec soit FRANC est la bonne nouvelle de cette panne : le module vérifie la santé des quatre coffres à son provisionnement, donc une AC absente tombe au démarrage et non à la première écriture, un mois plus tard. LE COFFRE LOCAL EN PREMIER. Le module retient « the first healthy instance » dans l'ordre de la liste. Triée par nom d'hôte, `fr-bod1` arrivait en tête : les QUATRE nœuds allaient chercher leur magasin à Bordeaux — mesuré, `Connected {"address": "https://10.2.242.202:8200"}` depuis Roubaix. UN NIVEAU DE JOURNAL. `ingress_log_level`, INFO par défaut. Le module raconte chaque Stat, Load et Store en DEBUG et à aucun autre niveau ; sans lui, une panne de magasin ne montre que son verdict, et « storage is probably misconfigured » ne dit pas laquelle des trois opérations a échoué. MESURÉ APRÈS BASCULE, et c'est la propriété que tout ce chantier achetait : UNE émission sur fr-rbx1, ZÉRO sur les trois autres, les quatre servant le même certificat (notAfter identique à la seconde) avec `Verify return code: 0 (ok)` contre la racine DN42. Les trois nœuds qui ne savent pas résoudre `dns-01` ont enfin un certificat. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FGwvXLVXJ2PrRFwJTB3Xp9