diff --git a/04-ISSUES/042-nothing-gives-a-node-an-account-for-a-registry/00-report.md b/04-ISSUES/042-nothing-gives-a-node-an-account-for-a-registry/00-report.md new file mode 100644 index 0000000..019cf14 --- /dev/null +++ b/04-ISSUES/042-nothing-gives-a-node-an-account-for-a-registry/00-report.md @@ -0,0 +1,64 @@ +--- +status: open +opened: 2026-09-11 +located-in: [] +fixed-by: +amended-design: +--- + +# 042 — Nothing gives a node an account for a registry + +## Symptom + +A module names an image in a registry that requires authentication. The machine cannot fetch it: + +``` +pull access denied … authorization failed: no basic auth credentials +``` + +Nothing in the mesh delivers a registry credential to a node. There is no provision for it, no +field in a manifest for it, and no step in enrolment that establishes one. + +Observed when the lab's own image registry was deleted and machines were given a real path to the +internet for the first time. Public images fetched normally; the operator's own — in their own +registry — could not be fetched at all. + +## Why this matters + +**Delivery ends at a node pulling an image, and this is the last step of it.** The whole design +from source to artifact to machine assumes the final fetch succeeds. It succeeded until now for +one reason: everything was either public, or came from a registry the harness ran with no +authentication at all. + +**And it applies to the mesh's own store, not only to somebody else's.** The registry the mesh runs +is reached over the private network and today asks for nothing. That is a decision — *anything that +can reach it can read every artifact the mesh holds, and push to it if pushing is open* — but it +has never been written down as one. It reads as an absence, which is the kind of thing that stays +true by accident until it is exploited. + +**The mesh already knows how to do this.** A provision grants a consumer a credential, minted by +the mesh, sealed to the machine, with the plaintext discarded. An account on a registry is exactly +that shape: the artifact store is already a provision, and a node that must pull from it is already +a consumer of it. What is missing is not a mechanism but the recognition that pulling is a use of +the store, not a thing that happens beneath it. + +**It is also a bootstrap question**, which is where it will bite first: the machine that installs a +mesh pulls the control plane's image before the mesh exists to grant anything +([ADR 0067](../../02-DECISIONS/0067-genesis-is-a-pivot.md)). Whatever the answer is, it has to +survive a moment when there is nobody to ask. + +## Open questions + +- **Should the ability to pull be granted like anything else** — the store mints a per-node account, + seals it to the machine, and the host writes whatever the runtime reads? That would make a node's + reach into the artifact store follow the same rules as its reach into a database. +- **What should the mesh's own registry require?** If the answer is "nothing, inside the private + network", that is defensible and must be *recorded* as the decision it is, with what it assumes + about who is on that network. +- **What authenticates a push?** Reading and writing are not the same grant, and a builder that may + publish is a much stronger thing than a node that may fetch. +- **What does an operator's own external registry do here?** It is not the mesh's to grant accounts + on. Is the credential operator-supplied, like any other secret the mesh cannot invent — and if so, + which module owns it, given that every module pulling from there needs it? +- **How does any of this work before the mesh exists?** The bootstrap fetches images with no mesh to + grant a credential, so the first pull is either public, anonymous, or carried.