La refonte de ce matin posait une convention. Une convention qu'on n'outille pas tient tant que quelqu'un y pense : c'est le raisonnement de D-70, applique au corpus documentaire. Etat de depart mesure : 2 documents sur 34 declaraient leur lecteur. Les 32 autres disaient leur SUJET — ce qui avait enfoui le runbook de reprise le plus utile du depot au §6 de autorisation.md. Les 38 le declarent desormais, lecteur determine document par document et non colle au gabarit : l'exploitant (devis, migration de tenant, cycle de vie, gabarit d'or), le mainteneur (conceptions, registres, carte), le lecteur externe (ecosysteme-chezlepro), l'agent IA (MISE-A-JOUR-CODEX-CLAUDE). Deux exemptions DERIVEES, pas listees — un chemin en dur aurait vieilli a la premiere page ajoutee : un document qui s'annonce genere, et un fragment sans titre. Les 13 exemptes verifies un par un ; aucun document ecrit a la main n'est exempte par accident. La preuve ne lit que l'EN-TETE, ce qui empeche frontiere-opnsense.md et plan-et-generation.md — qui parlent de generation dans leur corps — d'etre exemptes a tort. Eprouvee dans les deux sens. Elle a echoue seule des sa premiere execution en nommant deux documents que mon inventaire avait manques (docs/audit/). Puis test negatif delibere : declaration retiree de meta-classe.md -> ECHEC la nommant ; restauree -> OK. Ce qu'elle ne teste pas : que le lecteur declare soit le BON. Ca se juge en revue ; elle garantit qu'on a du y penser. P01–P34. Comptes perimes corriges au passage (AGENTS.md et devis-services.md annoncaient encore 30 preuves). Verifie : prouver.py 0 (34 OK), plan-recette inchange. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.5 KiB
Registre des flux réseau — conception
Pour qui : le mainteneur qui déclare un flux réseau dans
roles/*/meta/flux.yml.
But
Set-OPS tient un registre des flux (qui parle à qui, sur quel port, dans quel sens, pourquoi) pour deux usages :
- Générer les règles nftables de chaque serveur — autoriser les flux déclarés, tout refuser d'autre (moindre privilège). Complète la couche chiffrement (TLS) par la couche accès.
- Preuve d'audit — la matrice d'accès réseau documentée (source → dest : port : chiffrement : raison), exigée par un audit de sécurité et le label de certification.
Principe : le rôle possède ses flux
Comme meta/empreinte.yml (dimensionnement) est la propriété du rôle, roles/<rôle>/meta/flux.yml
déclare les flux du logiciel. Le rôle sait sur quoi il écoute et à quoi il se connecte ; personne
d'autre. Le registre global se dérive de l'ensemble des flux.yml des rôles présents sur un nœud.
Schéma de meta/flux.yml
flux:
- sens: ingress # ingress = ce rôle ÉCOUTE ; egress = ce rôle SE CONNECTE
port: 5432 # entier ou liste [80, 443]
protocole: tcp # tcp | udp
pair: [serveur_keycloak, serveur_forgejo] # QUI — voir « Résolution du pair »
chiffrement: tls-requis # tls-requis | tls | starttls | ssh | tls-cible | clair | n-a (bonus audit)
# tls-requis : chiffré + pair vérifié (verify-full) | tls : chiffré | starttls : mise à niveau opportuniste
# ssh : transport SSH (chiffré, hôte vérifié) | tls-cible : TLS visé mais pas encore appliqué (feuille de route)
# clair : non chiffré (local ou terminé à l'edge) | n-a : sans objet
raison: "Connexions applicatives (verify-full)." # lisible, pour l'audit
Résolution du pair
| Valeur | Résout vers |
|---|---|
un rôle/groupe (serveur_prometheus) |
les IP des hôtes de ce groupe (via le plan) |
edge |
le(s) hôte(s) de l'edge (serveur_nginx) |
flotte |
tous les nœuds de l'instance |
externe |
hors flotte (frontière publique — géré à l'OPNsense, pas dans le nœud) |
localhost |
boucle locale — aucune règle inter-nœud (nftables autorise lo) |
expositions |
dérivé des expose: des applications (cas de l'edge → backends) |
La résolution pair → IP réutilise le plan (registre IP/FQDN/zones) déjà en place.
Génération
Un résolveur (miroir de instancier) agrège, par serveur, les flux.yml de tous ses rôles
(services + intégrations), résout les pair, et produit :
nftables: ruleset par serveur (allow des flux résolus,policy droppar défaut), consommé par le rôlenftables_baseline;- le registre d'audit :
docs/registre-flux.md(généré) + une ciblemake flux.
Activation prudente
Activer nftables = action destructive (peut couper l'accès) → confirmation explicite + déploiement graduel (garder l'accès SSH/Ansible, tester par nœud). nftables reste préparé mais non activé tant que le registre n'est pas complet et validé.
Séquence
- ✅ figer le schéma (ce doc) + piloter sur postgresql / client_metrique / nginx ;
- le résolveur (agrégation → règles + registre) ;
- remplir tous les rôles (large transcription du travail zéro-confiance déjà fait) ;
- générer + registre d'audit ; puis activer nftables nœud par nœud.
poste: false — un service publié qui ne s'adresse pas à un humain
Ajouté le 2026-08-09. Ne concerne que les flux ingress dont le pair inclut externe,
c'est-à-dire les services publiés.
La frontière étend ces services au VLAN d'administration : le poste de l'exploitant y
est, et c'est de là qu'il ouvre ses consoles web ou son client de courriel. Mais tous les
services publiés ne s'adressent pas à un humain — le 25 entrant de Postfix est un flux
serveur à serveur, les MX distants.
| Situation | Exemple | poste |
|---|---|---|
| un poste de travail s'y connecte | serveur_nginx 443, serveur_dovecot 993 |
absent (défaut true) |
| flux serveur à serveur uniquement | serveur_postfix 25 entrant |
false |
Sans ce mot-clé, la frontière autorisait admin → 25 que le nftables de l'hôte refusait :
deux couches déclarant deux politiques différentes. Mesuré par make frontiere-mesurer, qui
distingue précisément ce cas d'une vraie fuite.
Le mot-clé vit dans meta/flux.yml, avec le rôle qui sait ce que son port veut dire. Le
générateur de la frontière, lui, ne connaît aucun numéro de port.
partage: — décrire une écoute plutôt que l'ouvrir
Ajouté le 2026-08-09 avec P33, qui refuse que deux rôles co-localisés revendiquent le même port.
Le registre confondait deux situations :
| Situation | Exemple | partage |
|---|---|---|
| le rôle ouvre l'écoute | serveur_dovecot lie 12345 (SASL réseau) |
absent |
| le rôle décrit celle d'un autre | serveur_backup emprunte le sshd de serveur_debian |
true |
Sans cette distinction, la seule co-location légitime de la flotte — tcp/22 sur
backup-01 — serait signalée à tort. Une preuve qui crie sur un cas sain finit par être
ignorée, ce qui est pire que de ne pas l'avoir.
Corollaire à retenir : un port qu'on subit (le défaut amont d'un logiciel) doit être imposé et déclaré comme les autres. Celui d'Alloy ne l'était pas, et c'est la seule raison pour laquelle la collision a pu durer des semaines.