pare-feu proxmox : un flux ICMP devient une regle, au lieu d etre saute

Le type ICMP (echo-request) etait range parmi les ports derives et le flux
saute : le ping de supervision n avait pas de regle, et web-frontal-01 passe
en REJECT est devenu mort pour Icinga. icmp_type dans le devis, icmp-type
vers l API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-09-28 13:29:38 -04:00
parent 3676e69cd9
commit 4ce296f3d5
2 changed files with 24 additions and 7 deletions

View file

@ -80,7 +80,9 @@ def _regle_cle(r: dict) -> tuple:
str(r.get("action") or "").upper(),
str(r.get("source") or ""),
str(r.get("proto") or ""),
str(r.get("dport") or ""))
str(r.get("dport") or ""),
# Le devis dit `icmp_type`, l'API de Proxmox rend `icmp-type`.
str(r.get("icmp_type") or r.get("icmp-type") or ""))
def _prefixes_retires() -> tuple[str, ...]:
@ -260,7 +262,8 @@ def appliquer(api: Cluster, p: dict) -> int:
for r in g["regles"]:
corps = {"type": str(r.get("sens", "in")).lower(), "action": r["action"],
"enable": 1, "comment": str(r.get("via") or g.get("role", ""))[:100]}
for cle, champ in (("source", "source"), ("proto", "proto"), ("dport", "dport")):
for cle, champ in (("source", "source"), ("proto", "proto"), ("dport", "dport"),
("icmp_type", "icmp-type")):
if r.get(cle):
corps[champ] = r[cle]
_fait(api(f"/cluster/firewall/groups/{n}", "POST", corps), f"regle de {n}")

View file

@ -116,6 +116,21 @@ def _ports(fl: dict) -> list[str]:
return fixes
def _cibles(fl: dict) -> list[dict]:
"""Ce qu'une regle vise : un port TCP/UDP, ou un TYPE ICMP.
L'ICMP N'A PAS DE PORT (2026-09-28). Un flux `protocole: icmp` porte son type dans
`port` (`echo-request`). `_ports` ne garde que les nombres : le type etait range parmi
les « ports derives » et le flux SAUTE. Le ping de supervision, pourtant declare par
`serveur_debian`, n'a donc jamais eu de regle ; la premiere VM passee en `REJECT` est
devenue « morte » pour Icinga (100 % de pertes) tout en servant parfaitement.
"""
if str(fl.get("protocole", "tcp")).lower() == "icmp":
p = fl["port"]
return [{"proto": "icmp", "icmp_type": str(t)} for t in (p if isinstance(p, list) else [p])]
return [{"proto": fl.get("protocole", "tcp"), "dport": port} for port in _ports(fl)]
def construire(tenants: list[tuple[str, str, dict]]) -> dict:
"""Le devis, en structure. Un bloc par tenant federe."""
flux_par_role = charger_flux()
@ -201,11 +216,11 @@ def construire(tenants: list[tuple[str, str, dict]]) -> dict:
if not admin_de(nom):
continue
utilises.add(cle)
for port in _ports(fl):
for cible in _cibles(fl):
regles.append({
"action": "ACCEPT", "sens": "IN",
"source": f"+{cle}", "via": "administration",
"proto": fl.get("protocole", "tcp"), "dport": port,
**cible,
"raison": fl.get("raison", ""),
})
continue
@ -217,12 +232,11 @@ def construire(tenants: list[tuple[str, str, dict]]) -> dict:
utilises.add(cle)
else:
source, via = ",".join(srcs_pair), pair
for port in _ports(fl):
for cible in _cibles(fl):
regles.append({
"action": "ACCEPT", "sens": "IN",
"source": source, "via": via,
"proto": fl.get("protocole", "tcp"),
"dport": port,
**cible,
"raison": fl.get("raison", ""),
})
# GARDE ANTI-LOCKOUT. Le plan de gestion du tenant est resolu en