From 027c41d12535c1db4fb539a03797dfc7568355d9 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 14 Sep 2026 14:59:11 +0200 Subject: [PATCH] =?UTF-8?q?Issue=20047=20=E2=80=94=20the=20firewall=20leav?= =?UTF-8?q?es=20published=20container=20ports=20open?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rehearsed on three lab machines before doing it on an anchor: loading the mesh's rules refuses an ordinary host port and leaves a published container port reachable, same prober, same second. It is deliberate — no forward chain, because dropping there would stop every container — but traffic to a published port never reaches the input chain, so the firewall is silent about it. The anchor publishes 38 such ports today, all filtered by the system being replaced, so the cutover would open every one of them while reporting a firewall that is up. --- .../00-report.md | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 04-ISSUES/047-the-firewall-does-not-cover-published-container-ports/00-report.md diff --git a/04-ISSUES/047-the-firewall-does-not-cover-published-container-ports/00-report.md b/04-ISSUES/047-the-firewall-does-not-cover-published-container-ports/00-report.md new file mode 100644 index 0000000..d72f232 --- /dev/null +++ b/04-ISSUES/047-the-firewall-does-not-cover-published-container-ports/00-report.md @@ -0,0 +1,69 @@ +--- +status: open +opened: 2026-09-14 +located-in: [] +fixed-by: +amended-design: +--- + +# 047 — The firewall does not cover published container ports + +## Symptom + +A machine running the mesh's firewall drops what it should drop and leaves every container port +published on all addresses open to anything that can reach the machine. + +Rehearsed in the lab on three machines, one probing another, with a single change between the two +measurements: + +| | ordinary port on the host | container port published on `0.0.0.0` | +|---|---|---| +| before the mesh's rules | reachable | reachable | +| after the mesh's rules | **refused** | **still reachable** | + +Same prober, same ports, same second. The first column is the firewall working. The second is the +question. + +## Why this is the way it is + +It is deliberate, and the reasoning is written where the rules are generated: the mesh's table hooks +`input` and `output` and **no forward chain**, because what a machine forwards is the container +runtime's business — the runtime writes rules for the bridges it creates, and a second table +dropping in `forward` would drop container traffic the runtime explicitly allowed, stopping every +container on the node including the control plane. + +That reasoning is sound. The conclusion drawn from it is not the only one available, because traffic +to a published port does not traverse `input` at all: it is redirected and then forwarded. So a +default-drop `input` chain says nothing whatsoever about it, and the firewall is silent on the ports +most likely to matter. + +## Why it matters, measured rather than argued + +The anchor this mesh will be installed onto publishes **38 distinct container ports on all +addresses** — a document store, three cache sentinels, mail transfer and retrieval, the forge's own +SSH, and thirty more. + +Today those are filtered, by the system being replaced, which does it with rules that hook exactly +the path this one leaves alone. So the cutover from the old firewall to this one **opens all +thirty-eight at once, silently, on a machine with a public address**, while every check reports a +firewall that is up and dropping by default. + +That is the worst shape a security fault can take: the mechanism is present, it reports success, and +the thing it is believed to be doing is not the thing it does. + +## How it would be checked + +Two probes from another machine, against a port on the host and a published container port, before +and after the rules are loaded. Both must change together. The lab can do this — it is how the table +above was produced — and nothing does it today. + +## Open questions + +- Can the mesh filter forwarded traffic without owning the whole `forward` chain? A table that + accepts by default and drops only what the mesh knows about would not stop the runtime's traffic, + and hooking `forward` at all is the thing the current comment rejects. +- Should a module's declared reach apply to its published ports? A module that says it listens to + the mesh only, and is then reachable from everywhere because its port is published, is not doing + what its manifest says. +- Is the answer instead that the mesh should not publish on all addresses? A port bound to the + private network needs no filtering, and most of these want exactly that.