ADR 0191: the mesh's resolver holds only the mesh's own names; a public name resolves publicly

Publishing every routed public name at a private address turned ace's LAN-facing resolver into an
outage for non-members: a phone got the control-node's tunnel address for the mail server. Routes
have internal names since 0151 and the proxy certifies public names publicly, so nothing needs the
private answer. Narrows 0066 and 0151; amends connectivity §2 and §5.
This commit is contained in:
2026-10-03 15:11:45 +02:00
parent 22e96e5bc7
commit e5e6e56ecf
5 changed files with 160 additions and 13 deletions
+38 -13
View File
@@ -5,10 +5,12 @@ code:
- mesh-controller internal/catalogue/filtering.go
- mesh-controller examples/route-proxy
- mesh-controller internal/identity/authority.go
- mesh-controller cmd/mesh-controller/plan.go (the names the roster publishes)
- mesh-host internal/identity/serving.go
- mesh-host internal/apply (the service that reflects a rule set)
updated: 2026-10-02
updated: 2026-10-03
decisions:
- 02-DECISIONS/0191-the-meshs-resolver-holds-only-the-meshs-own-names.md
- 02-DECISIONS/0180-the-found-front-end-is-uninstalled-once-a-machine-is-converged.md
- 02-DECISIONS/0170-the-firewall-seat-serves-its-verbs.md
- 02-DECISIONS/0169-a-machine-joins-through-the-tunnel-and-the-bus-is-never-public.md
@@ -421,7 +423,22 @@ that module and nothing else.
the argument for the table in ADR 0009 being a table: the pattern is only obvious once seen, and
the cost of not seeing it is inventing a mechanism that already exists.
### And the public names a proxy serves must resolve in the mesh too
### The mesh resolves only its own names; a public name resolves publicly
**The mesh's resolver holds names under the mesh suffix and nothing else** — every machine, and through
it every route's internal name `<label>.<node>.internal`
([ADR 0151](../../02-DECISIONS/0151-a-routes-internal-name-is-composed-under-the-node-that-serves-it.md)).
**A public name the mesh serves is never given a private answer**: it is forwarded and resolves to the
public address, from a member and from anything else the resolver answers — a resolver may serve a
machine's LAN, and a phone on that LAN must get the address it can reach
([ADR 0191](../../02-DECISIONS/0191-the-meshs-resolver-holds-only-the-meshs-own-names.md)). Inside the
mesh, a routed service is reached, and certified by the internal authority, under its internal name.
*Checked by the controller's catalogue tests — every name the roster carries ends in the mesh suffix —
and on a machine by asking its resolver for a public name the mesh serves: the answer is the public
address.*
*What follows is how the mesh got here, kept because the reasoning it rejects is the expensive half to
rediscover.*
*2026-09-09, found by an internal certificate authority that could not issue.* The mesh writes every
`<node>.internal` name into every declared container and treats the public names a proxy serves as a
@@ -444,6 +461,13 @@ would go stale the day one changes. The mesh propagates the names it was told to
knows nothing about what they mean
([ADR 0066](../../02-DECISIONS/0066-public-routing-is-name-agnostic.md)).
*2026-10-03, withdrawn.* Publishing public names with private answers turned every resolver that also
serves a LAN into an outage for that LAN's non-members — a phone was handed the control-node's tunnel
address for the mail server — while every check, run from a member, passed. Its reason had gone: routes
have internal names since ADR 0151, and the proxy certifies public names from a public authority and
internal names from the internal one. Superseded by the rule at the head of this section
([ADR 0191](../../02-DECISIONS/0191-the-meshs-resolver-holds-only-the-meshs-own-names.md)).
## 3 — Exposure
Settled by [ADR 0007](../../02-DECISIONS/0007-connectivity.md); summarised here because
@@ -871,13 +895,15 @@ is unchanged. **The same code path certifies against an internal authority as ag
only the issuer differs.** That is what makes trusted certificates possible for a mesh whose names
the public internet cannot resolve.
**And it does not work until the routed name resolves inside the mesh** — the §2 finding above,
arriving here because this is what needed it. The authority's challenge reaches the routed name only
once that name is in internal resolution; a public authority is handed that dependency by public
DNS, and an internal one has to be handed it by the mesh. *Checked by a handshake to a routed name
that verifies against the internal root and nothing else — which cannot succeed unless the issuer
first reached the name to certify it*
([ADR 0066](../../02-DECISIONS/0066-public-routing-is-name-agnostic.md)).
**The internal authority certifies internal names; a public one certifies public names.** The
authority's challenge reaches the name it certifies, so each certifies what it can resolve: the
internal authority a route's `<label>.<node>.internal`, which the mesh resolves, and a public authority
the public name, which public DNS resolves. A proxy holds both, and a public name is never certified
by the internal authority. *Checked by a handshake to a route's internal name that verifies against
the internal root and nothing else, and one to its public name that verifies against the public
roots* ([ADR 0191](../../02-DECISIONS/0191-the-meshs-resolver-holds-only-the-meshs-own-names.md)).
Until 2026-10-03 this paragraph had the internal authority certify public names, which needed them
resolved inside the mesh ([ADR 0066](../../02-DECISIONS/0066-public-routing-is-name-agnostic.md)).
## 6 — One statement behind exposure, filtering and certificates
@@ -983,10 +1009,9 @@ The list is worth having in one place, because it is most of the argument:
operator's to move between meshes, but the manifest layer still stores it as a literal — so today
the composition is a per-node override rather than the design. The interpolation that would let a
module carry a label and a node carry the domain, and the mesh join them, does not yet exist.
- **Publishing route names into internal resolution.** The same ADR requires a granted route to be
resolvable inside the mesh, not only routable from outside it; the mechanism that writes
`<node>.internal` into containers does not yet also write the routed names, which is why an
internal issuer cannot currently validate one without a hand-placed entry.
- **Withdrawing public names from internal resolution.** The roster still publishes every routed
public name at its serving node's private address, which ADR 0191 forbids; until the controller
stops, a resolver that answers a LAN hands that LAN's non-members addresses they cannot reach.
## The hub adopts the predecessor's tunnel