swarm-nats-auth: read its own OIDC client secret from the store
The responder reads its OIDC client secret at `swarm/services/<client-id>/oidc/client` with the store login it already opens for the callout keys, and holds it in memory. `--client-secret-file` is removed. When introspection answers non-2xx, the responder re-reads the secret from the store once and, if it changed, retries the introspection once. Both fit inside the request's 1.5s introspection budget, under the server's 2s callout timeout: the budget is now one deadline for the whole request. A re-read that does not finish by then keeps running in the background, the request is denied, and the next request introspects with what it read. One re-read runs at a time; a refusal while one runs waits on it. In swarm-nats.nix the `swarm-bao-nats-auth-oidc` fetch unit, the flag and the `oidc-client.secret` LoadCredential entry are gone, along with the unit's policy ordering in glue-bao-readers-policy-order.nix. A tmpfiles `r` rule removes the copy a container still holds at /var/lib/nixos-containers/swarm-nats/var/lib/swarm-nats-auth/oidc-client.secret; nothing reads it. No policy change: the `swarm-nats-auth` role already reads this path (`natsAuthReaders` in swarm-bao.nix), which is the role the removed fetch unit logged in as. Deploy order: none, and no operator step. The store's grant already exists, so the queue host can be deployed before, after or without the store's host and authelia's. Rolling back re-creates the fetch unit and the file; the store leaf is untouched.
This commit is contained in:
parent
a66670be87
commit
6646329da5
12 changed files with 557 additions and 253 deletions
|
|
@ -823,7 +823,7 @@ let
|
|||
&& lib.elem "swarm-bao-matrix-ctl-policy.service" u.wants
|
||||
&& !(lib.elem "swarm-bao-matrix-ctl-policy.service" u.requires)
|
||||
&& !(noReaders ? swarm-bao-matrix-oidc)
|
||||
&& !(noReaders ? swarm-bao-nats-auth-oidc);
|
||||
&& !(noReaders ? swarm-bao-nats-callout-xkey);
|
||||
}
|
||||
{
|
||||
# The ordering is set apart from each reader's own definition, so it can
|
||||
|
|
|
|||
|
|
@ -347,8 +347,8 @@ let
|
|||
}
|
||||
{
|
||||
# The responder names no seed file, by flag or by credential, and the
|
||||
# copies a container may still hold are removed. The OIDC secret is the
|
||||
# control that the credential list is read at all.
|
||||
# copies a container may still hold are removed. The store identity is
|
||||
# the control that the credential list is read at all.
|
||||
name = "the responder takes no seed from a file, and the container's seed copies are removed";
|
||||
ok =
|
||||
let
|
||||
|
|
@ -357,7 +357,7 @@ let
|
|||
dir = "/var/lib/nixos-containers/swarm-nats/var/lib/swarm-nats-auth";
|
||||
rules = natsWithStoreIdentity.systemd.tmpfiles.rules;
|
||||
in
|
||||
lib.elem "oidc-client.secret:/var/lib/swarm-nats-auth/oidc-client.secret" creds
|
||||
lib.elem "bao-client.pem:/var/lib/swarm-nats-auth/bao-client.pem" creds
|
||||
&& !(lib.any (lib.hasInfix ".seed") creds)
|
||||
&& !(lib.hasInfix "seed-file" u.serviceConfig.ExecStart)
|
||||
&& lib.elem "r ${dir}/issuer.seed" rules
|
||||
|
|
@ -404,41 +404,31 @@ let
|
|||
&& !(lib.any (path: refused natsWithStoreIdentity path) (lib.attrNames setting));
|
||||
}
|
||||
{
|
||||
# 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";
|
||||
# The responder reads its OIDC secret from the store itself, so no host
|
||||
# unit fetches it, no credential or flag carries it, and a copy a
|
||||
# container still holds is removed. On or off the store's host alike;
|
||||
# the callout key fetch beside it is the control that the unit set is
|
||||
# read at all, and the store cert role the control on the flags.
|
||||
name = "the responder's OIDC secret is fetched by no unit and carried by no credential or flag, and the container's copy is removed";
|
||||
ok =
|
||||
let
|
||||
services = natsWithStoreIdentity.systemd.services;
|
||||
fetch = services.swarm-bao-nats-auth-oidc;
|
||||
copy = services.swarm-nats-auth-secrets.script;
|
||||
fetchedNowhere =
|
||||
h:
|
||||
!(h.systemd.services ? swarm-bao-nats-auth-oidc)
|
||||
&& h.systemd.services ? swarm-bao-nats-callout-xkey;
|
||||
u = responderOf natsWithStoreIdentity;
|
||||
copy = natsWithStoreIdentity.systemd.services.swarm-nats-auth-secrets.script;
|
||||
rules = natsWithStoreIdentity.systemd.tmpfiles.rules;
|
||||
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
|
||||
# An unpublished or empty secret fails the unit, so `storeRetry` retries it.
|
||||
&& !(lib.hasInfix "exit 0" fetch.script)
|
||||
&& lib.elem "container@swarm-nats.service" fetch.before
|
||||
fetchedNowhere natsWithStoreIdentity
|
||||
&& fetchedNowhere natsOnStoreHost
|
||||
&& !(lib.any (lib.hasInfix "oidc-client") u.serviceConfig.LoadCredential)
|
||||
&& !(lib.hasInfix "client-secret" u.serviceConfig.ExecStart)
|
||||
&& lib.hasInfix "--store-cert-role swarm-nats-auth" u.serviceConfig.ExecStart
|
||||
&& lib.elem "r /var/lib/nixos-containers/swarm-nats/var/lib/swarm-nats-auth/oidc-client.secret" rules
|
||||
&& !(lib.hasInfix "oidc-client" copy)
|
||||
&& !(lib.hasInfix "authelia" copy);
|
||||
}
|
||||
{
|
||||
# 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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue