diff --git a/nix/host-modules/swarm-authelia.nix b/nix/host-modules/swarm-authelia.nix index 753b067f..e8f684ff 100644 --- a/nix/host-modules/swarm-authelia.nix +++ b/nix/host-modules/swarm-authelia.nix @@ -681,6 +681,18 @@ in # would reject it, but three layers away and at boot — naming both # sources here is the cheaper failure. ++ [ + { + # The bridge introspects by name, so a null URL becomes a nix + # coercion error several files from its cause. Only reachable by + # enabling authelia and clearing `url` by hand — an assertion + # rather than a fallback, because a guessed URL that evaluates + # cleanly is worse than a refused build. + assertion = cfg.url != null; + message = + "services.hyperhive.swarm.authelia.url must not be null when authelia " + + "is enabled: swarm-authelia-bridge introspects at " + + "`\${url}/api/oidc/introspection` from inside its container."; + } { assertion = lib.length (lib.unique (map (c: c.id) cfg.oidc.clients)) == lib.length cfg.oidc.clients; message = @@ -922,12 +934,14 @@ in # verifier's — same reasoning as `swarmctl`'s own # `SWARMCTL_AUTHELIA_BIN`. SWARM_AUTHELIA_BRIDGE_AUTHELIA_BIN = "${cfg.package}/bin/authelia"; - # Local loopback, not the public HTTPS vhost: this process - # runs right next to authelia (same container, same netns), - # so there is a faster, simpler path than round-tripping - # through the gateway's nginx for a call nothing external - # ever needs to see. - SWARM_AUTHELIA_BRIDGE_INTROSPECTION_URL = "http://127.0.0.1:${toString cfg.port}/api/oidc/introspection"; + # By name through the gateway, not loopback. A loopback + # literal encodes "authelia is in my netns" at the call site, + # and authelia's OIDC endpoints are https-only in effect — + # reached directly they answer 400, because the forwarded + # headers nginx injects for every other consumer are what let + # it determine its own issuer. Same URL `swarm-nats-auth` + # uses, so there is one idiom rather than two. + SWARM_AUTHELIA_BRIDGE_INTROSPECTION_URL = "${cfg.url}/api/oidc/introspection"; SWARM_AUTHELIA_BRIDGE_CLIENT_ID = bridgeClientId; # Minted by `${unitName}-secrets`'s `mint` loop (it iterates # every entry in `cfg.oidc.clients`, which now always