From 862253518f4a0d39374b2dd4cd1611713a01c742 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 29 Sep 2026 01:36:08 +0200 Subject: [PATCH] Issues 143 and 144: the found firewall is neither retired nor all of it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both found by converging the control node — the first machine with a firewall to flip, since the two before it had none. 143: the preview and the flip both say the found firewall is disabled. The node reported converged, 372 resources applied, nothing failed, and ufw is still enabled and active. A converged node's declaration carries no resource that would disable it; the sentence is printed by the command and nothing implements it. 144: ufw was never what filtered the traffic that mattered there. Fifty forwarded openings converged through it had matched zero packets, while a chain the predecessor installed in the container runtime's pre-accept hook did the work — in memory only, recreated by nothing. The mesh's filter now covers that path, so the machine no longer depends on it, but the chain remains and is the only thing refusing the bus and the registry, which the design requires reachable from anywhere so a machine can enrol before it has a private address. --- .../00-report.md | 73 +++++++++++++++++++ .../00-report.md | 70 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 04-ISSUES/143-converging-does-not-retire-the-firewall-it-found/00-report.md create mode 100644 04-ISSUES/144-the-predecessors-rules-outlive-the-firewall-it-was-found-as/00-report.md diff --git a/04-ISSUES/143-converging-does-not-retire-the-firewall-it-found/00-report.md b/04-ISSUES/143-converging-does-not-retire-the-firewall-it-found/00-report.md new file mode 100644 index 0000000..82618f1 --- /dev/null +++ b/04-ISSUES/143-converging-does-not-retire-the-firewall-it-found/00-report.md @@ -0,0 +1,73 @@ +--- +status: located +opened: 2026-09-29 +located-in: + - mesh-controller internal/catalogue (a converged node's declaration) + - mesh-host internal/apply/opening.go +fixed-by: +amended-design: +--- + +# 143 — Converging a machine does not retire the firewall it found, and says it does + +## What was observed + +The control-node was converged on 2026-09-29, the first machine with a found firewall to be flipped — +the two converged before it had none. + +The preview said, and the flip repeated: + +``` +the found firewall (ufw) is disabled, never flushed: its configuration stays on disk +... +sent: the host loads the mesh's filter and disables the firewall it found +``` + +The mesh then reported the node `converged`, 372 resources applied, nothing failed. Afterwards, on the +machine: + +``` +systemctl is-enabled ufw -> enabled +systemctl is-active ufw -> active +``` + +And the declaration that was sent carries no resource that would disable it. A converged node's +declaration has no adoption block at all, and nothing in its 372 resources names the found firewall. +The sentence is printed by the command; no resource implements it. + +## Why it matters beyond this instance + +**It is a stated behaviour that does not happen, reported as success** — the fault this repository +exists to catch, and +[ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md) states it as +part of what the flip *is*: "loads the mesh's derived filter in place of its refusal-only table, and +retires the found firewall by disabling it, never by flushing". + +**It could only be found on the first machine that had one.** The two machines converged before this +had no firewall to retire, so the step had never run, and nothing reported that it had not. That is +the same shape as [issue 136](../136-a-module-may-name-a-program-the-machine-does-not-have/00-report.md): +a step that is silent when it does nothing. + +**The machine is left doubly filtered, which is not what either firewall describes.** Every base chain +at a hook runs and a drop in any is final, so the machine now enforces the *intersection* of the mesh's +derived filter and a rule set left by the system being replaced. Nothing is broken by that today — +measured from outside, mail, the proxy and git-over-ssh answer and the databases and admin interfaces +are refused — but the machine's behaviour is described by neither of the two things claiming to +describe it, and the stale set includes a rule for a broker that no longer exists. + +**And returning the node to adopted would be wrong in the other direction.** ADR 0100 says that +restores the found firewall by enabling it again; enabling something that was never disabled is +harmless, but the mesh's belief about which firewall is in force has been wrong in both modes. + +## Open questions + +- Which side owns retiring it — a resource in the declaration, so it is applied and reported like + everything else, or the flip as an act? A resource seems right: the flip is otherwise entirely + expressed as one, and an act that only the command performs cannot be re-checked on a later + reconcile. +- What should a reconcile do if the found firewall is enabled again by hand, or by a package update? + Convergence is a state, so presumably re-disable it and say so. +- Should the preview say what it *will* do rather than what it does, until a step exists that does it? + The wording was read as evidence twice in one session. +- Is there a check that a sentence the mesh prints corresponds to a resource it sends? This is the + second time today that a printed claim and a sent declaration disagreed. diff --git a/04-ISSUES/144-the-predecessors-rules-outlive-the-firewall-it-was-found-as/00-report.md b/04-ISSUES/144-the-predecessors-rules-outlive-the-firewall-it-was-found-as/00-report.md new file mode 100644 index 0000000..63ac152 --- /dev/null +++ b/04-ISSUES/144-the-predecessors-rules-outlive-the-firewall-it-was-found-as/00-report.md @@ -0,0 +1,70 @@ +--- +status: located +opened: 2026-09-29 +located-in: + - mesh-host internal/apply/opening.go + - mesh-controller cmd/mesh-controller (the converge preview) +fixed-by: +amended-design: +--- + +# 144 — A predecessor's rules outlive the firewall the mesh found, and the mesh cannot see them + +## What was observed + +The mesh reports one thing about a machine's existing filtering: `firewall found: ufw`. On the +control-node, ufw was never what filtered the traffic that mattered. + +Measured on 2026-09-29, before the machine was converged: + +- ufw filters connections *to the machine*. It does not filter connections to a container's published + port, which arrive on the forwarded path where the container runtime accepts them before ufw's + forward chains are reached. Around thirty ports were published that way. +- Every one of the mesh's own forwarded openings, converged through ufw, had matched **zero packets** — + fifty rules in that chain, none ever matched, while the chain itself had passed 1.6 million + established packets. The restrictions read as applied and were inert. +- What actually kept those ports off the internet was a chain the predecessor installed in the + container runtime's own pre-accept hook, allowing the deliberately public ports and the private + ranges and dropping the rest on the outward link. Confirmed from outside: the proxy answered, the + container manager did not. +- That chain exists only in the running kernel. The persisted rule file is the distribution's empty + default, and nothing on disk recreates the chain. + +After the flip, the mesh's own filter is loaded and does cover the forwarded path, so the machine no +longer depends on that chain. But **the chain is still there**, and it is now the only thing refusing +two ports the mesh believes are open: the bus and the registry, which +[ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md) requires be +reachable from anywhere so a machine can enrol and pull before it has a private-network address. The +mesh's rendered filter accepts both from anywhere. From outside, both are refused. + +## Why it matters beyond this instance + +**"The firewall found" is a kind, and filtering is not all in one place.** The host identifies one +front-end and reports it. A machine can carry rules from several sources — the front-end's own, the +container runtime's, an intrusion-prevention chain, and whatever a predecessor installed directly — +and the mesh's account of what filters the machine names exactly one of them. + +**So adoption's central promise was half-true in both directions.** What the mesh converged through +the found firewall on the forwarded path did nothing at all, and what did the work was invisible to it. +A machine was reported as filtered by a mechanism that was not filtering. + +**And convergence cannot retire what it cannot see.** Even once +[issue 143](../143-converging-does-not-retire-the-firewall-it-found/00-report.md) is fixed and the found +firewall is disabled, this chain remains, silently narrowing the machine below what the mesh's own +filter says. A rule the mesh did not write, cannot list, and will not remove — which today breaks the +enrolment path the design guarantees. + +**The safe direction is not the same as the correct one.** Being more closed than intended broke nothing +visible, which is exactly why it went unnoticed for as long as the mesh has been on this machine. + +## Open questions + +- Should the host report every place the machine filters from, rather than one kind — the front-end, + the runtime's hooks, and any chain it does not recognise, named so a person can look? +- What should the mesh do about rules it did not write and does not understand? Reporting them seems + right; removing them cannot be, and leaving them silent is what produced this. +- Does an opening converged through a found firewall need a check that it can actually take effect? + Fifty rules matching nothing would have been visible from the counters at any point. +- Is the bus and the registry being reachable from anywhere still what the mesh wants on a machine that + faces the internet? The design says yes, for enrolment. It deserves asking on its own rather than + being answered by a leftover.