Every unit that writes a bao policy or cert-auth role ran only while the operator-placed bootstrap token existed, and skipped silently otherwise. The token lives 24h, so on any real swarm a PR adding or changing a grant deployed with its unit skipped, and each one needed a manual token refresh (plus a root `bao policy write` when it added a path). A `bao-granter` principal now writes them. Its leaf is minted by swarm-bao-pki on the store host (0600 root, never copied off it), and its policy covers `swarm-*` policies, `swarm-*` cert-auth roles and `pki/roles/swarm-*` by glob, plus the mount and services-root paths the controller's unit already used. All ten granting units (controller, secret-publisher, matrix-ctl, matrix-token, queue-agent, grafana-oidc, otel-oidc, forwarder-oidc, services-issuer, nats-tls) log in with it instead of reading the token. They keep the 2880 x 30s retry, now require swarm-bao-pki, and when the store refuses the granter they fail and print the one-time step instead of skipping. swarm-bao-granter-role is the one unit left on the token. It enables the auth mounts (moved out of the controller's unit) and writes the granter's own policy and role. The bootstrap policy is renamed `bao-bootstrap` and shrinks to those five stanzas; it is shipped at /etc/hyperhive/bao-bootstrap-policy.hcl. The old name `swarm-bootstrap` matched the granter's own `swarm-*` glob. The granter's CN joins certAuthCns, so no hive can be named into its role. An assertion keeps both pki role names under `swarm-`. With no client CA the granting units no longer render, and a warning says so. module-eval pins the granter's policy stanza by stanza, what it cannot reach, that every call a granting unit makes is granted, and that only swarm-bao-granter-role reads the token. Refs #4704
65 lines
2.5 KiB
Nix
65 lines
2.5 KiB
Nix
# Glue: where the store and one of its readers share a host, the reader waits
|
|
# for the unit that writes the cert-auth role it logs in with.
|
|
#
|
|
# ONE PAIRING PER FILE — the store's reader policy units ← the readers
|
|
# they grant, and nothing else. Deleting this leaves every reader as it is on a
|
|
# host whose store is remote: it may log in before its role exists, and its own
|
|
# retries are what carry it past that.
|
|
#
|
|
# ⚠️ Gated on BOTH the store and that reader being here. Off the store's host
|
|
# there is no local policy unit to order against. On the store's host without
|
|
# the reader, setting `systemd.services.<reader>.after` would define a unit
|
|
# with no ExecStart, so each gate below restates the one the reader's own
|
|
# module puts on it. A reader whose gate changes must change here too.
|
|
#
|
|
# Ordering, never a requirement: a policy unit that failed still counts as
|
|
# done, and the reader's own retries carry it past that. `wants` as well as
|
|
# `after`, so a reader started on its own pulls its policy unit into the same
|
|
# transaction.
|
|
{
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
hyperhiveCfg = config.services.hyperhive;
|
|
deployCfg = hyperhiveCfg.deploy;
|
|
baoDeploy = deployCfg.bao;
|
|
|
|
havePair = cert: key: cert != null && key != null;
|
|
|
|
# Reader unit → the gate its own module defines it under.
|
|
readersHere = {
|
|
# ./glue-matrix-bao-token.nix
|
|
swarm-bao-matrix-token =
|
|
havePair baoDeploy.matrixTokenClientCertFile baoDeploy.matrixTokenClientKeyFile
|
|
&& deployCfg.matrix.enable;
|
|
# ./glue-queue-agent-credential.nix
|
|
swarm-bao-queue-agent =
|
|
deployCfg.hive-controller.enable
|
|
&& havePair baoDeploy.queueAgentClientCertFile baoDeploy.queueAgentClientKeyFile;
|
|
# ./swarm-grafana.nix
|
|
swarm-bao-grafana-oidc = deployCfg.grafana.enable;
|
|
# ./swarm-otel.nix
|
|
swarm-bao-otel-oidc =
|
|
deployCfg.swarm-otel.enable
|
|
&& havePair baoDeploy.otelOidcClientCertFile baoDeploy.otelOidcClientKeyFile;
|
|
# ./swarm-bao.nix: its block is gated on the store, which `orderAfterPolicy`
|
|
# already checks.
|
|
swarm-bao-forwarder-oidc = true;
|
|
# ./swarm-nats.nix: the queue's TLS leaf, not a secret, but the same wait.
|
|
swarm-bao-nats-tls = deployCfg.nats.enable;
|
|
};
|
|
|
|
orderAfterPolicy =
|
|
reader: here:
|
|
lib.mkIf (baoDeploy.enable && here) {
|
|
systemd.services.${reader} = {
|
|
after = [ "${reader}-policy.service" ];
|
|
wants = [ "${reader}-policy.service" ];
|
|
};
|
|
};
|
|
in
|
|
{
|
|
config = lib.mkMerge (lib.mapAttrsToList orderAfterPolicy readersHere);
|
|
}
|