# Glue: register the secret store's own journal forwarder as an OIDC client # wherever authelia runs. # # ONE PAIRING PER FILE — swarm-bao's forwarder ← authelia, and nothing else. # Deleting this leaves a forwarder authelia has never heard of: the token # endpoint refuses it, nothing is minted, the publisher has nothing to copy # into the store, and the collector's export is a 401 nobody asked for. # # ⚠️ A SECOND client beside ./glue-swarm-otel-oidc-client.nix's, not a reuse # of it. That one is the swarm collector's identity for what IT pushes; this # one belongs to the collector inside the store's container, which is a # different principal on a different host — one identity per principal, the # rule `swarm-controller.nix` states over its own `queueClientId`. # # ⚠️ Gated on authelia being HERE, and deliberately NOT on this host running # the store. A client is a row in THIS host's provider config, so it can only # be declared where that config is rendered, and ./swarm-bao.nix's `config` # hangs off `deploy.bao.enable` — the split ./glue-grafana-oidc-client.nix and # ./glue-swarm-otel-oidc-client.nix each made for the same reason. Read either # file's own comment for the property this one shares with them. { lib, config, ... }: let hyperhiveCfg = config.services.hyperhive; deployCfg = hyperhiveCfg.deploy; baoCfg = hyperhiveCfg.swarm.bao; in { config = lib.mkIf (hyperhiveCfg.enable && deployCfg.authelia.enable) { # One declaration, two readers: `clientId` is a read-only option # ./swarm-bao.nix owns, and ./swarm-otel.nix builds this principal's # authenticator audience from the same option. services.hyperhive.swarm.authelia.oidc.clients = [ { id = baoCfg.otel.clientId; description = "HyperHive secret store journal forwarder"; kind = "machine"; redirectUris = [ ]; # Its own id as its own permitted audience — the self-referential # form `swarm-authelia.nix`'s `hiveClients` uses, which is the shape # to copy here: this forwarder's token lands on an `oidc/*` receiver # of the swarm collector, exactly as a hive's does. audience = [ baoCfg.otel.clientId ]; # ⚠️ What makes the token READABLE by that receiver at all. Authelia's # default is an opaque handle, and an `oidc` extension verifies # offline against `/jwks.json` — so without this the export fails with # a message about the verifier rather than about the token. Same # value, same reason, as every hive's client. accessTokenSignedResponseAlg = "RS256"; } ]; }; }