swarm-bao: grant the controller read on the agent credential prefix

mint_and_verify reads the queue credential back before writing it, so a
re-run keeps the value a live agent already authenticates with. that read
is read_optional, which maps only a 404 to absence — so with create/update
alone every mint aborted on a 403 at its first store read.

read on the same paths the stanza already grants create and update, and
nothing else: no list, no delete, no patch.
This commit is contained in:
atlas 2026-09-23 17:59:34 +02:00 committed by mara
commit 87174863ca
2 changed files with 27 additions and 15 deletions

View file

@ -180,9 +180,17 @@ let
# `secret`, and the engine inserts `data/`. Matching the code's spelling
# literally would grant nothing.
#
# Write-only on purpose. The controller mints these; nothing in its job reads
# one back, and a read capability here would let it recover every agent's
# credentials rather than merely replace them.
# `read` is there because the controller mints idempotently: `mint_and_verify`
# reads the queue credential back before writing so that a re-run keeps the
# value a live agent is already authenticating with instead of rotating it.
# That read is `read_optional`, which treats only a 404 as absence — a denial
# stays an error on purpose, so without `read` the first re-run of a mint
# aborts on a 403 rather than concluding the path is empty.
#
# It is the whole of the widening: `read` on the paths this same stanza
# already lets the controller create and replace, and no `list`, so it can
# only fetch a credential for an agent it was told the name of — which is an
# agent it could already overwrite.
controllerPolicyText = ''
path "auth/cert/certs/hive-*" {
capabilities = ["create", "update", "read", "delete"]
@ -201,7 +209,7 @@ let
}
path "${credentialMountPath}/data/swarm/agents/*" {
capabilities = ["create", "update"]
capabilities = ["create", "read", "update"]
}
'';