Watch
0
0
Fork
You've already forked hyperhive
0

swarm-nats: require the responder's store identity, and drop its no-store mode

The responder reads the callout xkey before it connects, so a responder
with no secret store no longer starts, and its "deny every agent token,
serve OIDC" mode could not run. That mode is gone: `agent_token::Store`
is built from the settings the xkey load already read, and `authorize`
takes a source rather than an `Option` of one.

On the nix side, `deploy.nats.authBaoClientCertFile` and
`authBaoClientKeyFile` are now asserted at eval when the queue is
enabled. The units' no-identity branches, the copy unit's empty-file
fallback and its "denies agent tokens" message are removed; an absent
leaf file fails `swarm-nats-auth-secrets` like an absent seed does.
This commit is contained in:
atlas 2026-10-05 22:13:58 +02:00 • committed by mara
commit 52c931c3a7
5 changed files with 193 additions and 248 deletions

View file

@ -82,6 +82,12 @@ let
responderOf = h: h.containers.swarm-nats.config.systemd.services.swarm-nats-auth;
refusedWithoutIdentity =
m:
lib.any (
a: !a.assertion && lib.hasInfix "deploy.nats.authBaoClientCertFile and" a.message
) m.assertions;
# A hive running NOTHING of the swarm's own services — no IdP here, no
# `swarm.authelia.url` set by hand. The whole point of the fixture is what it
# does *not* say: no IdP address is given and none is derived from
@ -91,6 +97,17 @@ let
autheliaColocated = hive { deploy.authelia.enable = true; };
cases = [
{
# The xkey and the responder's OIDC client secret are read only from
# the store, so a queue with no responder leaf cannot start. Refused at
# eval; the controls are a leaf named by hand and the store host's
# minted one.
name = "a queue with no responder store identity is refused at eval, one with a leaf is not";
ok =
refusedWithoutIdentity natsOldPath
&& !(refusedWithoutIdentity natsWithStoreIdentity)
&& !(refusedWithoutIdentity natsOnStoreHost);
}
{
# Reads the RENDERED settings, not the option: `calloutBlocks {…} // {
# … }` is a shallow merge, and a future edit that dropped or shadowed
@ -182,17 +199,6 @@ let
&& !(lib.hasInfix "exit 0" s)
&& u.serviceConfig.Restart == "on-failure";
}
{
name = "a queue host with no responder leaf renders an xkey fetch that fails naming the options";
ok =
let
u = natsOldPath.systemd.services.swarm-bao-nats-callout-xkey;
in
!(u.environment ? BAO_CLIENT_CERT)
&& lib.hasInfix "deploy.nats.authBaoClientCertFile" u.script
&& lib.hasInfix "exit 1" u.script
&& !(lib.hasInfix "ensure-xkey" u.script);
}
{
# Its creates are what the responder's role was granted; on the store's
# host the role's unit has to have run first.
@ -281,16 +287,16 @@ let
&& lib.hasPrefix "https://" u.environment.BAO_ADDR;
}
{
# 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";
# Copied as the seeds are, so an absent leaf fails the unit rather than
# reaching the responder as a file it cannot log in with.
name = "the copy unit delivers the store identity beside the two seeds, and nothing in its place when absent";
ok =
let
s = natsWithStoreIdentity.systemd.services.swarm-nats-auth-secrets.script;
in
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 "/dev/null" s)
&& lib.hasInfix "callout-user.seed" s
&& lib.hasInfix "issuer.seed" s;
}
@ -318,31 +324,6 @@ let
&& !(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
# credentials are exactly the three it cannot run without.
name = "a responder with no store identity is not pointed at a store";
ok =
let
u = responderOf natsOldPath;
in
!(u.environment ? BAO_ADDR)
&& !(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.