Watch
0
0
Fork
You've already forked hyperhive
0

docs: describe the forge's OIDC secret as fetched from bao, not copied or hand-placed

sso.md still described a host-side copy unit and an operator-placed file
for a forge elsewhere; secrets.md's client-secret row still named
sso.clientSecretFile as the operator's route. The clientSecretFile
example now shows the path swarm-bao-forge-oidc writes.

Refs #5015
This commit is contained in:
atlas 2026-10-09 23:47:13 +02:00 • committed by mara
commit 5658361096
3 changed files with 52 additions and 43 deletions

View file

@ -42,12 +42,12 @@ neither is a renaming of the other.
## Swarm-level — one of each per swarm ## Swarm-level — one of each per swarm
| secret | generated by | lives at | hive elsewhere | | secret | generated by | lives at | hive elsewhere |
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| swarm-services root CA (cert + key) | `swarm-bao.nix`'s granting unit, inside the store's `pki` mount | the **key** never leaves the mount; the **cert** lands at `/var/lib/swarm-bao-services-pki/services-root.pem` (0644) and at `/var/lib/hive-tls/swarm-services-root.pem` on every hive | nothing to copy — every hive receives the cert with the leaf it asks the store for, or from `pki/ca/pem` where it fronts no swarm name and needs a store identity | | swarm-services root CA (cert + key) | `swarm-bao.nix`'s granting unit, inside the store's `pki` mount | the **key** never leaves the mount; the **cert** lands at `/var/lib/swarm-bao-services-pki/services-root.pem` (0644) and at `/var/lib/hive-tls/swarm-services-root.pem` on every hive | nothing to copy — every hive receives the cert with the leaf it asks the store for, or from `pki/ca/pem` where it fronts no swarm name and needs a store identity |
| authelia session, JWT and storage-encryption keys | authelia's first-boot unit, in-container | `/var/lib/authelia-swarm/{session,jwt,storage-encryption}.key` | generated in place; nothing outside that container reads them | | authelia session, JWT and storage-encryption keys | authelia's first-boot unit, in-container | `/var/lib/authelia-swarm/{session,jwt,storage-encryption}.key` | generated in place; nothing outside that container reads them |
| authelia OIDC HMAC key | same unit | `/var/lib/authelia-swarm/oidc-hmac.key` | same | | authelia OIDC HMAC key | same unit | `/var/lib/authelia-swarm/oidc-hmac.key` | same |
| authelia OIDC issuer key (RSA) | same unit | `/var/lib/authelia-swarm/oidc-issuer.key` | same — relying parties verify against the **public** half at `/jwks.json` | | authelia OIDC issuer key (RSA) | same unit | `/var/lib/authelia-swarm/oidc-issuer.key` | same — relying parties verify against the **public** half at `/jwks.json` |
| OIDC client secret, plaintext half | `authelia crypto hash generate --random` | `/var/lib/authelia-swarm/oidc-clients/<id>.secret` | operator provides the file and names it in whichever option reads it — `sso.clientSecretFile` for a service | | OIDC client secret, plaintext half | `authelia crypto hash generate --random` | `/var/lib/authelia-swarm/oidc-clients/<id>.secret` | operator provides the file and names it in whichever option reads it — `sso.clientSecretFile` for a service; the forge and, by default, the hive collector need none — `swarm-bao-forge-oidc` and `swarm-bao-hive-otel-oidc` fetch it from the store (below) |
| OIDC client secret, digest half | the same mint | `oidc-clients/<id>.digest` | authelia's own half; merged at runtime via `settingsFiles` | | OIDC client secret, digest half | the same mint | `oidc-clients/<id>.digest` | authelia's own half; merged at runtime via `settingsFiles` |
| the swarm collector's copy of its OIDC secret | `swarm-bao-otel-oidc.service` reads it out of the swarm secret store, **on every host that runs the collector and holds a store identity** | `/var/lib/swarm-otel-oidc/<id>.secret` inside the `swarm-otel` container | same unit, same path — one route, co-located or not. A collector with no store identity has `clientSecretFile == null`, its already-supported unauthenticated-push degrade — see below | | the swarm collector's copy of its OIDC secret | `swarm-bao-otel-oidc.service` reads it out of the swarm secret store, **on every host that runs the collector and holds a store identity** | `/var/lib/swarm-otel-oidc/<id>.secret` inside the `swarm-otel` container | same unit, same path — one route, co-located or not. A collector with no store identity has `clientSecretFile == null`, its already-supported unauthenticated-push degrade — see below |
| Grafana's copy of its OIDC secret | `swarm-bao-grafana-oidc.service` reads it out of the swarm secret store, **on every host that runs Grafana** | `/var/lib/grafana-oidc/<id>.secret` inside the `swarm-grafana` container | same unit, same path — one route, co-located or not. Nothing for an operator to place beyond this host's store leaf, see below | | Grafana's copy of its OIDC secret | `swarm-bao-grafana-oidc.service` reads it out of the swarm secret store, **on every host that runs Grafana** | `/var/lib/grafana-oidc/<id>.secret` inside the `swarm-grafana` container | same unit, same path — one route, co-located or not. Nothing for an operator to place beyond this host's store leaf, see below |

View file

@ -121,10 +121,17 @@ mechanism with flags.
### 1. All-local — one host runs both ### 1. All-local — one host runs both
Nothing to configure at all. Per service, a host-side unit waits for Nothing to configure at all. authelia mints each client's secret at its
authelia's first boot to mint that client's secret and copies it into the first boot, and `swarm-secret-publish` on its host writes it to the swarm
service's container, and the service's own module contributes its client secret store at `swarm/services/<client id>/oidc/client`. A host-side unit
entry — callback URL included — to authelia's client list. then reads it from the store and writes it into the service's container:
`swarm-bao-forge-oidc` for the forge, under the forge publisher's store
leaf, into `/var/lib/forgejo-oidc/<client id>.secret` (the file
`forgejo-sso-source` reads); `swarm-bao-matrix-oidc` for matrix, under
matrix-ctl's. A unit that can't read the secret yet fails and retries
every 30 seconds for a day, so there is no start order to get right. The
service's own module contributes its client entry — callback URL
included — to authelia's client list.
Each relying service's own glue module builds its callback once, and Each relying service's own glue module builds its callback once, and
both authelia's client list and the service's own OIDC client config both authelia's client list and the service's own OIDC client config
@ -134,12 +141,10 @@ rejected login with no error text worth reading.
<!-- vale write-good.Passive = NO --> <!-- vale write-good.Passive = NO -->
⚠️ The delivery is a copy, not a `bindMounts` entry, and deliberately so: ⚠️ The secret is written into the container's state directory, not bound
nixos-container refuses to start a container whose bind source is in with `bindMounts`: nixos-container refuses to start a container whose
missing, and this secret doesn't exist until authelia's first boot has bind source is missing, and this secret doesn't exist until authelia's
run. Binding it would make the service wait on a file that waits on a first boot has run and the publisher has written it.
container that starts after it — on a fresh hive, a permanent stall
presenting as "the forge is broken," many layers from its cause.
<!-- vale write-good.Passive = YES --> <!-- vale write-good.Passive = YES -->
@ -151,23 +156,27 @@ written in place).
### 3. A hive elsewhere ### 3. A hive elsewhere
No shared host, so no automatic path. The operator provides the file and The forge's host needn't be the store's or authelia's host, and the
names it: operator places no secret file: `swarm-bao-forge-oidc` runs on the
forge's host as in the all-local case and fetches the secret over the
store's address. What that host needs is the forge publisher's store
leaf, issued from the store's CA and copied over from the store's host:
```nix ```nix
services.hyperhive.swarm = { services.hyperhive = {
authelia.url = "https://auth.example.com"; swarm.authelia.url = "https://auth.example.com";
forge.sso = { deploy.bao = {
enable = true; forgePublisherClientCertFile = "/var/lib/swarm-bao-pki/forge-publisher.pem";
clientSecretFile = "/var/lib/hyperhive/forge-oidc-secret"; forgePublisherClientKeyFile = "/var/lib/swarm-bao-pki/forge-publisher-key.pem";
}; };
}; };
``` ```
**This module asserts both at eval.** A hive that boots with SSO **A forge host without that leaf still evaluates.** `swarm-bao-forge-oidc`
half-configured shows a login button that always fails — a symptom renders and fails at start, naming both options, and the forge has no
many layers from its cause, and far worse to diagnose than an login source until an operator places the leaf. Where the store runs on
evaluation error. the same host, `glue-bao-tls.nix` defaults both options to the leaf it
mints.
## Where each relying party differs ## Where each relying party differs

View file

@ -245,7 +245,7 @@ in
sso.clientSecretFile = lib.mkOption { sso.clientSecretFile = lib.mkOption {
type = lib.types.nullOr lib.types.str; type = lib.types.nullOr lib.types.str;
default = null; default = null;
example = "/var/lib/hyperhive/forge-oidc-secret"; example = "/var/lib/forgejo-oidc/forgejo.secret";
description = '' description = ''
Path **inside the forge container** holding the client Path **inside the forge container** holding the client
secret's plaintext. secret's plaintext.