diff --git a/02-DECISIONS/0066-public-routing-is-name-agnostic.md b/02-DECISIONS/0066-public-routing-is-name-agnostic.md new file mode 100644 index 0000000..ce711fd --- /dev/null +++ b/02-DECISIONS/0066-public-routing-is-name-agnostic.md @@ -0,0 +1,115 @@ +--- +topic: routing and names +status: proposed +date: 2026-09-09 +deciders: jochen +reconstructed: false +extends: 0007-connectivity.md +--- + +# 66. Public routing is name-agnostic, its names are resolved inside the mesh, and an internal authority can certify them + +## Context + +**[ADR 0007](0007-connectivity.md) and [connectivity §3](../03-DESIGN/01-to-be/08-connectivity.md) +made a public route a grant: a workload that must be reachable requires a route, the proxy provides +it, the consumer contributes the name it wants and the port it listens on.** What was never pinned +is **what that name is** — and building a whole mesh in the lab showed the gap costs more than it +looks. + +**The catalogue shipped each route as a full domain.** A module that needed a public name carried +that name, in full, as a literal in its manifest. Running the same catalogue against a different +domain — a lab standing in for production, or a second operator's mesh — meant overriding that +literal on every routed module, per node. The mesh was, in effect, carrying a **map of names to +services**: the one thing it should never hold, because a name is the operator's choice (one runs +the forge at `git`, another at `code`) and the domain is the node's, and neither is the mesh's to +know. + +**And a second gap surfaced the moment an internal issuer tried to certify those names.** +[Connectivity §5](../03-DESIGN/01-to-be/08-connectivity.md) already states the issuer must be +configurable and that the lab runs its own ACME authority. With that authority wired to the proxy, +issuance still could not complete: the authority accepted the order and offered a challenge, then +**could not connect to the validation target.** Nothing inside the mesh resolved the public route +name. The mesh publishes each `.internal` name into every container, but not the public names +the proxy serves — so a validator living in the mesh had no address to reach, and a name the mesh +cannot resolve is a name it cannot have certified. + +**The two are one problem.** A name the mesh can *compose* from parts it is given, and *propagate* +to whoever needs to resolve it, is exactly a name it can also have *certified* — and the reverse: +without the composition and the propagation, neither the routing nor the certificate is the +operator's to move between meshes. + +## Considered Options + +**1. Keep the full domain in the manifest, override per node.** The status quo. It works, and it is +wrong in the specific way this repository cares about: the catalogue holds a domain map, lab and +production differ by an override on every routed module rather than one fact, and a module manifest +names something — the public domain — that belongs to the node, not the module. An unowned name in +the wrong place is the shape of a leak. + +**2. A module declares a label; the node declares its public domain; the mesh composes.** The route +contribution carries a subdomain the operator chose, the node carries its public domain as +node-level configuration, and the mesh joins `