diff --git a/docs/swarm/sso.md b/docs/swarm/sso.md index 4f49ca84..c49a2029 100644 --- a/docs/swarm/sso.md +++ b/docs/swarm/sso.md @@ -3,7 +3,7 @@ The swarm runs one authelia, and it is two things at once: the **session provider** every protected vhost checks (`auth_request`), and — once any client is declared — an **OIDC provider** issuing tokens to relying -parties like the forge. +parties: the forge and the matrix homeserver. The second role is derived rather than switched: `services.hyperhive.swarm.authelia.oidc.clients` being non-empty turns it @@ -116,20 +116,20 @@ mechanism with flags. ### 1. All-local — one host runs both -Nothing to configure beyond `swarm.forge.sso.enable = true`. A host-side -unit waits for authelia's first boot to mint the secret and copies it -into the forge container, and the forge module contributes its own client +Nothing to configure beyond `swarm.forge.sso.enable = true` or +`swarm.matrix.sso.enable = true`. Per service, a host-side unit waits for +authelia's first boot to mint that client's secret and copies it into the +service's container, and the service's own module contributes its client entry — callback URL included — to authelia's client list. -The callback is built from the same source name the registration uses, so -the redirect URI authelia is told to allow and the one forgejo actually -sends cannot drift apart. A mismatch there is a rejected login with no -error text worth reading. +The callback is built once and read twice, so the redirect URI authelia is +told to allow and the one the service actually sends cannot drift apart. A +mismatch there is a rejected login with no error text worth reading. ⚠️ The delivery is a copy, not a `bindMounts` entry, and deliberately so: nixos-container refuses to start a container whose bind source is missing, and this secret does not exist until authelia's first boot has -run. Binding it would make the forge wait on a file that waits on a +run. Binding it would make the service wait on a file that waits on a container that starts after it — on a fresh hive, a permanent stall presenting as "the forge is broken", several layers from its cause. @@ -159,12 +159,38 @@ half-configured shows a login button that always fails — a symptom several layers from its cause, and far worse to diagnose than an evaluation error. +## Where each relying party differs + +The registration half is identical; what each service does with the +result is not. + +| | forge | matrix | +|---|---|---| +| how it learns the config | a oneshot calls `forgejo admin auth`, writing a login-source row into its database | tuwunel reads a `[[global.identity_provider]]` entry from its config file | +| how it reads the secret | a path inside its container | the same path, handed on by `LoadCredential` | +| callback URL | `/user/oauth2//callback` | `/_matrix/client/unstable/login/sso/callback/`, a shape tuwunel fixes rather than accepts | +| cost of a malformed entry | the login source is missing | the homeserver can refuse to start | + +Two consequences worth stating plainly: + +- **tuwunel re-reads its secret file on every OAuth exchange**, not only + at startup, and its own sandboxing hides most paths from it. It gets the + file through `LoadCredential` for the same reason the registration token + does — that keeps `DynamicUser` and `PrivateUsers` intact, with no + host-side ownership arrangement to maintain. +- **Matrix SSO lives inside the homeserver.** The client-server API is + spoken by non-browser clients holding matrix access tokens — every + agent's own daemon — as well as by federation, so `/_matrix/` is served + directly and authenticates itself. The forward-auth vhosts protect + browser surfaces; this is not one of them. + ## What this does not do -- **It does not disable local login.** The forge keeps its password - database and gains a second door. An identity provider that can take - the forge offline when it hiccups is a worse forge than one with two - ways in. +- **It does not disable local login.** Each service keeps its password + database and gains a second door. An identity provider that can take a + service offline when it hiccups is worse than one with two ways in. + Making authelia the only path is a separate, reversible switch per + service (tuwunel's `login_with_password`, forgejo's own setting). - **It does not provision users.** Agents are created and destroyed continuously, so the subject set belongs to a program rather than to a config file; today that program is `swarmctl`.