hive-c0re: hand the daemon the store identity it cannot open itself

`credential.rs` calls `SecretStore::from_env`, and nothing set `BAO_*` for
this unit — only `swarm-bao-matrix-token` had them. Fixing that alone would
not have been enough: hive-c0re runs as hive-core, and glue-bao-tls mints the
client key `0600` inside a `0700` directory, so the daemon cannot read the
file even when it is named.

Both halves go through LoadCredential, which this unit already uses for the
swarm-status client secret: root reads the identity at unit start, hive-core
sees it under `%d`, and no second on-disk copy exists.

The gate is the identity, never `deploy.bao.enable` — a hive that reads a
store on another machine holds a certificate and runs no store. Four
module-eval cases: the co-located and off-host presence arms, the absence arm
for a hive with no identity, and a presence/absence pair for the optional CA.
This commit is contained in:
atlas 2026-09-02 23:51:00 +02:00 committed by mara
commit ad439843f1
3 changed files with 103 additions and 1 deletions

View file

@ -9,6 +9,13 @@
}:
let
cfg = config.services.hyperhive.c0re;
baoDeploy = config.services.hyperhive.deploy.bao;
baoCfg = config.services.hyperhive.swarm.bao;
# The same test ../glue-matrix-bao-token.nix applies, and for the same
# reason: a reader is defined by holding a certificate the store accepts,
# not by sharing a host with the store. Deriving this from
# `deploy.bao.enable` would be the co-location assumption itself.
haveBaoClientIdentity = baoDeploy.clientCertFile != null && baoDeploy.clientKeyFile != null;
in
{
# nix (the prebuild `nix build`, flake-check, and meta eval) writes
@ -263,3 +270,23 @@ in
# ./default.nix. The daemon reads a path, never a value.
HIVE_C0RE_OIDC_CLIENT_SECRET_FILE = "%d/swarm-status-client.secret";
}
//
# Where the swarm's secret store is, and the identity this hive presents to
# it (hive-c0re::workers::credential). `swarm_secret_client` reads these
# spellings explicitly rather than vaultrs's `VAULT_*` defaults — falling
# through to those would build a client with no identity and fail at the TLS
# handshake, naming neither.
lib.optionalAttrs haveBaoClientIdentity {
BAO_ADDR = "https://${baoCfg.domain}:${toString baoCfg.port}";
# `%d`, not the paths themselves: the key is `0600` root-owned and this
# daemon runs as hive-core, so it never gets read access to the original.
# See the LoadCredential in ./default.nix.
BAO_CLIENT_CERT = "%d/bao-client.pem";
BAO_CLIENT_KEY = "%d/bao-client-key.pem";
}
// lib.optionalAttrs (haveBaoClientIdentity && baoDeploy.serverCaFile != null) {
# Absent means the system trust store — right for a deployment with a real
# CA, wrong for the self-signed one ../glue-bao-tls.nix mints, which is why
# that file names this path rather than leaving it to a default.
BAO_CACERT = "%d/bao-ca.pem";
}