pare-feu Proxmox : des IPSets partout où c'est possible, et rien d'inutile
Six règles par tenant portaient quatorze adresses en dur : les mots-clés `flotte` et `edge` n'avaient pas droit à un IPSet, seuls les rôles en avaient. `flotte` en reçoit un, `edge` renvoie à celui de nginx. 36 des 40 règles se lisent maintenant `-source +t17-…`. Et le devis listait 28 à 30 IPSets par tenant dont la moitié n'était référencée nulle part : un opérateur en aurait créé 58 pour n'en utiliser qu'une douzaine. Seuls les IPSets référencés sont émis — 6 par tenant. Un devis crée ce qu'il liste. Restent quatre règles en liste explicite, celles dont la source est plusieurs rôles à la fois. Aucun IPSet unique ne les couvre et Proxmox n'accepte qu'une référence par règle ; les éclater gonflerait le devis pour un gain discutable. Preuves : 25 OK, 0 échec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ece250ae49
commit
dbb4465602
2 changed files with 36 additions and 5 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -36,6 +36,21 @@ chacun respecte sa contrainte, et le préfixe reste commun.
|
|||
Vérifié : aucune collision d'IPSet, et **tout renvoi `+X` d'une règle pointe vers un IPSet qui
|
||||
existe** — 58 IPSets, 34 groupes, aucun orphelin.
|
||||
|
||||
### Corrigé — des listes d'adresses en dur, et 48 IPSets inutilisés
|
||||
Six règles par tenant portaient **quatorze adresses en dur** : les mots-clés `flotte` et
|
||||
`edge` n'avaient pas droit à un IPSet, seuls les rôles en avaient. `flotte` en reçoit un
|
||||
désormais, et `edge` renvoie à celui de nginx. **36 des 40 règles** se lisent maintenant
|
||||
`-source +t17-…`.
|
||||
|
||||
Et le devis listait **28 à 30 IPSets par tenant dont la moitié n'était référencée nulle
|
||||
part** : un opérateur en aurait créé 58 pour n'en utiliser qu'une douzaine. Seuls les IPSets
|
||||
réellement référencés sont émis — **6 par tenant**. Un devis crée ce qu'il liste.
|
||||
|
||||
Restent quatre règles en liste explicite : celles dont la source est **plusieurs rôles à la
|
||||
fois** (LDAPS ouvert à Keycloak, Dovecot, Icinga Web et Postfix). Aucun IPSet unique ne les
|
||||
couvre et Proxmox n'accepte qu'une référence par règle ; les éclater gonflerait le devis pour
|
||||
un gain discutable.
|
||||
|
||||
### Corrigé — l'affectation variait selon l'état du tenant
|
||||
Elle partait de `hotes_actifs`, avec un repli sur « tous » quand il n'y en avait aucun. Deux
|
||||
tenants donnaient donc deux comportements : Technolibre listait ses 14 VM (zéro actif → repli),
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ RACINE = Path(__file__).resolve().parents[1]
|
|||
sys.path.insert(0, str(RACINE / "scripts"))
|
||||
|
||||
from resoudre_flux import ( # noqa: E402
|
||||
GROUPE_EDGE,
|
||||
charger_flux,
|
||||
est_groupe_operationnel,
|
||||
_enfants,
|
||||
|
|
@ -111,7 +112,13 @@ def construire(tenants: list[tuple[str, str, dict]]) -> dict:
|
|||
ips = _ip_par_hote(data)
|
||||
|
||||
# Un IPSet par role porte dans ce tenant : les membres sont ses hotes.
|
||||
# `flotte` en recoit un aussi : sans lui, six regles par tenant portaient
|
||||
# quatorze adresses en dur, illisibles et impossibles a mettre a jour d'un geste.
|
||||
ipsets: dict[str, dict] = {}
|
||||
if ips:
|
||||
ipsets[f"t{n['index']}-flotte"] = {
|
||||
"role": "flotte (tous les hotes du tenant)", "membres": sorted(set(ips.values())),
|
||||
}
|
||||
for groupe in sorted(_enfants(data)):
|
||||
if not est_groupe_operationnel(groupe):
|
||||
continue
|
||||
|
|
@ -123,6 +130,7 @@ def construire(tenants: list[tuple[str, str, dict]]) -> dict:
|
|||
|
||||
groupes: list[dict] = []
|
||||
sans_source: list[str] = []
|
||||
utilises: set[str] = set()
|
||||
for groupe in sorted(_enfants(data)):
|
||||
if not est_groupe_operationnel(groupe):
|
||||
continue
|
||||
|
|
@ -141,10 +149,17 @@ def construire(tenants: list[tuple[str, str, dict]]) -> dict:
|
|||
if not srcs:
|
||||
sans_source.append(f"{groupe}:{','.join(_ports(fl))}")
|
||||
continue
|
||||
# Source par IPSet quand le pair est UN role : une seule liste a tenir.
|
||||
source = (f"+{nom_ipset(pairs[0], n['index'])}"
|
||||
if len(pairs) == 1 and nom_ipset(pairs[0], n["index"]) in ipsets
|
||||
else ",".join(srcs))
|
||||
# Source par IPSet des que possible : une seule liste a tenir, et une
|
||||
# regle qui se lit. Les mots-cles `flotte` et `edge` y ont droit comme
|
||||
# les roles — `edge` designe le role nginx.
|
||||
source = ",".join(srcs)
|
||||
if len(pairs) == 1:
|
||||
cle = {"flotte": f"t{n['index']}-flotte",
|
||||
"edge": nom_ipset(GROUPE_EDGE, n["index"])}.get(
|
||||
pairs[0], nom_ipset(pairs[0], n["index"]))
|
||||
if cle in ipsets:
|
||||
source = f"+{cle}"
|
||||
utilises.add(cle)
|
||||
for port in _ports(fl):
|
||||
regles.append({
|
||||
"action": "ACCEPT", "sens": "IN",
|
||||
|
|
@ -179,7 +194,8 @@ def construire(tenants: list[tuple[str, str, dict]]) -> dict:
|
|||
|
||||
blocs.append({
|
||||
"tenant": nom, "etiquette": etiquette,
|
||||
"ipsets": ipsets, "groupes": groupes,
|
||||
"ipsets": {k: v for k, v in ipsets.items() if k in utilises},
|
||||
"groupes": groupes,
|
||||
"affectations": affect, "sans_source": sorted(set(sans_source)),
|
||||
"admin": admin_de(nom),
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue