Compare commits

..

View file

@ -79,14 +79,6 @@ let
# per service from it. Were the queue to declare this list, the next
# consumer would collide on the same client id — and only at the
# moment it landed.
#
# Fed to the option as a DEFINITION in the config block below, rather
# than appended to the declared list downstream. That is what puts it
# through the submodule: one list, one type, every option's default
# present. Appending a raw attrset instead left the list half-typed —
# and a field later added to the submodule then existed on the
# declared entries and not on these, which is an eval error reachable
# only once hive identities are on.
hiveClients = lib.mapAttrsToList (name: _: {
id = "hive-${name}";
description = "HyperHive hive ${name}";
@ -94,18 +86,21 @@ let
redirectUris = [ ];
}) hyperhiveCfg.swarm.hives;
# Everything downstream renders and mints from this, not from the
# declared list alone.
allClients = cfg.oidc.clients ++ lib.optionals cfg.oidc.hiveIdentities hiveClients;
# authelia refuses to start with an OIDC provider that has no clients,
# so the provider is derived from the client list rather than carrying
# its own `enable`: one fact, and it cannot contradict itself. An empty
# list is the default, which makes every hive that has not opted in
# byte-identical to before.
#
# ⚠️ The derived hive identities are definitions of this same option,
# so they can turn the provider on by themselves. That is only
# reachable where the queue is already enabled (`hiveIdentities`
# defaults to it) — and a queue-enabled hive already contributes a
# client, so no existing deployment flips.
oidcEnabled = cfg.oidc.clients != [ ];
# ⚠️ Derived from `allClients`, so hive identities can turn the provider
# on by themselves. That is only reachable where the queue is already
# enabled (`hiveIdentities` defaults to it) — and a queue-enabled hive
# already contributes a client, so no existing deployment flips.
oidcEnabled = allClients != [ ];
# Secrets that are 64 random bytes of hex and nothing more. The OIDC
# hmac key joins them; the issuer key does not (see below — it is RSA).
@ -149,11 +144,6 @@ let
printf -- " client_secret: '%s'\n" "$(cat ${lib.escapeShellArg "${clientsDir}/${c.id}.digest"})"
printf -- ' authorization_policy: one_factor\n'
''
# Read plainly, and that is a property of the list rather than of
# this line: every entry reaching here is a definition of
# `oidc.clients`, so the module system has applied the submodule and
# each option's default is present. A derived entry that names only
# the fields it cares about still arrives with the rest filled in.
+ lib.optionalString (c.tokenEndpointAuthMethod != null) ''
printf -- ' token_endpoint_auth_method: %s\n' ${lib.escapeShellArg c.tokenEndpointAuthMethod}
''
@ -229,7 +219,7 @@ let
${lib.concatMapStrings (c: ''
mint ${lib.escapeShellArg c.id}
'') cfg.oidc.clients}
'') allClients}
# Re-rendered every boot, deliberately: the secret is minted once,
# but the metadata around it (a new redirect URI, a renamed client)
@ -240,7 +230,7 @@ let
printf -- 'identity_providers:\n'
printf -- ' oidc:\n'
printf -- ' clients:\n'
${lib.concatMapStrings renderClient cfg.oidc.clients}
${lib.concatMapStrings renderClient allClients}
} > ${lib.escapeShellArg "${clientsFile}.tmp"}
chmod 0600 ${lib.escapeShellArg "${clientsFile}.tmp"}
mv ${lib.escapeShellArg "${clientsFile}.tmp"} ${lib.escapeShellArg clientsFile}
@ -548,14 +538,6 @@ in
};
config = lib.mkIf (hyperhiveCfg.enable && cfg.enable) {
# The derived half of the client list, declared the same way an
# operator declares one. Everything downstream then reads a single
# uniformly-typed `cfg.oidc.clients` and cannot tell the two apart —
# including the assertions below, which is why a hive named `x`
# colliding with a declared `hive-x` is caught rather than rendered
# twice.
services.hyperhive.swarm.authelia.oidc.clients = lib.mkIf cfg.oidc.hiveIdentities hiveClients;
# A redirect URI on a machine client is not harmless-but-unused: it
# means whoever wrote it believes a browser is involved. Failing here
# is how that belief gets corrected at the point it was expressed,
@ -568,7 +550,7 @@ in
+ "kind = \"machine\" but declares redirectUris. A client_credentials "
+ "client has nobody to redirect; drop the URIs or make it "
+ "kind = \"interactive\".";
}) cfg.oidc.clients
}) allClients
# Two clients sharing an id renders two YAML entries under one name.
# Newly reachable now that part of the list is DERIVED: a hive called
# `x` and a service client called `hive-x` never met before. Authelia
@ -576,14 +558,12 @@ in
# sources here is the cheaper failure.
++ [
{
assertion = lib.length (lib.unique (map (c: c.id) cfg.oidc.clients)) == lib.length cfg.oidc.clients;
assertion = lib.length (lib.unique (map (c: c.id) allClients)) == lib.length allClients;
message =
"services.hyperhive.swarm.authelia: duplicate OIDC client id(s): "
+ lib.concatStringsSep ", " (
lib.unique (
lib.filter (id: lib.count (x: x == id) (map (c: c.id) cfg.oidc.clients) > 1) (
map (c: c.id) cfg.oidc.clients
)
lib.filter (id: lib.count (x: x == id) (map (c: c.id) allClients) > 1) (map (c: c.id) allClients)
)
)
+ ". Hive identities are named `hive-<name>` from "