swarm-bao: let the controller list linked-account dirs
OpenBao checks a LIST against the directory with a trailing slash, so
the controller's LIST on secret/metadata/swarm/agents/<a>/matrix is
checked as .../matrix/. Its empty last segment matches the `+` in the
delete stanza .../agents/+/matrix/+ (added by bbf93120), which then is
the only non-exact rule matching, and its ["delete"] denies the LIST
before acl.go's trimmed-path fallback reaches .../+/matrix ["list"].
The forge directory fails the same way against .../+/forge/+.
Writing the list stanzas as .../+/matrix/ and .../+/forge/ makes them
match the slashed request too, and with one `+` segment against two
they outrank the delete stanzas. Deletes on .../matrix/<id> still
resolve to .../+/matrix/+, which the slashed list path does not match.
Reproduced by iris against a local bao server -dev with a non-root
token: list stanza alone allowed, plus the delete stanza denied, list
stanza with trailing slash plus the delete stanza allowed.
Closes #4919
This commit is contained in:
parent
08e67520ed
commit
4356dc82a4
2 changed files with 13 additions and 7 deletions
|
|
@ -375,6 +375,11 @@ let
|
|||
#
|
||||
# The agent PKI grant is its only path on that mount: it can ask the one role
|
||||
# for a certificate, not write that role or reach the issuer.
|
||||
|
||||
# The two `list` paths end in `/`: bao checks a LIST against the directory
|
||||
# with a trailing slash, where `+` matches the empty last segment, so a
|
||||
# slashless list path loses that request to the `+/matrix/+` and `+/forge/+`
|
||||
# delete stanzas and the LIST is denied.
|
||||
controllerPolicyText = ''
|
||||
path "auth/cert/certs/hive-*" {
|
||||
capabilities = ["create", "update", "read", "delete"]
|
||||
|
|
@ -400,11 +405,11 @@ let
|
|||
capabilities = ["delete"]
|
||||
}
|
||||
|
||||
path "${credentialMountPath}/metadata/swarm/agents/+/matrix" {
|
||||
path "${credentialMountPath}/metadata/swarm/agents/+/matrix/" {
|
||||
capabilities = ["list"]
|
||||
}
|
||||
|
||||
path "${credentialMountPath}/metadata/swarm/agents/+/forge" {
|
||||
path "${credentialMountPath}/metadata/swarm/agents/+/forge/" {
|
||||
capabilities = ["list"]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1197,9 +1197,10 @@ let
|
|||
}
|
||||
{
|
||||
# `linked_accounts` names an agent's matrix accounts and forge labels by
|
||||
# listing their two directories. A LIST matches the directory path
|
||||
# itself, so each stanza reaches that one directory: not the agent's
|
||||
# other keys, not `agents/` itself, not anything below. Pinned as whole
|
||||
# listing their two directories. bao checks a LIST against the directory
|
||||
# with a trailing slash, so each stanza names that slashed path and
|
||||
# reaches that one directory: not the agent's other keys, not `agents/`
|
||||
# itself, not anything below. Pinned as whole
|
||||
# stanzas, and as the only metadata stanzas under `agents/` beside the
|
||||
# queue revocation and the account deletes, so a widened path or an added
|
||||
# capability fails.
|
||||
|
|
@ -1209,8 +1210,8 @@ let
|
|||
s = baoGrantHere.systemd.services.swarm-bao-controller-policy.script;
|
||||
stanzas = lib.length (lib.splitString "path \"secret/metadata/swarm/agents/" s) - 1;
|
||||
in
|
||||
lib.hasInfix "path \"secret/metadata/swarm/agents/+/matrix\" {\n capabilities = [\"list\"]\n}" s
|
||||
&& lib.hasInfix "path \"secret/metadata/swarm/agents/+/forge\" {\n capabilities = [\"list\"]\n}" s
|
||||
lib.hasInfix "path \"secret/metadata/swarm/agents/+/matrix/\" {\n capabilities = [\"list\"]\n}" s
|
||||
&& lib.hasInfix "path \"secret/metadata/swarm/agents/+/forge/\" {\n capabilities = [\"list\"]\n}" s
|
||||
&& stanzas == 6;
|
||||
}
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue