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.