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:
parent
e2ff4f5281
commit
87174863ca
2 changed files with 27 additions and 15 deletions
|
|
@ -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"]
|
||||
}
|
||||
'';
|
||||
|
||||
|
|
|
|||
|
|
@ -182,11 +182,13 @@ let
|
|||
&& !(lib.hasInfix "sys/policies/acl" s);
|
||||
}
|
||||
{
|
||||
# 🩸 `read` is load-bearing here and is the one capability neither
|
||||
# sibling has. matrix-ctl's first act is to read this path back and stop
|
||||
# if something is there — that read IS "and only once", so without the
|
||||
# capability every container restart would mint a second access token and
|
||||
# invalidate the hive's.
|
||||
# 🩸 `read` is load-bearing here, and the publisher — the one sibling
|
||||
# that still has no `read` — shows what its absence costs. matrix-ctl's
|
||||
# first act is to read this path back and stop if something is there —
|
||||
# that read IS "and only once", so without the capability every container
|
||||
# restart would mint a second access token and invalidate the hive's.
|
||||
# (The controller holds `read` for the same idempotency reason, on the
|
||||
# agent prefix.)
|
||||
name = "matrix-ctl may read back the one path it writes";
|
||||
ok =
|
||||
let
|
||||
|
|
@ -473,16 +475,18 @@ let
|
|||
&& !(lib.hasInfix "path \"secret/*\"" s);
|
||||
}
|
||||
{
|
||||
# Write-only is the property, not an accident of how it was typed: a
|
||||
# `read` here would let the controller recover every agent's credentials
|
||||
# instead of only replacing them. Pinned as the whole capability list,
|
||||
# because an added capability is exactly what a presence check misses.
|
||||
name = "the controller's grant on agent credentials is write-only";
|
||||
# The exact list is the property, not an accident of how it was typed.
|
||||
# `read` is in it because `mint_and_verify` reads a queue credential back
|
||||
# before rewriting it; `list` is not, so the controller can fetch a
|
||||
# credential only for an agent it was handed the name of, never enumerate
|
||||
# the tree. Pinned as the whole capability list, because an added
|
||||
# capability is exactly what a presence check misses.
|
||||
name = "the controller's grant on agent credentials is create/read/update and nothing else";
|
||||
ok =
|
||||
let
|
||||
s = baoGrantHere.systemd.services.swarm-bao-controller-policy.script;
|
||||
in
|
||||
lib.hasInfix "path \"secret/data/swarm/agents/*\" {\n capabilities = [\"create\", \"update\"]" s;
|
||||
lib.hasInfix "path \"secret/data/swarm/agents/*\" {\n capabilities = [\"create\", \"read\", \"update\"]" s;
|
||||
}
|
||||
{
|
||||
# The policy above grants paths under a mount nothing else creates, so
|
||||
|
|
|
|||
Loading…
Reference in a new issue