Files
hq/04-ISSUES/052-the-firewall-does-not-know-the-brokers-port/00-report.md
T
jschoubben b163ed1fcc Issue 052 — the firewall closes the port the mesh runs on
The packet filter generates its rules from what modules declare they listen on.
The broker is not a module, so it declares nothing, so its port is not opened.
Every machine dials that port to enrol and to receive every declaration it is
ever sent.

Invisible where it is assembled and fatal on the next machine: a mesh of one
never dials its own broker across the network, so the ruleset looks right. The
first machine to join is refused at the packet filter during enrolment, several
steps from anything that reports it — and assigning the firewall before joining
machines is both the natural order and the one that breaks.

This is 051 in a second place. That issue says the substrate cannot be updated
because the mesh holds no record of it; the same absence means the firewall
cannot know it exists. Ssh is already a floor for the same reason — a machine
nobody can reach is a machine nobody can repair — and the broker may be the same
class of fact.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-14 22:59:33 +02:00

3.2 KiB

status, opened, located-in, fixed-by, amended-design
status opened located-in fixed-by amended-design
open 2026-09-14

052 — The firewall closes the port the mesh runs on

Symptom

A one-node mesh with the packet filter assigned generates this input chain:

policy drop
ct state established,related accept
iif "lo" accept
icmp / icmpv6 accept
<mesh address> tcp dport 22   accept      ssh
<mesh address> tcp dport 5000 accept      the registry
<mesh address> tcp dport 20000 accept
udp dport 51820 accept                    the overlay

The substrate broker's port is not there. Every machine dials it to enrol and to receive every declaration it is ever sent. Nothing opens it.

The rules are generated from what modules declare they listen on. The broker is not a module — it is raised by the installer from the bundle — so it declares nothing, and the generator has nothing to generate from.

Why this matters

It is invisible on the mesh where it is first assembled and fatal on the next one. A mesh of one never dials its own broker across the network, so the missing rule changes nothing and the firewall looks correct. The first machine that tries to join is refused at the packet filter, during enrolment, before the mesh can report anything about it — and the cause is several steps from the symptom.

It would have been met during the migration, not before it. The intended order is to raise the anchor, assign its modules, then join the other machines. Assigning the firewall before the second machine enrols is both the natural order and the one that breaks.

It is 051 in a second place. That issue records that the substrate cannot be updated because the mesh holds no record of it. The same absence means the firewall cannot know the substrate exists. Anything else generated from what modules declare has the same hole: the store, the broker, and their ports are outside every such computation.

The store is the same shape and has not been checked. It binds on the machine and is reached by the control plane; whether that survives a default-drop policy has not been established here.

Open questions

  • Should the substrate declare its listens — which means the substrate being something the mesh holds a record of, i.e. 051's adoption?
  • Or should the firewall have a floor that is not derived from modules at all, the way ssh already is? Ssh is in the rules for exactly this reason: a machine nobody can reach is a machine nobody can repair, and that is not a thing any module declares. The broker is arguably the same class of fact — the mesh cannot manage a machine it cannot talk to.
  • What else is in that class? Whatever the answer, the question "which ports must be open for the mesh itself to work" should be answerable from one place rather than assembled from modules that happen to exist.

How this would be checked

Rule Checked by
A machine with the firewall assigned can still be joined The packet filter is assigned to an anchor, and a second machine enrols afterwards.
The mesh's own ports are open The generated ruleset is compared against the substrate's own bindings, not only against module declarations.