Watch
0
0
Fork
You've already forked hyperhive
0

name the mint, not the publisher, as the writer of the client secrets

Finishes the sweep of prose that said the publisher unit writes or carries the OIDC client secrets: rust docs, nix comments and option descriptions, test names and docs.
This commit is contained in:
atlas 2026-10-30 04:32:22 +01:00 • committed by mara
commit 2fc63d844b
24 changed files with 52 additions and 52 deletions

View file

@ -152,7 +152,7 @@ the label isn't taken from the payload at all.
**Nothing to set where the hive holds its store identity.** The hive's collector **Nothing to set where the hive holds its store identity.** The hive's collector
reads its secret from the swarm's secret store under the hive's own leaf reads its secret from the swarm's secret store under the hive's own leaf
(`deploy.bao.clientCertFile`): `swarm-bao-hive-otel-oidc.service` fetches (`deploy.bao.clientCertFile`): `swarm-bao-hive-otel-oidc.service` fetches
`swarm/hives/<hive>/oidc/client`, which the publisher in authelia's container `swarm/hives/<hive>/oidc/client`, which authelia's mint, in its container,
writes, into `/run/hive-otel-oidc/` (tmpfs, so never on persistent disk). It writes, into `/run/hive-otel-oidc/` (tmpfs, so never on persistent disk). It
runs at boot and retries every 30s until the store answers; until then the runs at boot and retries every 30s until the store answers; until then the
collector runs on an empty file and the swarm refuses its exports. When a collector runs on an empty file and the swarm refuses its exports. When a

View file

@ -204,7 +204,7 @@ in
# The secret publisher's, minted here for the reason the controller's # The secret publisher's, minted here for the reason the controller's
# line above gives — and it serves that case more often, not less: the # line above gives — and it serves that case more often, not less: the
# publisher runs in AUTHELIA's container, on the one host # publisher's unit runs in AUTHELIA's container, on the one host
# guaranteed not to be this one once the store has a host of its own. # guaranteed not to be this one once the store has a host of its own.
[ -s ${pkiDir}/secret-publisher.pem ] || ${signLeaf} ${pkiDir} secret-publisher \ [ -s ${pkiDir}/secret-publisher.pem ] || ${signLeaf} ${pkiDir} secret-publisher \
${lib.escapeShellArg deployCfg.bao.secretPublisherCommonName} "" clientAuth ${lib.escapeShellArg deployCfg.bao.secretPublisherCommonName} "" clientAuth

View file

@ -6,7 +6,7 @@
# #
# ⚠️ The minting is NOT here. ./glue-bao-tls.nix holds the CA and signs the # ⚠️ The minting is NOT here. ./glue-bao-tls.nix holds the CA and signs the
# leaf, because the thing that owns a private key owns issuing from it. What # leaf, because the thing that owns a private key owns issuing from it. What
# belongs here is the pairing: which host paths go to the publisher in # belongs here is the pairing: which host paths go to the publisher's identity in
# authelia's container. # authelia's container.
# #
# ⚠️ Gated on a PKI directory existing, not on the store alone — the same rule # ⚠️ Gated on a PKI directory existing, not on the store alone — the same rule

View file

@ -1201,8 +1201,8 @@ in
# The forge's OIDC client secret, out of the swarm secret store under the # The forge's OIDC client secret, out of the swarm secret store under the
# forge publisher's leaf — the one route, wherever authelia runs. Same # forge publisher's leaf — the one route, wherever authelia runs. Same
# shape as ../hive-matrix.nix's `swarm-bao-matrix-oidc`: the login and the # shape as ../hive-matrix.nix's `swarm-bao-matrix-oidc`: the login and the
# read both fail loudly, and `storeRetry` retries until the publisher in # read both fail loudly, and `storeRetry` retries until authelia's mint,
# authelia's container has written the secret. # in its container, has stored the secret.
# #
# On the host, which reads that leaf from its own files. A host with no # On the host, which reads that leaf from its own files. A host with no
# publisher leaf fails here, naming the options, rather than rendering no # publisher leaf fails here, naming the options, rather than rendering no

View file

@ -1064,8 +1064,7 @@ in
# #
# `Restart=on-failure` covers a sealed store or one still starting; # `Restart=on-failure` covers a sealed store or one still starting;
# the timer below repeats the run, which a unit without `RemainAfterExit` allows. # the timer below repeats the run, which a unit without `RemainAfterExit` allows.
# The start timeout is bounded for the reason # The start timeout is bounded because a sealed store answers on the
# ./swarm-secret-publisher.nix states: a sealed store answers on the
# port and never answers the read. # port and never answers the read.
systemd.services.swarm-matrix-appservice-sync = lib.mkIf ctlActive { systemd.services.swarm-matrix-appservice-sync = lib.mkIf ctlActive {
description = "keep the swarm's appservice registration in step with the swarm secret store"; description = "keep the swarm's appservice registration in step with the swarm secret store";

View file

@ -786,8 +786,8 @@ in
# This hive's OIDC client secret, out of the swarm secret store under the # This hive's OIDC client secret, out of the swarm secret store under the
# hive's own leaf. Same shape as ./hive-matrix.nix's # hive's own leaf. Same shape as ./hive-matrix.nix's
# `swarm-bao-matrix-oidc`: the login and the read both fail loudly, and # `swarm-bao-matrix-oidc`: the login and the read both fail loudly, and
# `storeRetry` retries until the publisher in authelia's container has # `storeRetry` retries until authelia's mint, in its container, has
# written the secret, because the collector does not start without it. # stored the secret, because the collector does not start without it.
# #
# The collector re-reads `client_secret_file` on every token fetch, but # The collector re-reads `client_secret_file` on every token fetch, but
# the file it reads is `LoadCredential`'s copy, made at start: a changed # the file it reads is `LoadCredential`'s copy, made at start: a changed

View file

@ -212,7 +212,7 @@ let
# no other collector shares it. The module requires a value. # no other collector shares it. The module requires a value.
forwarderTelemetryPort = 8901; forwarderTelemetryPort = 8901;
# A client this container registers and mints for itself. Its secret goes # A client this container registers and mints for itself. Its secret goes
# through the store like every other forwarder's: the publisher carries it # through the store like every other forwarder's: the mint creates it
# there and the forwarder reads it back under the same identity. # there and the forwarder reads it back under the same identity.
forwarderClient = { forwarderClient = {
id = forwarderClientId; id = forwarderClientId;
@ -227,8 +227,8 @@ let
accessTokenSignedResponseAlg = "RS256"; accessTokenSignedResponseAlg = "RS256";
}; };
# The secret publisher runs in this container, beside the mint whose secrets # The mint runs in this container and creates its secrets in the store. It
# it copies. It needs a store identity, and a reader is defined by holding a # needs a store identity, and a reader is defined by holding a
# certificate the store accepts, never by standing next to it — the rule # certificate the store accepts, never by standing next to it — the rule
# ./swarm-bao.nix's `deploy.bao` options block states in full. # ./swarm-bao.nix's `deploy.bao` options block states in full.
# `deploy.bao.enable` here would be the co-location assumption itself. # `deploy.bao.enable` here would be the co-location assumption itself.

View file

@ -539,8 +539,8 @@ let
} }
''; '';
# The identity that copies authelia's minted OIDC client secrets into the # The identity authelia's mint creates its OIDC client secrets in the store
# store. Named outside `hive-*` for the same reason as the controller's: the # with. Named outside `hive-*` for the same reason as the controller's: the
# controller may create policies under that prefix, and a policy it can # controller may create policies under that prefix, and a policy it can
# rewrite is not a constraint on anything. # rewrite is not a constraint on anything.
secretPublisherPolicyName = "swarm-secret-publisher"; secretPublisherPolicyName = "swarm-secret-publisher";
@ -685,7 +685,7 @@ let
swarmAppserviceRegistrationLeaf = "swarm/controller/swarm-controller/matrix/appservice-registration"; swarmAppserviceRegistrationLeaf = "swarm/controller/swarm-controller/matrix/appservice-registration";
# The controller's own OIDC client secret, the nix half of # The controller's own OIDC client secret, the nix half of
# `swarm_secret_client::queue::controller_client_path`. The publisher writes # `swarm_secret_client::queue::controller_client_path`. Authelia's mint writes
# it; the controller reads it and holds no other copy. # it; the controller reads it and holds no other copy.
controllerClientLeaf = "swarm/controller/swarm-controller/oidc/client"; controllerClientLeaf = "swarm/controller/swarm-controller/oidc/client";
@ -771,7 +771,7 @@ let
# and read like the API key above. # and read like the API key above.
classifierAcpKeyLeaf = "swarm/services/review-classifier/acp-provider"; classifierAcpKeyLeaf = "swarm/services/review-classifier/acp-provider";
# The UI's OIDC client secret. The publisher writes it; the granter reads it # The UI's OIDC client secret. Authelia's mint writes it; the granter reads it
# into the `oidc` auth method's config, which is the only copy bao uses. # into the `oidc` auth method's config, which is the only copy bao uses.
baoUiClientLeaf = "swarm/services/${cfg.ui.oidc.clientId}/oidc/client"; baoUiClientLeaf = "swarm/services/${cfg.ui.oidc.clientId}/oidc/client";
@ -1672,7 +1672,7 @@ let
# own and lands it in a collector's container — because that route is # own and lands it in a collector's container — because that route is
# proven and there is no second one worth inventing. # proven and there is no second one worth inventing.
# #
# Where the publisher in authelia's container leaves it. A swarm service's # Where authelia's mint, in its container, stores it. A swarm service's
# client is registered once for the whole swarm, so its secret is one value. # client is registered once for the whole swarm, so its secret is one value.
# The `swarm-forwarder-oidc` role's grant is this one path, so any other # The `swarm-forwarder-oidc` role's grant is this one path, so any other
# answers 403 however correct it looks. # answers 403 however correct it looks.
@ -1983,8 +1983,8 @@ in
example = "swarm-secret-publisher.svc"; example = "swarm-secret-publisher.svc";
description = '' description = ''
Subject the store's secret-publisher cert-auth role accepts — the Subject the store's secret-publisher cert-auth role accepts — the
identity that copies authelia's minted OIDC client secrets into the identity authelia's mint creates its OIDC client secrets in the
store so a hive that does not host authelia can read its own. store with, so a hive that does not host authelia can read its own.
A **second** identity rather than reuse of A **second** identity rather than reuse of
{option}`services.hyperhive.deploy.bao.controllerCommonName`: the {option}`services.hyperhive.deploy.bao.controllerCommonName`: the

View file

@ -105,8 +105,8 @@ in
description = '' description = ''
The OAuth2 client id the swarm builder presents to the swarm queue. The OAuth2 client id the swarm builder presents to the swarm queue.
Read-only: the host running authelia registers it, the queue's Read-only: the host running authelia registers it, the queue's
auth-callout responder grants it the build subject, and the secret auth-callout responder grants it the build subject, and
publisher carries its secret to the store, all from this one value. authelia's mint stores its secret in the store, all from this one value.
''; '';
}; };

View file

@ -96,8 +96,8 @@ in
description = '' description = ''
The OAuth2 client id the claude login minter presents to the swarm The OAuth2 client id the claude login minter presents to the swarm
queue. Read-only: the host running authelia registers it, the queue's queue. Read-only: the host running authelia registers it, the queue's
auth-callout responder grants it the login subject, and the secret auth-callout responder grants it the login subject, and
publisher carries its secret to the store, all from this one value. authelia's mint stores its secret in the store, all from this one value.
''; '';
}; };

View file

@ -351,7 +351,7 @@ let
"/var/lib/grafana-metrics/bearer" "/var/lib/grafana-metrics/bearer"
]; ];
# Where the publisher in authelia's container leaves this client's secret. A # Where authelia's mint, in its container, stores this client's secret. A
# swarm service's client is registered once for the whole swarm, so its # swarm service's client is registered once for the whole swarm, so its
# secret is one value and not one per hive. Both ends compose this from the # secret is one value and not one per hive. Both ends compose this from the
# same swarm-wide client id, so a rename cannot leave one of them behind. # same swarm-wide client id, so a rename cannot leave one of them behind.
@ -719,8 +719,8 @@ in
++ map (p: "r ${p}") legacyHostSecretPaths; ++ map (p: "r ${p}") legacyHostSecretPaths;
# THE delivery unit — one route, in every deployment. The secret authelia # THE delivery unit — one route, in every deployment. The secret authelia
# minted arrives out of the swarm secret store, which the publisher in # minted arrives out of the swarm secret store, which authelia's mint,
# authelia's container wrote it into, and that is true whether authelia is # in its container, wrote it into, and that is true whether authelia is
# a network away or in the container next door. # a network away or in the container next door.
# #
# 🩸 No second unit copies the plaintext out of authelia's tree # 🩸 No second unit copies the plaintext out of authelia's tree
@ -737,7 +737,7 @@ in
# there" into a value. # there" into a value.
# #
# ⚠️ An ABSENT secret is "not published yet", not a fault of this host's. # ⚠️ An ABSENT secret is "not published yet", not a fault of this host's.
# The publisher runs in authelia's container and authelia mints on its # The mint runs in authelia's container and authelia mints on its
# first boot, so early in a swarm's life there is legitimately nothing to # first boot, so early in a swarm's life there is legitimately nothing to
# read. # read.
# Nothing here writes a stand-in: there is no such thing as a locally valid # Nothing here writes a stand-in: there is no such thing as a locally valid

View file

@ -85,8 +85,8 @@ in
description = '' description = ''
The OAuth2 client id the notification router presents to the swarm The OAuth2 client id the notification router presents to the swarm
queue. Read-only: the host running authelia registers it, the queue's queue. Read-only: the host running authelia registers it, the queue's
auth-callout responder grants it the router's subjects, and the secret auth-callout responder grants it the router's subjects, and
publisher carries its secret to the store, all from this one value. authelia's mint stores its secret in the store, all from this one value.
''; '';
}; };

View file

@ -261,7 +261,7 @@ let
# regression rather than a choice anyone made. # regression rather than a choice anyone made.
hiveReaderIdentity = baoDeploy.clientCertFile != null && baoDeploy.clientKeyFile != null; hiveReaderIdentity = baoDeploy.clientCertFile != null && baoDeploy.clientKeyFile != null;
# Where the publisher in authelia's container leaves this client's secret — # Where authelia's mint, in its container, stores this client's secret —
# composed from the same swarm-wide `clientId` the registration in # composed from the same swarm-wide `clientId` the registration in
# ./glue-swarm-otel-oidc-client.nix uses, so a rename cannot leave one of # ./glue-swarm-otel-oidc-client.nix uses, so a rename cannot leave one of
# them behind. The same prefix ./swarm-grafana.nix reads its own client # them behind. The same prefix ./swarm-grafana.nix reads its own client
@ -554,8 +554,8 @@ in
# ./swarm-grafana.nix has for its own client. # ./swarm-grafana.nix has for its own client.
# THE delivery unit — one route, in every deployment. The secret authelia # THE delivery unit — one route, in every deployment. The secret authelia
# minted arrives out of the swarm secret store, which the publisher in # minted arrives out of the swarm secret store, which authelia's mint,
# authelia's container wrote it into, whether authelia is a network away or # in its container, wrote it into, whether authelia is a network away or
# in the container next door. # in the container next door.
# #
# 🩸 No unit here copies the plaintext directly out of authelia's # 🩸 No unit here copies the plaintext directly out of authelia's

View file

@ -119,8 +119,8 @@ in
description = '' description = ''
The OAuth2 client id the review classifier presents to the swarm queue. The OAuth2 client id the review classifier presents to the swarm queue.
Read-only: the host running authelia registers it, the queue's Read-only: the host running authelia registers it, the queue's
auth-callout responder grants it the try-out subject, and the secret auth-callout responder grants it the try-out subject, and
publisher carries its secret to the store, all from this one value. authelia's mint stores its secret in the store, all from this one value.
''; '';
}; };

View file

@ -2417,7 +2417,7 @@ let
&& !(lib.hasInfix "appservice-registration" baoGrantHere.systemd.services.swarm-bao-controller-policy.script); && !(lib.hasInfix "appservice-registration" baoGrantHere.systemd.services.swarm-bao-controller-policy.script);
} }
{ {
# The controller's own OIDC client secret, which the publisher writes and # The controller's own OIDC client secret, which authelia's mint writes and
# the controller reads at start. Pinned as the whole stanza, so an added # the controller reads at start. Pinned as the whole stanza, so an added
# capability fails. # capability fails.
name = "the controller reads its own client secret and cannot write it"; name = "the controller reads its own client secret and cannot write it";

View file

@ -421,7 +421,7 @@ let
# for: the reader's grant is one path under `services`, so a secret # for: the reader's grant is one path under `services`, so a secret
# filed under the hive that happens to run the store would be refused # filed under the hive that happens to run the store would be refused
# rather than missing, however correct the path reads. # rather than missing, however correct the path reads.
name = "the forwarder's secret is read from the prefix the publisher writes"; name = "the forwarder's secret is read from the prefix the mint writes";
ok = ok =
let let
s = baoWithCollector.systemd.services.swarm-bao-forwarder-oidc.script; s = baoWithCollector.systemd.services.swarm-bao-forwarder-oidc.script;

View file

@ -315,7 +315,7 @@ let
# refused rather than empty, however correct it reads. The negative arm is # refused rather than empty, however correct it reads. The negative arm is
# the rename this is exposed to — a secret filed under the hive that runs # the rename this is exposed to — a secret filed under the hive that runs
# the service instead of under the service itself. # the service instead of under the service itself.
name = "grafana's OIDC secret is read from the prefix the publisher writes"; name = "grafana's OIDC secret is read from the prefix the mint writes";
ok = ok =
let let
s = grafanaRemoteAuthelia.systemd.services.swarm-bao-grafana-oidc.script; s = grafanaRemoteAuthelia.systemd.services.swarm-bao-grafana-oidc.script;

View file

@ -125,7 +125,7 @@ let
# Same 403-not-a-miss reason as grafana's arm above: the reader's grant # Same 403-not-a-miss reason as grafana's arm above: the reader's grant
# covers the `services` prefix, so a path outside it is refused rather # covers the `services` prefix, so a path outside it is refused rather
# than empty, however correct it reads. # than empty, however correct it reads.
name = "the collector's OIDC secret is read from the prefix the publisher writes"; name = "the collector's OIDC secret is read from the prefix the mint writes";
ok = ok =
let let
s = otelBaoRemoteAuthelia.systemd.services.swarm-bao-otel-oidc.script; s = otelBaoRemoteAuthelia.systemd.services.swarm-bao-otel-oidc.script;

View file

@ -2,8 +2,8 @@
//! with. Read from the secret store as the responder starts and held in //! with. Read from the secret store as the responder starts and held in
//! memory, never in a file, `argv` or the environment. //! memory, never in a file, `argv` or the environment.
//! //!
//! The secret can change under a running responder: the publisher in authelia's //! The secret can change under a running responder: authelia's mint, in its
//! container re-publishes it when it is re-minted. So when the `IdP` refuses an //! container, writes a new one when it re-mints. So when the `IdP` refuses an
//! introspection as a credential (a 400 or 401), the secret is read from the //! introspection as a credential (a 400 or 401), the secret is read from the
//! store again ([`StoredSecret::after_refusal`]) and, when it changed, the //! store again ([`StoredSecret::after_refusal`]) and, when it changed, the
//! introspection is tried once more. Both fit in the one request's //! introspection is tried once more. Both fit in the one request's
@ -36,9 +36,9 @@ pub fn path(client_id: &str) -> Result<String> {
Ok(format!("{prefix}/oidc/client")) Ok(format!("{prefix}/oidc/client"))
} }
/// The secret at `path`, with surrounding whitespace trimmed: the publisher /// The secret at `path`, with surrounding whitespace trimmed: an earlier
/// stores the minted file as is, and a trailing newline is not part of the /// release stored the minted file as is, and a trailing newline is not part of
/// secret. Errors name the path, never the value. /// the secret. Errors name the path, never the value.
/// ///
/// # Errors /// # Errors
/// When the store cannot be read, or holds nothing or only whitespace there. /// When the store cannot be read, or holds nothing or only whitespace there.

View file

@ -66,7 +66,7 @@ pub fn client_secret_path(client_id: &str) -> Result<String, Error> {
/// No `Debug`: `value` authenticates the builder at the queue. /// No `Debug`: `value` authenticates the builder at the queue.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ClientSecret { pub struct ClientSecret {
/// The secret, under the field name the publisher writes. /// The secret, under the field name authelia's mint writes.
pub value: String, pub value: String,
} }

Some files were not shown because too many files have changed in this diff Show more