diff --git a/docs/gateway.md b/docs/gateway.md index 6bf2df77..e569b0fc 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -14,6 +14,9 @@ Single nginx in front of every hyperhive web surface. Runs on the **host**, next | `matrix./_matrix/*` | `matrix.` | tuwunel (`8008`) | `matrix.gatewayHost != null` | | `matrix./` | `matrix.` | fluffychat-web static | `matrix.gui.enable` | | `matrix./config.json` | `matrix.` | inline JSON (FluffyChat boot config) | `matrix.gui.enable && domain != null` | +| `auth./` | `auth.` | authelia (`9091`) | `swarm.authelia.enable` | + +The authelia vhost is declared only by the host that **runs** authelia, not by every hive that uses it — a client hive knows the swarm's `authelia.url` but must not answer for a name it doesn't serve. Its server name is exactly `swarm.authelia.domain`: authelia validates `authelia_url ⊂ session cookie domain` at startup, so a near-miss is a container that refuses to boot. It carries no `auth_basic` — the login page must not sit behind the login mechanism it replaces — and sets the four `X-Forwarded-{Proto,Host,Uri,For}` headers, since authelia decides by the *original* request rather than the hop it sees. Per-agent UIs stay sub-path because they're hyperhive-internal and base-path-aware. External standard apps (forge / matrix) get sub-domains because their defaults work cleanly at sub-domain root + per-origin cookies / storage isolation matters. @@ -57,6 +60,7 @@ Each location carries a duplicated `auth_basic` block (separate locations don't - `` → `127.0.0.1` - `forge.` → `127.0.0.1` (when forge.behindGateway) - `matrix.` → `127.0.0.1` (when matrix.gatewayHost set) +- `auth.` → `127.0.0.1` (when swarm.authelia.enable) `lib.unique` de-dupes if any sub-domain happens to equal another entry. Operators with real DNS leave it off. diff --git a/docs/network.md b/docs/network.md index 1d2edbd9..f538bf95 100644 --- a/docs/network.md +++ b/docs/network.md @@ -113,7 +113,8 @@ schemes pick their own. ## Resolver behaviour dnsmasq is **authoritative** for the hive's own zones — answers -``, `forge.`, `matrix.` +``, `forge.`, `matrix.` and — +on the host running it — the swarm's `auth.` queries with the bridge IP (where nginx is reachable). Everything else is forwarded to the host's own resolvers: dnsmasq runs on the host and reads the host's `/etc/resolv.conf` directly. Containers don't need diff --git a/docs/swarm/sso.md b/docs/swarm/sso.md index 0c1c5b61..627120c4 100644 --- a/docs/swarm/sso.md +++ b/docs/swarm/sso.md @@ -10,6 +10,38 @@ The second role is derived rather than switched: on. authelia refuses to start with a provider that has no clients, so a separate `enable` would be a second fact free to disagree with the first. +## Getting in the first time + +authelia binds loopback only. The **gateway** on the host running it +publishes it as `auth.` — vhost, dnsmasq record and TLS +name all follow `swarm.authelia.enable`, so there is nothing to turn on +separately. (Details, including why a client hive must not declare that +vhost: [`../gateway.md`](../gateway.md).) + +Reachable is not the same as usable: the provider is generated with an +empty user set, deliberately. A provider with nobody in it yet is the +correct state for a fresh swarm — it is not a half-finished install, and +seeding a default account would be a credential in a config file. + +Add the first subject on the host running authelia: + +```console +# swarmctl user add mara --display-name Mara --email mara@example.com --group admins +added mara to /var/lib/authelia-swarm/users.yml +password: +this password is stored nowhere — record it now +``` + +The password is generated, hashed, and printed once; only the hash is +kept. `swarmctl` writes its canonical `users.json`, re-renders authelia's +`users.yml` from it, and restarts authelia. Full reference: +[`../tools/swarmctl-cli.md`](../tools/swarmctl-cli.md). + +This step stays manual on purpose. Bootstrapping an identity provider +non-interactively means a secret arriving from somewhere — a file, an +env var, a nix expression — and every one of those is worse than an +operator typing one command once. + ## What secrets exist, and where each one lives | secret | generated by | rests in | read by |