diff --git a/docs/integrations/matrix.md b/docs/integrations/matrix.md index 4706c554..674990a0 100644 --- a/docs/integrations/matrix.md +++ b/docs/integrations/matrix.md @@ -105,8 +105,9 @@ delegation (the latter lives in `gateway.md::Discovery flow`). ## Provisioning flow (appservice) -Registration is closed. **Appservices** create accounts: agents never see -an appservice token, and an agent only ever receives its own `access_token`. +Registration is closed. **The swarm's appservice** creates accounts: agents +never see an appservice token, and an agent only ever receives its own +`access_token`. The appservice has no URL (`url: null` in its registration), so the @@ -116,48 +117,42 @@ no secret has to be equal on both sides of the wire, and why account creation doesn't depend on registration being open to anyone who learns a token. -1. **System activation** mints a 32-byte random hex appservice token (64 - chars) at `/var/lib/hyperhive/matrix-appservice-token` and its - spec-required `hs_token` sibling, mode `0600 root:root`, then renders - the registration to - `/var/lib/hyperhive/matrix-appservice/hyperhive.yaml` (also `0600`). - The script mints the tokens only when missing; the registration is - re-rendered every time, because the token file can be overwritten in - place by the swarm secret store and a registration naming a stale - token authenticates nobody. Runs at activation time, before any - container start, because the directory is bind-mounted and - nixos-container refuses to start when a bind source is missing. -2. **Read-only bind-mount** maps that directory into the tuwunel - container at the same path. -3. **systemd `LoadCredential=`** inside the container copies the - registration into - `/run/credentials/tuwunel.service/hyperhive-appservice.yaml`, owned by - tuwunel's dynamic user with mode `0400`, at service start. The host +1. **`swarm-matrix-ctl appservice render`**, inside the `hive-matrix` + container and before tuwunel starts, mints the registration's + `as_token` and its spec-required `hs_token` when they're missing, and + renders the registration to + `/var/lib/swarm-matrix-appservice/swarm.yaml` (mode `0600 root:root`). +2. **systemd `LoadCredential=`** copies the registration into + `/run/credentials/tuwunel.service/swarm-appservice.yaml`, owned by + tuwunel's dynamic user with mode `0400`, at service start. The source file stays `root:root 0600` — no `chown :tuwunel` / `chmod 0640` / GID-pin gymnastics required. Keeps `DynamicUser = true` + `PrivateUsers = true` intact. -4. tuwunel's `appservice_dir` points at the credentials directory, not at - the bind-mount path. It reads only `.yaml`/`.yml` entries from there, - so the sibling credentials are invisible to it. The `.yaml` suffix on - the credential id is what makes this work. -5. **hive-c0re** doesn't read the appservice token and creates no - account. Its `@hive-:` token comes from the swarm store (below). -6. **Agents' accounts aren't this hive's.** `swarm-controller` creates each - one with the swarm's own appservice token (next section), stores its - token at `swarm/agents//matrix/main`, and the agent's - `hive-matrix-daemon` reads it from there as the agent itself. +3. tuwunel's `appservice_dir` points at the credentials directory. It + reads only `.yaml`/`.yml` entries from there, so the sibling + credentials are invisible to it. The `.yaml` suffix on the credential + id is what makes this work. +4. **hive-c0re** holds no appservice token and creates no account. Its + `@hive-:` token comes from the swarm store (below). +5. **`swarm-controller` creates every account**: each agent's, with its + token stored at `swarm/agents//matrix/main` for the agent's + `hive-matrix-daemon` to read as the agent itself, and each hive's + sender account (below). + +A homeserver whose `swarm-matrix-ctl` has no store identity +(`services.hyperhive.deploy.matrix.ctlBaoClientCertFile`) loads no +registration, and nothing creates accounts on it. ### The swarm's appservice, and its admin sender -A second registration sits beside the hive's: id `swarm`, sender `@swarm`, -the same non-exclusive namespace. It's the swarm's identity on the -homeserver, and `swarm-controller` creates every agent's account with it. -tuwunel loads every `.yaml` in `appservice_dir` and refuses only a -duplicate `id` or `as_token`, so the two overlapping namespaces coexist. +The registration's id is `swarm`, its sender `@swarm`, and its user +namespace non-exclusive. It's the swarm's identity on the homeserver: +`swarm-controller` creates every agent's account and every hive's sender +account with it. `swarm-matrix-ctl appservice render` mints its tokens inside the `hive-matrix` container, before tuwunel starts, and renders the -registration tuwunel loads as a second credential. `appservice publish` +registration tuwunel loads as a credential. `appservice publish` then writes its `as_token` to `swarm/controller/swarm-controller/matrix/appservice-token`. No hive's policy reaches that path: only matrix-ctl (which writes it) and @@ -199,13 +194,12 @@ lands on. `services.hyperhive.deploy.swarm-controller.authBridgeUrl` and `services.hyperhive.deploy.swarm-controller.matrixHomeserverUrl` set. -### The appservice's sender account, and why it isn't an admin +### A hive's sender account, and why it isn't an admin -`@hive-:` is the appservice's own `sender_localpart`, -which the homeserver creates itself when it loads the registration — on a -zero-user database, inside startup, before the HTTP listener accepts -anything. It's an **ordinary account**: nothing promotes it; the -homeserver's `admin_execute` promotes only `@swarm`. +`@hive-:` is the account a hive acts as. +`swarm-controller` creates it with the swarm's appservice token, for every +hive in its directory. It's an **ordinary account**: nothing promotes it; +the homeserver's `admin_execute` promotes only `@swarm`. **One account per hive.** The localpart carries the hive's name, so a swarm whose hives share a homeserver gives each of them its own identity: the @@ -220,8 +214,8 @@ appservice token and publishes it to `swarm/hives//matrix/sender-token`, a reads it from there under its own certificate. That path sits inside the hive's own read grant (`swarm/hives//*`), so a hive fetches its own token and gets a refusal on any other hive's. The name says what it -authenticates as — an account the appservice registration brings into being -— rather than any privilege level, because it carries none. +authenticates as — an account the swarm's appservice creates — rather +than any privilege level, because it carries none. It needs no promotion for what the hive does with it. Creating the hive Space and the chat room, writing their hierarchy and join rules, and @@ -251,8 +245,8 @@ required.
Appservice identity -The activation script mints the appservice token and renders the -registration before the homeserver restarts, so every boot has both +`swarm-matrix-ctl appservice render` mints the appservice tokens and +renders the registration before tuwunel starts, so every boot has both halves. @@ -261,11 +255,10 @@ halves. too. - **The homeserver's `admin_execute` promotes only `@swarm` at boot** (above); a hive's sender account is never promoted. -- **The value that matters lives at `matrix/appservice-token`.** - `swarm-secret-publish` on the authelia host mints and `put`s it - there; the hive uses its locally minted token only until the first - successful read. See [`../swarm/secrets.md`](../swarm/secrets.md) - for how that mint stays idempotent across runs. +- **The value that matters lives at + `swarm/controller/swarm-controller/matrix/appservice-token`.** + `appservice publish` writes the container's copy there whenever the + store's differs, and `swarm-controller` reads it from there.
@@ -277,8 +270,8 @@ Initial rollout settings: restart. `trusted_servers = []` keeps it effectively closed until you list peers. - `allow_registration = false`. tuwunel checks this flag only for - requests that arrive **without** an appservice token, so the appservices - still create accounts and tuwunel refuses everyone else. With no + requests that arrive **without** an appservice token, so the swarm's + appservice still creates accounts and tuwunel refuses everyone else. With no registration token configured, `allow_registration = true` makes tuwunel refuse to start unless `yes_i_am_very_very_sure_…_open_registration_…` is also set. diff --git a/docs/swarm/credentials.md b/docs/swarm/credentials.md index d1a443dc..b448ef03 100644 --- a/docs/swarm/credentials.md +++ b/docs/swarm/credentials.md @@ -66,7 +66,6 @@ of the cell says how. | `swarm/agents//forge-token` | `swarm-controller`, at agent creation and in a pass every 5 minutes over every agent with a store identity | the agent container itself, under its own certificate, fetched to `/run/hive-agent-forge-token/token` | ✅ the controller re-mints when the stored token is missing or no longer matches the forge (last eight characters and scopes) | ✅ the agent re-fetches on a 10-minute timer | | `swarm/agents//forge/