Watch
0
0
Fork
You've already forked hyperhive
0

swarm: OIDC clients registered wherever authelia runs; nats + matrix secrets from bao

The three client registrations move into glue-{controller,nats,matrix}-oidc-client.nix,
gated only on deploy.authelia.enable and reading their ids from swarm.* options,
so the host running authelia registers every one of them whichever host runs
the service. The matrix callback is a new read-only swarm.matrix.sso.redirectUri,
read by both the homeserver's config and its client entry.

swarm-secret-publish now also publishes the queue's and the homeserver's minted
secrets to swarm/services/<id>/oidc/client. The queue host reads its responder's
secret there with swarm-bao-nats-auth-oidc under the responder's own leaf
(swarm-nats-auth role gains that one read path), and the homeserver's host with
swarm-bao-matrix-oidc under matrix-ctl's leaf (swarm-matrix-ctl role gains its
one read path). The host-file copies are gone: swarm-nats-auth-secrets now
delivers only the callout seeds and the store identity, and
hive-matrix-oidc-secret is removed. A fetch unit whose leaf is unset still
renders and fails naming the option pair.

Closes #4943
This commit is contained in:
atlas 2026-10-05 02:56:18 +02:00 • committed by mara
commit 962da3b784
20 changed files with 702 additions and 293 deletions

View file

@ -178,9 +178,8 @@ let
&& lib.hasPrefix "https://" u.environment.BAO_ADDR;
}
{
# An absent leaf must not stop the responder, which would deny every
# client: it is delivered empty, and the three credentials the responder
# cannot run without are delivered too.
# An absent leaf must not stop the responder's agent-token path: it is
# delivered empty, beside the two seeds.
name = "the copy unit delivers the store identity, and an absent one as an empty file";
ok =
let
@ -189,7 +188,43 @@ let
lib.hasInfix "install -m 0400 /etc/pki/nats-auth.pem " s
&& lib.hasInfix "install -m 0400 /etc/pki/nats-auth-key.pem " s
&& lib.hasInfix "install -m 0400 /dev/null " s
&& lib.hasInfix "oidc-client.secret" s;
&& lib.hasInfix "callout-user.seed" s
&& lib.hasInfix "issuer.seed" s;
}
{
# The responder's OIDC secret has one route, the store, under the
# responder's own leaf. The copy unit's arms are the control: on a queue
# host without authelia nothing reads authelia's tree, and nothing
# copies the secret from any host file.
name = "a queue host without authelia reads the responder's OIDC secret from the store, and copies none from a host file";
ok =
let
services = natsWithStoreIdentity.systemd.services;
fetch = services.swarm-bao-nats-auth-oidc;
copy = services.swarm-nats-auth-secrets.script;
in
!natsWithStoreIdentity.services.hyperhive.deploy.authelia.enable
&& fetch.environment.BAO_CLIENT_CERT == "/etc/pki/nats-auth.pem"
&& fetch.environment.BAO_CLIENT_KEY == "/etc/pki/nats-auth-key.pem"
&& lib.hasInfix "bao kv get -field=value secret/swarm/services/swarm-nats/oidc/client" fetch.script
&& lib.hasInfix "/var/lib/nixos-containers/swarm-nats/var/lib/swarm-nats-auth/oidc-client.secret" fetch.script
&& lib.hasInfix "refresh_consumer swarm-nats swarm-nats-auth.service" fetch.script
&& lib.elem "container@swarm-nats.service" fetch.before
&& !(lib.hasInfix "oidc-client" copy)
&& !(lib.hasInfix "authelia" copy);
}
{
# No responder leaf is a responder with no OIDC secret, which refuses
# every client. The unit still renders, and fails naming the options.
name = "a queue host with no responder leaf renders a secret fetch that fails naming the options";
ok =
let
fetch = natsOldPath.systemd.services.swarm-bao-nats-auth-oidc;
in
!(fetch.environment ? BAO_CLIENT_CERT)
&& lib.hasInfix "deploy.nats.authBaoClientCertFile" fetch.script
&& lib.hasInfix "exit 1" fetch.script
&& !(lib.hasInfix "bao login" fetch.script);
}
{
# The control: no identity, no store wiring, and the responder's
@ -203,6 +238,18 @@ let
&& !(u.environment ? BAO_CLIENT_CERT)
&& lib.length u.serviceConfig.LoadCredential == 3;
}
{
# On the store's host the fetch logs in under the responder's leaf, so it
# waits for the unit writing that role.
name = "on the store's host the responder's OIDC secret fetch uses its leaf and waits for its role";
ok =
let
u = natsOnStoreHost.systemd.services.swarm-bao-nats-auth-oidc;
in
u.environment.BAO_CLIENT_CERT == "/var/lib/swarm-bao-pki/nats-auth.pem"
&& lib.elem "swarm-bao-nats-auth-policy.service" u.after
&& lib.elem "swarm-bao-nats-auth-policy.service" u.wants;
}
{
# On the store's host the glue pairs the responder with a leaf of its
# own, never the queue's TLS-issuing one or the hive's.
@ -220,10 +267,10 @@ let
{
# Not a rename test. `hostClientSecretDir` is `readOnly`, so the fixture
# cannot define it; what can break is a reader left pointing at the
# namespace it moved out of. Five modules read this through an
# namespace it moved out of. Several modules read this through an
# `autheliaCfg` alias, where a path-shaped grep does not see it.
name = "a consumer of authelia's host client-secret dir renders it from the deploy namespace";
ok = lib.hasInfix "/var/lib/nixos-containers/swarm-authelia/var/lib/authelia-swarm/oidc-clients/" autheliaOldPath.systemd.services.swarm-nats-auth-secrets.script;
ok = lib.hasPrefix "/var/lib/nixos-containers/swarm-authelia/var/lib/authelia-swarm/oidc-clients/" autheliaOldPath.services.hyperhive.otel.clientSecretFile;
}
{
# authelia exits at startup on `users: {}`, so an empty database, and a