diff --git a/02-DECISIONS/0032-the-local-account-owns-the-mesh.md b/02-DECISIONS/0032-the-local-account-owns-the-mesh.md new file mode 100644 index 0000000..c288478 --- /dev/null +++ b/02-DECISIONS/0032-the-local-account-owns-the-mesh.md @@ -0,0 +1,78 @@ +--- +topic: how we work +status: accepted +date: 2026-08-31 +deciders: jochen +reconstructed: false +extends: 02-DECISIONS/0031-the-control-plane-authenticates-nobody.md +--- + +# 32. The local account owns the mesh; a surface delegates to a module + +## Context + +[ADR 0031](0031-the-control-plane-authenticates-nobody.md) settled that the control plane +authenticates nobody, and deliberately left one thing open: **how a person signing in to a mesh +surface is authenticated.** This answers it, and answers a question 0031 did not ask — *who owns +the mesh at all.* + +**There was no answer, and the absence was invisible** because every operation so far has been run +by the person sitting at the machine. Nothing had to say whether that was the design or the +circumstance. + +## Decision + +**The account that installed the host owns the mesh on that node.** Authority is a local login, +and there is nothing else to hold. + +**No mesh user model.** No accounts, no roles, no grants, nothing to administer. A person with a +shell on a node can do anything the mesh can do there, because that is already true and pretending +otherwise would be a boundary that does not exist. + +**This follows from what was already decided rather than adding to it.** +[ADR 0004](0004-a-node-and-how-it-joins.md) says there is no authorisation between nodes — every +node is the operator's own, so a message from one is a message from them, and *the mesh boundary +is therefore the security boundary*. A user model inside that boundary would guard nothing: anyone +who could be stopped by it could equally read the node's key off the disk. + +**The board is different, and the difference is the network.** A surface reachable by a browser +has to know who is asking, because the people reaching it are not, by construction, people with a +shell on the machine. **So the board delegates to an OAuth provider** — which is a module. + +## What this does not change + +**The identity provider is still not substrate** (ADR 0031). A *surface* delegating +authentication is not *the control plane* delegating it. The control plane runs, applies +declarations and reaches nodes with no identity provider in existence; only the board needs one, +and only to decide whose browser it is talking to. + +The test is unchanged and still answers no: *does the control plane need it in order to run?* + +## Consequences + +**The board depends on a module, and says so.** An ordinary edge in the graph, which means the +board cannot come up before the provider it authenticates against — stated as a dependency rather +than discovered as an outage. + +**Moving the identity provider takes the board with it.** During that module's own conversion the +board is unavailable, and that is acceptable: it is a surface, nothing depends on it, and a brief +interruption is the trade already accepted everywhere else. Nothing that keeps a service serving +goes through it. + +**Anyone with a shell on a node has full authority there.** Written down rather than left implied, +because it is the sentence that decides who gets an account on a machine. The protection is the +machine's own login, and the overlay that keeps the machine unreachable from outside +([ADR 0007](0007-connectivity.md)). + +**A node cannot be operated by somebody without a login on it.** Deliberate, and the cost of +having no user model: there is no way to give a person authority over one node without giving them +a shell there. If that is ever wanted, it is a new decision and not a gap in this one. + +## References + +- [ADR 0031](0031-the-control-plane-authenticates-nobody.md) — the control plane authenticates + nobody; this answers what it left open +- [ADR 0004](0004-a-node-and-how-it-joins.md) — no authorisation between nodes, and why the mesh + boundary is the security boundary +- [`03-DESIGN/01-to-be/11-a-board.md`](../03-DESIGN/01-to-be/11-a-board.md) — the surface this is + about diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index 8077008..e2c5a47 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -127,5 +127,6 @@ python3 00-META/checks/index.py fail if stale - **0022** — [The constitution absorbs what is already enforced](0022-the-constitution-absorbs-what-is-enforced.md) - **0023** — [The approval is the checkpoint, not the second pair of hands](0023-approval-is-the-checkpoint.md) - **0025** — [The design record is read where it is written, never copied to be found](0025-the-design-record-is-read-not-copied.md) +- **0032** — [The local account owns the mesh; a surface delegates to a module](0032-the-local-account-owns-the-mesh.md)