5.0 KiB
topic, status, date, deciders, reconstructed, extends
| topic | status | date | deciders | reconstructed | extends |
|---|---|---|---|---|---|
| building it | accepted | 2026-09-17 | jochen | false | 0072-two-graphs-and-the-build-chain.md |
82. The registry is reached by name, and the overlay is its security
Context
Delivery ends at a node pulling an image, and for every node but the one that built it, that step has never worked. Three facts conspired, each recorded separately:
- Artifact references are written under
127.0.0.1:5000— a deliberate parking (the catalogue says so in the commit that reverted the mesh-reachable name: "the runtime refused it: 'http: server gave HTTP response to HTTPS client' … the binding expression returns then"), so a joined node is told to pull from its own loopback (issue 048). - A container runtime treats any non-loopback registry as HTTPS, and the mesh's registry serves plain HTTP; nothing the mesh writes tells any runtime otherwise — the one place that file existed was the lab's, which is why this never failed in a bed (issue 048).
- Nothing gives a node an account for the registry (issue 042) — and nothing has ever said whether one is required.
The tempting fix is TLS from the mesh's own authority. The machinery even exists — the mesh CA
issues leaves for <node>.internal names, and a certificate: manifest field delivers them. But
the registry is reached over the overlay, and the overlay is WireGuard: every byte is already
encrypted and already authenticated to a peer the mesh admitted. The mesh's own code has carried
this position for weeks: "the registry is reached over the mesh's own private network … a second
layer inside it would be certificates to issue and rotate for no property the first does not
have." TLS inside the tunnel would also re-order genesis (a certificate needs the network, the
registry precedes it) and put CA handling into three clients (the runtime, the archive fetcher,
the builder) — cost with no new property.
Decision
The overlay is the registry's transport security, and the mesh writes the trust it means.
- References name the registry by its mesh name. The builder publishes to
<provider>.internal:<port>(the binding'satandport) — the parked one-line change lands. Genesis still publishes to loopback on the first machine, before any overlay exists; references minted at genesis stay loopback and are valid where they matter — on that machine. A rebuild re-pins to the mesh name. - Every node on the private network is told the mesh's registry speaks plain HTTP. The
controller injects, into every such node's declaration, a merged
/etc/docker/daemon.jsonnaming<provider>.internal:<port>underinsecure-registries, and a service resource that restarts the runtime when that file changes — the/etc/hostspattern for the content, the nftables pattern for the reload. No module author is involved; being on the network is what grants the trust, because being on the network is what the trust is. - No accounts (issue 042), recorded as the position it always was. Reading and pushing
require presence on the overlay and nothing else. The boundary is enforced, not assumed: the
registry's
listensisfrom: mesh, the firewall derives from it, and the overlay admits only peers holding mesh-issued keys. An operator's external registry credential is an ordinary operator-supplied secret (secret accept), owned by whichever module names that registry. Per-node accounts return as a decision, not a patch, if the boundary assumption ever changes — the shape would be the existing provision flow.
How this is checked
- The no-fake lab bed: a joined node pulls a mesh-built image by the registry's
.internalname over the overlay — an address outside every range the lab's own runtime configuration trusts, so the mesh-written trust is what makes it work or nothing does. - The firewall half is generated from
listensand visible in the node's ruleset (from: mesh). - The plaintext-inside-tunnel position holds exactly as long as the registry is unreachable off
the overlay; the
listensstanza and the derived ruleset are the check.
Consequences
A runtime restart when the trust first lands on a node — at joining, before workloads, where it is free. The registry's HTTP is exposed to whatever stands on the overlay, which is the stated boundary; a mesh that wants defence in depth inside its own tunnel reopens this record rather than bolting certificates on quietly. Issues 042 and 048 close on this record.