ADR 0100: the guard lets the machine itself through; in use is a non-loopback listener; openings say from where; 09 in step with the flip

This commit is contained in:
2026-09-22 16:34:53 +02:00
parent f3152d827f
commit 37252f9c3e
6 changed files with 47 additions and 35 deletions
+11 -7
View File
@@ -537,21 +537,25 @@ is why the check reads packets.*
### On an adopted node
*2026-09-22, [ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md).* **The firewall found on the machine stays in force**, and the mesh
loads no table there that drops by default or that accepts — neither genesis's base ruleset nor
loads no table there that drops by default or holds an accept — neither genesis's base ruleset nor
the derived one. Every base chain at a hook runs and a drop in any is final, whatever the other
firewall is written in, so a second, stricter table would close every port the machine serves, and
an accept in one would open nothing the found firewall drops. What the mesh needs reachable it
declares as **openings**: a port, from where, on the incoming path or the forwarded path — a
published container port is forwarded, and a firewall that filters only incoming traffic never
sees it. The controller derives them from what the filter would be derived from: the assigned
modules' `listens`, the hub's port, the foundation's ports. The host converges each opening through
sees it. The controller derives them from what the filter would be derived from, each from where
the filter would admit it: the assigned modules' `listens`, the hub's port, the bus and the registry
from anywhere; the store's port and the broker's management port from the private network. The host converges each opening through
the found firewall in that firewall's own terms, marks it as the mesh's, removes only what it
marked, and re-checks every opening on each reconcile so a reload or a reboot does not lose it for
longer than one reconcile. An opening is state, not a command, so it travels over the link like any
other resource. **The mesh guards its own ports in a table of its own that only refuses** —
accepting by default and holding nothing but refusals, so it cannot close what the machine serves,
and the found firewall's reload does not touch it. It refuses the store's port and the broker's
management port from outside the private network, matched on the port the packet was sent to; the
passing everything by default and holding nothing but refusals of the foundation's own two ports,
checked free at genesis, so it cannot close what the machine serves, and the found firewall's
reload does not touch it. It refuses the store's port and the broker's management port except from
the private network and the machine itself — loopback and the container runtime's networks — at
the prerouting hook, before the container runtime redirects the packet, so it matches the port the
packet was sent to, for both address families; the
bus, the registry and the hub's port stay reachable from anywhere, as a node enrols and pulls
before it has a private-network address. One kind of found firewall is spoken; a machine with none
needs no openings, and a machine with another kind is refused adoption. Converging the node refuses
@@ -560,7 +564,7 @@ sockets and published ports — what will close and which modules it will take,
derived filter in place of the refusal-only table and disables the found firewall without flushing
it. *How it is checked:* the adoption bed asserts the found firewall's rules differ only by the
mesh's marked rules, that the store is unreachable from off the private network before and after
the found firewall reloads, that a machine not yet enrolled reaches the bus, that a second machine
the found firewall reloads and reachable from a container on the node, that a machine not yet enrolled reaches the bus, that a second machine
enrols through the openings before and after a reload and a reboot, and that after the flip the
declared port is open and the undeclared one closed.