docs: define accounts host trust boundary

This commit is contained in:
jason.woltje committed 2026-11-10 13:41:05 -06:00
1 parent a7b2199390
commit fe820d17bf
1 file changed
+42
+42
View File
@@ -881,6 +881,43 @@ OIDC session or an account. The rule:
never on a deployed one.
- Dev mode keeps every CLI verb as it is.
### Host trust boundary
The host is the trust boundary. The instance uid can read and write the
instance's config, data root, bus files and credentials. That makes the uid
equivalent to root for this instance, though not root on the host. A CLI
token cannot protect the instance from someone who already has that uid:
they can read the token file, the bus database and every key, or change the
files directly. A token could help a remote admin CLI that has no host
access. That is a possible later feature, not part of Phase M.
Phase M reduces who holds the instance uid and makes local account actions
visible. A dedicated instance uid is used by no agent seat or human login.
In M2, the accounts loader refuses an accounts file with the wrong owner or
group/other write permission; `mosaic accounts` refuses when its uid does
not own the config directory and writes the OS uid into its receipt. In M3,
stamped builds and `.deployed` refuse dev flags. Case 2 runs agent processes
in containers, limiting their access to the host.
The install paths do not yet establish the dedicated-uid rule. Case 1's
acceptance script takes `--user` and `--home` from its arguments
(`scripts/case1-accept.sh:102-116`) and checks that the Console and bus units
run as that user (`scripts/case1-accept.sh:457-469`). Case 2's install runs
as a supplied non-root user (`scripts/case2-install.sh:2-3,95-103`); its
unit renderer accepts an existing non-root `--user` without checking that
it is dedicated
(`scripts/case2-unit.sh:136-145`) and writes `User=$USER_NAME`
(`scripts/case2-unit.sh:514`). Neither path checks that this account is
non-login or unused by agent seats. In particular, Case 2 can use a human's
own uid today. This is a deployment gap, not a property of the accounts
checks. M3 follow-up 1 closes it by making both install paths require a
dedicated non-login uid, verify config and data-root ownership, and reject
an uid assigned to an agent seat.
The residual risk is accepted: host root, or the instance uid, owns the
instance. Accounts protect users from one another through the Console and
bus. They do not protect an instance from its host owner.
### Locks
Three locks exist after this design: the per-org lifecycle lock
@@ -1295,6 +1332,7 @@ Rollback keeps OIDC. Nothing in it removes `--sso` or turns sign-in off.
| Identity confusion across providers | Identity is `(provider, sub)` with the issuer from config. Email matches invites only. A subject belongs to one account. |
| Local CLI acting outside the check | In accounts mode `mosaic org` and `decide --org` refuse. `mosaic accounts` runs as the instance uid, which can already read every bus file, and has no rights verbs. |
| Tampering with accounts.json on disk | The file must belong to the instance uid and not be group or other writable. Anyone who can write it already runs as the instance user and can read every bus. That is outside this design, as it is for access.json. |
| Host root or the instance uid bypassing accounts | Accepted residual risk: either can read and change the instance config, data root, bus files and credentials. Phase M limits and records who holds the instance uid; it does not make that uid untrusted. |
Not covered: a compromised identity provider, a stolen session cookie
before its 1 hour idle limit, and a compromised Console process, which holds
@@ -1397,6 +1435,10 @@ Acceptance tests, against a fake OIDC provider on port 0:
- `--dev-local-owner` from a checkout refuses with accounts.json present,
with `console.sso`, and with `.deployed`.
- `webui-service.sh render` and `case2-unit.sh` refuse a dev flag.
- Case 1 and Case 2 install tests reject a login-capable uid or an agent-seat
uid as the instance uid, require it to own the config directory and data
root, and verify that the Console and bus units run as that same dedicated
uid. A designated non-login instance uid passes.
- The existing sso and dev-owner suites stay green.
Grant needed: `stack-copy.sh` writes a new file into every copy, and the