swarm-bao: keep the bootstrap policy in one file, checked against the units using it (#4698)

setup.md's copy of the swarm-bootstrap policy still granted only the
controller's first six paths, while eight units now act with the
bootstrap token. The policy moves to
nix/host-modules/swarm-bao-bootstrap-policy.hcl, now covering every path
those units call. module-eval-bao-grants reads that file and fails
when a unit whose script uses the token calls a path the file does not
grant.
This commit is contained in:
atlas 2026-09-24 15:53:53 +02:00
commit e3c595857e
2 changed files with 292 additions and 0 deletions

View file

@ -0,0 +1,136 @@
# The `swarm-bootstrap` policy: what the 24h bootstrap token may do, and
# nothing else. ../../docs/getting-started/setup.md has the operator write it
# with the root token; ./swarm-bao.nix's granting units then act with it.
#
# Each stanza was derived with `bao <cmd> -output-policy`, which prints what a
# command requires without sending it. ../module-eval/bao-grants.nix reads
# this file and fails when a unit that uses the token calls a path it does not
# grant. The pki paths assume the default `servicesPkiMountPath` (`pki`) and
# `servicesPkiRoleName` (`swarm-services`).
# swarm-bao-controller-policy: the controller's own policy and role.
path "sys/policies/acl/swarm-controller" {
capabilities = ["create", "update"]
}
path "auth/cert/certs/swarm-controller" {
capabilities = ["create", "update"]
}
# The auth mounts it creates. Reading `sys/auth` is how the unit checks, and
# `sudo` is what enabling one costs.
path "sys/auth" {
capabilities = ["read"]
}
path "sys/auth/cert" {
capabilities = ["create", "update", "sudo"]
}
path "sys/auth/approle" {
capabilities = ["create", "update", "sudo"]
}
# The KV and PKI engines, checked the same way. Enabling a secrets engine does
# not ask for `sudo`.
path "sys/mounts" {
capabilities = ["read"]
}
path "sys/mounts/secret" {
capabilities = ["create", "update"]
}
path "sys/mounts/pki" {
capabilities = ["create", "update"]
}
path "sys/mounts/pki/tune" {
capabilities = ["create", "update"]
}
# The services root: generated once, read back on every run, and replaced
# only when it can no longer outlive a leaf.
path "pki/issuers" {
capabilities = ["list"]
}
path "pki/cert/ca" {
capabilities = ["read"]
}
path "pki/root" {
capabilities = ["delete", "sudo"]
}
path "pki/root/generate/internal" {
capabilities = ["create", "update"]
}
path "pki/roles/swarm-services" {
capabilities = ["create", "update"]
}
# swarm-bao-secret-publisher-policy
path "sys/policies/acl/swarm-secret-publisher" {
capabilities = ["create", "update"]
}
path "auth/cert/certs/swarm-secret-publisher" {
capabilities = ["create", "update"]
}
# swarm-bao-matrix-ctl-policy
path "sys/policies/acl/swarm-matrix-ctl" {
capabilities = ["create", "update"]
}
path "auth/cert/certs/swarm-matrix-ctl" {
capabilities = ["create", "update"]
}
# swarm-bao-services-issuer-policy
path "sys/policies/acl/swarm-services-issuer" {
capabilities = ["create", "update"]
}
path "auth/cert/certs/swarm-services-issuer" {
capabilities = ["create", "update"]
}
# swarm-bao-grafana-oidc-policy
path "sys/policies/acl/swarm-grafana-oidc" {
capabilities = ["create", "update"]
}
path "auth/cert/certs/swarm-grafana-oidc" {
capabilities = ["create", "update"]
}
# swarm-bao-otel-oidc-policy
path "sys/policies/acl/swarm-otel-oidc" {
capabilities = ["create", "update"]
}
path "auth/cert/certs/swarm-otel-oidc" {
capabilities = ["create", "update"]
}
# swarm-bao-matrix-token-policy and swarm-bao-queue-agent-policy write one
# policy and role per hive, `<prefix>-<hive>`, so these two are globs. Each
# stops at its own prefix.
path "sys/policies/acl/swarm-matrix-token-*" {
capabilities = ["create", "update"]
}
path "auth/cert/certs/swarm-matrix-token-*" {
capabilities = ["create", "update"]
}
path "sys/policies/acl/swarm-queue-agent-*" {
capabilities = ["create", "update"]
}
path "auth/cert/certs/swarm-queue-agent-*" {
capabilities = ["create", "update"]
}