# The cert login every unit that writes bao policies starts with, as shell text # that leaves `BAO_TOKEN` exported. It FAILS rather than skips: a grant that # was not written is otherwise invisible until whatever needs it fails # somewhere else. # # What the failure says follows from what the store answered: # # - A refused certificate ("invalid certificate or no client certificate # supplied", or "no chain matching all constraints"; openbao's cert-auth # login in `builtin/credential/cert/path_login.go`, HTTP 400) is the granter # role missing or not matching. Only that answer prints the one-time setup # steps. # - Any other failure from a store that answers `status` is not the role's: # a node that is not yet active answers the login with a 500 ("local node # not active but active cluster node not found") for the first moments after # an unseal. The message says so and the unit's `Restart=` retries. # - A store that does not answer `status` is sealed or unreachable. # # In every case bao's own error follows. # # Pure function — NOT a NixOS module. Call it from a module's `let`: # # granterLogin = import ./lib/granter-login.nix { # inherit lib granterCn granterPolicyName haveBootstrapToken baoStoreUp; # setupSteps = granterSetupSteps; # }; # # `baoStoreUp` is shell text that exits 0 on a reachable, unsealed store and # appends its error to `$err`. Needs `bao`, `coreutils` and `gnugrep` on the # caller's `path`. Takes the EXIT trap, to remove its scratch file. { lib, granterCn, granterPolicyName, haveBootstrapToken, baoStoreUp, setupSteps, }: '' err="$(mktemp)" trap 'rm -f "$err"' EXIT if ! BAO_TOKEN="$(bao login -method=cert -token-only 2>"$err")"; then if grep -qE 'invalid certificate or no client certificate supplied|no chain matching all constraints' "$err"; then echo ${lib.escapeShellArg "the store refused the granter's certificate (CN ${granterCn}): the ${granterPolicyName} role is not set up."} >&2 ${lib.optionalString haveBootstrapToken ''echo "swarm-bao-granter-role writes that role; journalctl -u swarm-bao-granter-role says why it has not." >&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") setupSteps} elif ${baoStoreUp}; then echo "the store is unsealed but the granter's login failed without a refused certificate, as a node that is not active yet answers; retrying." >&2 else echo "the store is sealed or unreachable; retrying." >&2 fi cat "$err" >&2 exit 1 fi export BAO_TOKEN ''