Watch
0
0
Fork
You've already forked hyperhive
0

granter role unit: no-op when the granter login works, delete the token after success

This commit is contained in:
atlas 2026-10-26 18:41:38 +01:00 • committed by mara
commit 3db835fb57
4 changed files with 42 additions and 3 deletions

View file

@ -37,13 +37,13 @@ systemctl restart swarm-bao-granter-role
Check `systemctl status swarm-bao-granter-role` logs
`Uploaded policy: bao-granter`, then restart the granting units that
failed while they waited, and remove the token:
failed while they waited. The granter unit deletes the token itself after a
successful run:
```bash
systemctl reset-failed 'swarm-bao-*-policy.service' swarm-bao-agent-pki.service
systemctl restart 'swarm-bao-*-policy.service' swarm-bao-agent-pki.service
systemctl status swarm-bao-controller-policy # Uploaded policy, Data written to: auth/cert/certs/swarm-controller
rm /var/lib/swarm-bao-bootstrap/grant.token
```
⏱️ A first attempt right after a rebuild may fail with `local node not

View file

@ -43,7 +43,10 @@ TTL means a forgotten file expires rather than lingering.
A sealed or unreachable store makes the unit retry every 30 s. A store that
refuses the token (expired, revoked, or missing the `bao-bootstrap` policy)
makes it exit 4 and stay `failed` with the one-time step in its log; mint a
fresh token or remove the file, then restart it.
fresh token or remove the file, then restart it. If the granter's own
certificate login already works, the unit logs that the bootstrap token isn't
needed and exits 0, so a stale file is harmless. A successful run deletes the
token file.
After that, a new or changed `swarm-*` grant needs no operator step: the unit
that writes it changes, and the deploy restarts it. A root step comes back only

View file

@ -3182,6 +3182,17 @@ in
# revoked, or minted without that policy.
if ! mounted="$(bao auth list -format=json 2>"$err")"; then
if ${baoStoreUp}; then
# A dead token beside a working granter is the steady state of
# a host that finished bootstrap and kept the file. The
# granter's own login is the proof. A fresh token still takes
# the full path below, since the granter cannot read back its
# own policy to compare it.
if BAO_CLIENT_CERT=${lib.escapeShellArg baoDeploy.granterClientCertFile} \
BAO_CLIENT_KEY=${lib.escapeShellArg baoDeploy.granterClientKeyFile} \
bao login -method=cert -token-only >/dev/null 2>&1; then
echo "granter role already in place; bootstrap token not needed"
exit 0
fi
echo ${lib.escapeShellArg "the store is unsealed but refused the bootstrap token in ${baoDeploy.bootstrapTokenFile}: it has expired, been revoked, or does not carry the bao-bootstrap policy."} >&2
echo "one-time step, as root on this host (docs/getting-started/setup.md):" >&2
${lib.concatMapStringsSep "\n" (l: "echo ${lib.escapeShellArg " ${l}"} >&2") granterSetupSteps}
@ -3224,6 +3235,9 @@ in
display_name=${lib.escapeShellArg granterCn} \
token_ttl=15m \
token_max_ttl=15m
# Single-use by design; the setup procedure's last step.
rm -f ${lib.escapeShellArg baoDeploy.bootstrapTokenFile}
'';
};

View file

@ -1112,6 +1112,28 @@ let
[ "swarm-bao-granter-role" ] ++ grantingUnitNames
);
}
{
# A dead token beside a working granter exits 0; one with no working
# granter still reaches exit 4; a successful run removes the token file.
# Presence controls: the controller's unit has neither the no-op line
# nor the delete.
name = "the granter's unit no-ops on a working granter login, still exits 4 without one, and deletes the token";
ok =
let
g = baoGrantHere.systemd.services.swarm-bao-granter-role.script;
other = baoGrantHere.systemd.services.swarm-bao-controller-policy.script;
noop = "granter role already in place; bootstrap token not needed";
del = "rm -f /run/secrets/bao-bootstrap.token";
before = lib.head (lib.splitString "refused the bootstrap token" g);
in
lib.hasInfix noop before
&& lib.hasInfix "bao login -method=cert -token-only" before
&& lib.hasInfix "BAO_CLIENT_CERT=" before
&& lib.hasInfix del g
&& lib.hasInfix "exit 4" g
&& !(lib.hasInfix noop other)
&& !(lib.hasInfix del other);
}
{
# Every granting unit retries a sealed or late store for a day, in the
# `[Unit]` section systemd reads it from, and waits for the unit that