# Glue: register the swarm queue as an OIDC client wherever authelia runs. # # ONE PAIRING PER FILE — swarm-nats ← authelia, and nothing else. Deleting this # leaves a queue responder whose introspection calls authelia refuses, so it # denies every client, and no minted secret for swarm-secret-publish to put in # the store. # # ⚠️ Gated on authelia being HERE, and NOT on this host running the queue. A # client is a row in THIS host's provider config, so it is declared where that # config is rendered; ./swarm-nats.nix's `config` hangs off # `deploy.nats.enable`, which answers a question about a different host. Same # shape as ./glue-grafana-oidc-client.nix. # # Registered whether or not the swarm runs a queue: nothing in `swarm.*` records # that, so the cost of a swarm without one is one unused client and one unused # minted secret. { lib, config, ... }: let hyperhiveCfg = config.services.hyperhive; deployCfg = hyperhiveCfg.deploy; natsCfg = hyperhiveCfg.swarm.nats; in { config = lib.mkIf deployCfg.authelia.enable { services.hyperhive.swarm.authelia.oidc.clients = [ { id = natsCfg.clientId; description = "HyperHive swarm queue"; # `client_credentials`: a queue's clients are daemons with nobody to # redirect, and no redirect URI exists. # # ⚠️ `kind` says that, and an empty `redirectUris` does NOT: authelia # permits only the grants a client names, and an omitted `grant_types` # means authorization-code alone. Introspection, which is all the # responder calls, works either way, so the token endpoint's # `unauthorized_client` is the only place a wrong kind shows. kind = "machine"; # The queue container's journal forwarder mints its token as this # client, for the swarm collector's `oidc/swarm-nats` receiver, which # accepts this audience alone (`serviceProducers` in # ./swarm-otel-service.nix). audience = [ natsCfg.clientId ]; # That receiver verifies the token offline against `/jwks.json`; # authelia's default opaque handle fails there. accessTokenSignedResponseAlg = "RS256"; } ]; }; }