flux : réseau d'administration = VLAN 10, et make flux réparé
`nftables_admin_ssh` est la source unique du « d'où administre-t-on » : il alimente les alias de la frontière, le devis du commutateur et le jeu nftables de chaque VM. Chezlepro déclarait encore l'ancien 192.168.255.0/24. `make flux` échouait par ailleurs sur un tri mêlant ports numériques et symboliques — défaut latent réveillé par les deux flux ICMP frag-needed, qui sont dans les deux sens. `_cle_port()` rend la clé homogène. Aperçus régénérés : les 14 hôtes actifs de Chezlepro portent 10.0.0.0/24. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
f8977d2d29
commit
b526160cbc
3 changed files with 53 additions and 2 deletions
33
CHANGELOG.md
33
CHANGELOG.md
|
|
@ -2,6 +2,39 @@
|
|||
|
||||
## 2026-08-06 — le chemin nord-sud devient dérivable
|
||||
|
||||
### Le réseau d'administration est le VLAN 10, partout
|
||||
|
||||
`nftables_admin_ssh` déclarait encore `192.168.255.0/24` chez Chezlepro — l'ancien monde.
|
||||
Cet intrant a **trois** consommateurs : les alias `SETOPS_ADMIN_*` de la frontière, le
|
||||
devis du commutateur, et le jeu nftables de chaque VM. Il est donc devenu la source unique
|
||||
du « d'où administre-t-on ».
|
||||
|
||||
- **Chezlepro** : `10.0.0.0/24`. Le VLAN 10 *est* son réseau d'administration (D-54).
|
||||
- **Technolibre** : ses deux réseaux **plus** `10.0.0.0/24`. Un tenant doit accepter son
|
||||
propre admin **et** celui de qui l'héberge — c'est de la VLAN 10 de l'hébergeur
|
||||
qu'Ansible se connecte. Sans le second, aucun déploiement ne joindrait ses VM.
|
||||
|
||||
Propagé : alias mis à jour sur la frontière, 14 aperçus nftables régénérés.
|
||||
|
||||
**Ce que ça évitait.** `flux-genere/infra-pki-01.nft` était figé avec l'ancienne valeur, et
|
||||
il **prime** sur le gabarit plat quand il existe. Un `make deployer` aurait posé un jeu
|
||||
n'autorisant SSH que depuis `192.168.255.0/24`, sur un hôte joint depuis `10.0.0.x` — la
|
||||
machine se serait fermée derrière l'outil qui venait de la configurer. Les treize autres
|
||||
n'avaient pas d'aperçu et seraient tombées sur le gabarit plat : SSH ouvert à tous, pas de
|
||||
blocage mais aucune restriction non plus. Les quatorze portent maintenant la bonne source.
|
||||
|
||||
### `make flux` était cassé par un port non numérique
|
||||
|
||||
Le tri du registre comparait les ports directement, donc `int` contre `str` dès que deux
|
||||
types se croisaient dans un même sens pour un même rôle. Le défaut était **latent** :
|
||||
`serveur_nginx` a `derive` depuis longtemps, mais son voisin est dans l'autre sens et le
|
||||
tuple tranche sur le rang avant d'atteindre le port. Les deux flux ICMP `frag-needed` de
|
||||
`serveur_debian`, eux, sont dans les deux sens — ils ont rendu la comparaison inévitable.
|
||||
|
||||
`_cle_port()` rend la clé homogène : les numériques d'abord, les symboliques ensuite par
|
||||
ordre alphabétique. Le registre se régénère.
|
||||
|
||||
|
||||
### L'EVPN tourne
|
||||
|
||||
Les commutateurs configurés, le trunk vérifié : `10.0.5.41` joint `.43` et `.47`. Le SDN
|
||||
|
|
|
|||
|
|
@ -19,9 +19,11 @@
|
|||
| `serveur_collabora` | ingress | 9980 | tcp | edge | clair | Éditeur servi au navigateur via l'edge (WebSocket WOPI ; TLS terminé à l'edge). |
|
||||
| `serveur_collabora` | ingress | 9980 | tcp | localhost | clair | Vérifications WOPI serveur→Collabora depuis Nextcloud co-localisé. |
|
||||
| `serveur_debian` | ingress | 22 | tcp | flotte, externe | ssh | Plan de gestion : administration et déploiement Ansible par SSH (inter-nœud ; l'accès depuis l'extérieur est filtré à l'OPNsense). |
|
||||
| `serveur_debian` | ingress | frag-needed | icmp | externe | n-a | ICMP « fragmentation nécessaire » entrant : sans lui, un distant ne peut pas nous demander de réduire nos paquets — les transferts se figent. |
|
||||
| `serveur_debian` | egress | 80 | tcp | externe | clair | Dépôts apt en clair et redirections HTTP des miroirs (l'intégrité vient de la signature des paquets, pas du transport). |
|
||||
| `serveur_debian` | egress | 123 | udp | externe | n-a | Synchronisation d'horloge (NTP). Une dérive fait échouer la validation des certificats step-ca et l'authentification SSO. |
|
||||
| `serveur_debian` | egress | 443 | tcp | externe | tls-requis | Dépôts apt en HTTPS (Debian, Smallstep, Grafana, Icinga, Forgejo, Nextcloud) — sans quoi aucun correctif de sécurité n'entre. |
|
||||
| `serveur_debian` | egress | frag-needed | icmp | externe | n-a | ICMP « fragmentation nécessaire » sortant : c'est ainsi que nos hôtes signalent l'overlay à 1450 aux correspondants distants. |
|
||||
| `serveur_dovecot` | ingress | 24 | tcp | serveur_postfix | tls-requis | Remise LMTP depuis Postfix (edge-mta -> mailstore), en TLS vérifié (lmtp_tls_security_level=verify). |
|
||||
| `serveur_dovecot` | ingress | 993 | tcp | externe | tls-requis | Accès courriel des utilisateurs (IMAPS). Frontière publique gérée à l'OPNsense. |
|
||||
| `serveur_dovecot` | ingress | 12345 | tcp | serveur_postfix | tls | Authentification SASL déléguée : Postfix valide les identifiants de soumission contre Dovecot. |
|
||||
|
|
@ -78,7 +80,7 @@
|
|||
## Synthèse chiffrement
|
||||
|
||||
- **clair** : 26 flux
|
||||
- **n-a** : 1 flux
|
||||
- **n-a** : 3 flux
|
||||
- **ssh** : 3 flux
|
||||
- **starttls** : 6 flux
|
||||
- **tls** : 8 flux
|
||||
|
|
|
|||
|
|
@ -103,6 +103,22 @@ def valider(flux_par_role: dict[str, list[dict]]) -> tuple[int, int]:
|
|||
|
||||
# --- Registre d'audit (niveau moteur, sans instance) ---------------------------
|
||||
|
||||
def _cle_port(port) -> tuple:
|
||||
"""Cle de tri stable pour un port, qu'il soit numerique ou symbolique.
|
||||
|
||||
Tous les ports ne sont pas des nombres : `derive` (serveur_nginx) et
|
||||
`frag-needed` (ICMP, serveur_debian) en sont. Comparer directement
|
||||
laisserait `int < str` lever une TypeError des que deux ports de types
|
||||
differents se retrouvent dans le meme sens pour un meme role.
|
||||
"""
|
||||
if isinstance(port, list):
|
||||
port = port[0] if port else 0
|
||||
try:
|
||||
return (0, int(port), "")
|
||||
except (TypeError, ValueError):
|
||||
return (1, 0, str(port))
|
||||
|
||||
|
||||
def generer_registre(flux_par_role: dict[str, list[dict]]) -> str:
|
||||
lignes = [
|
||||
"# Registre des flux réseau — matrice d'audit (GÉNÉRÉ)",
|
||||
|
|
@ -116,7 +132,7 @@ def generer_registre(flux_par_role: dict[str, list[dict]]) -> str:
|
|||
]
|
||||
rangs = {s: i for i, s in enumerate(("ingress", "egress"))}
|
||||
for role in sorted(flux_par_role):
|
||||
for fl in sorted(flux_par_role[role], key=lambda f: (rangs.get(f.get("sens"), 9), f.get("port") or 0)):
|
||||
for fl in sorted(flux_par_role[role], key=lambda f: (rangs.get(f.get("sens"), 9), _cle_port(f.get("port")))):
|
||||
pair = ", ".join(str(p) for p in _pairs(fl))
|
||||
port = fl.get("port")
|
||||
port = ", ".join(str(x) for x in port) if isinstance(port, list) else str(port)
|
||||
|
|
|
|||
Loading…
Reference in a new issue