swarm-controller: read the queue client secret from the store, drop the file
Some checks were skipped
public bin cache / build + push to preem:grid (push) Has been skipped
Some checks were skipped
public bin cache / build + push to preem:grid (push) Has been skipped
The controller's OIDC client secret (client `swarm-controller`, used for the queue connection, the auth-bridge bearer and the OTLP push) came from an operator-placed file, `deploy.swarm-controller.queue.clientSecretFile`, handed in by `LoadCredential=`. Now `swarm-secret-publish`, which already copies authelia's minted OIDC secrets into the store, also publishes this one, to `swarm/controller/swarm-controller/oidc/client`. That path sits under `controller/`, which no hive's policy reads. The controller reads it once at start with its existing store certificate and holds it in memory, as `swarm_queue_client::ClientSecret::Value`. If the store is down, it retries for about a minute and then fails the start, so `Restart=` tries again. Policy delta: the controller gets `read` on that leaf, and the publisher gets `create`/`update` on that leaf. Removed: the `queue.clientSecretFile` option (both spellings, now removed options with a message), its singleHostSwarm default, the credential and placeholder, and the path watcher plus its restart oneshot. A controller without a store identity is now an eval error, because it has no other way to get the secret.
This commit is contained in:
parent
97c4771514
commit
e94406cdb9
22 changed files with 595 additions and 247 deletions
|
|
@ -1,7 +1,7 @@
|
|||
# The unit that puts swarm-level secrets into the swarm's secret store, so
|
||||
# whoever needs one can read it there: a hive its agents' credential, a swarm
|
||||
# service its own, a hive its matrix appservice token. The OIDC secrets it only
|
||||
# copies; the appservice token it MINTS, having had no swarm-side producer.
|
||||
# whoever needs one can read it there: a hive its agents' credential, a
|
||||
# service or the controller its own, a hive its appservice token. OIDC secrets
|
||||
# it only copies; the appservice token it MINTS, having no swarm-side producer.
|
||||
#
|
||||
# ⚠️ "Whoever", including a reader on THIS host. A swarm service's secret goes
|
||||
# into the store even when the service runs beside authelia, because its
|
||||
|
|
@ -80,6 +80,11 @@ let
|
|||
hyperhiveCfg.swarm.bao.otel.clientId
|
||||
];
|
||||
|
||||
# The swarm controller's OIDC client, which it reads back from the store
|
||||
# under its own certificate.
|
||||
controllerClientId = hyperhiveCfg.swarm.controller.queueClientId;
|
||||
controllerSecretPath = "secret/swarm/controller/swarm-controller/oidc/client";
|
||||
|
||||
# Where this unit keeps the appservice tokens it minted, and the whole reason
|
||||
# a re-publish is idempotent. The store cannot be that record: ./swarm-bao.nix
|
||||
# grants this principal `create`/`update` and deliberately no `read`, so "does
|
||||
|
|
@ -104,8 +109,8 @@ in
|
|||
description = ''
|
||||
Publish the OIDC client secrets this host mints into the swarm's
|
||||
secret store, so a hive that does not run authelia can read its
|
||||
agents' credential and a swarm service can read its own — from
|
||||
wherever it runs, this host included. Also mints each hive's matrix
|
||||
agents' credential and a swarm service or the controller can read its
|
||||
own — from wherever it runs, this host included. Also mints each hive's matrix
|
||||
appservice token, which has no other swarm-side producer, and
|
||||
publishes it the same way.
|
||||
|
||||
|
|
@ -120,10 +125,10 @@ in
|
|||
identity's job (see `baoClientCertFile`), not this option's.
|
||||
|
||||
Turning it off leaves every hive but this one without its agents'
|
||||
credential, the swarm's Grafana without any login at all, its
|
||||
collector pushing unauthenticated, and every hive falling back to the
|
||||
appservice token its own first boot minted — so two hives never agree
|
||||
on one. Each secret has exactly one route and this is the producer's
|
||||
credential, the swarm controller unable to start, the swarm's Grafana
|
||||
without any login at all, its collector pushing unauthenticated, and
|
||||
every hive falling back to the appservice token its own first boot
|
||||
minted — so two hives never agree on one. Each secret has exactly one route and this is the producer's
|
||||
end of it, so the honest reason to set it false is a deployment
|
||||
delivering those secrets by some other mechanism it owns.
|
||||
'';
|
||||
|
|
@ -261,6 +266,22 @@ in
|
|||
fi
|
||||
'') serviceClientIds}
|
||||
|
||||
# The controller's own client, under `controller/` rather than
|
||||
# `services/`: every hive reads `services/*`, and this client may read
|
||||
# every hive's status. The nix half of
|
||||
# `swarm_secret_client::queue::controller_client_path`.
|
||||
src=${lib.escapeShellArg "${deployCfg.authelia.hostClientSecretDir}/${controllerClientId}.secret"}
|
||||
if [ -s "$src" ]; then
|
||||
bao kv put ${lib.escapeShellArg controllerSecretPath} \
|
||||
value=@"$src"
|
||||
published=$((published + 1))
|
||||
else
|
||||
# Authelia mints it only where the controller registers its client,
|
||||
# which is where the controller runs beside it.
|
||||
echo "no minted secret at $src yet; the path unit will re-run this" >&2
|
||||
skipped=$((skipped + 1))
|
||||
fi
|
||||
|
||||
# The matrix appservice token, per hive. Unlike the two loops above
|
||||
# there is nothing to copy: authelia never minted this one, and each
|
||||
# homeserver's own host minted its own — which is exactly why two hives
|
||||
|
|
|
|||
Loading…
Reference in a new issue