swarm-bao: grant the agent PKI mount (for #4756)
#4756 moves agent client certificates onto a PKI mount of their own, `pki-agents`, whose root bao generates internally. The unit that sets that mount up runs as the bao granter, and the granter's policy is only written while #4754's one-time bootstrap token is in place. Adding these grants after an operator has done that step would cost a second token placement, so they go into the granter's policy here, before it. Six stanzas: enable and tune the mount, list its issuers, read its CA, generate its root internally, and write `swarm-*` roles on it. No root delete or sudo: agent cert-auth roles pin that root by value, so replacing it must not be something a deploy can do. Adds deploy.bao.agentPkiMountPath (default `pki-agents`), which the stanzas are rendered from. The module-eval case pinning the granter's policy now lists all seventeen stanzas, and the "grants nothing outside" case also refuses the agent mount's root, issue, sign and a roles/* glob.
This commit is contained in:
parent
e9cec0da21
commit
5cd7f866f4
2 changed files with 81 additions and 4 deletions
|
|
@ -185,10 +185,13 @@ let
|
||||||
# A trailing `*` in a bao ACL path is a pure string-prefix match, and an
|
# A trailing `*` in a bao ACL path is a pure string-prefix match, and an
|
||||||
# exact path wins over any prefix.
|
# exact path wins over any prefix.
|
||||||
#
|
#
|
||||||
# The first three are the per-principal grants. The rest are what
|
# The first three are the per-principal grants. The next eight are what
|
||||||
# `swarm-bao-controller-policy` does besides grants: the KV and pki mounts and
|
# `swarm-bao-controller-policy` does besides grants: the KV and pki mounts and
|
||||||
# the services root. No `sys/auth`: the auth mounts are created with the
|
# the services root. The last six set up the agent PKI mount: the mount, its
|
||||||
# bootstrap token by `swarm-bao-granter-role`.
|
# root and the `swarm-*` role agent certificates are issued through. No
|
||||||
|
# `root` delete there: every agent's cert-auth role pins that root by value,
|
||||||
|
# so replacing it would lock every agent out. No `sys/auth`: the auth mounts
|
||||||
|
# are created with the bootstrap token by `swarm-bao-granter-role`.
|
||||||
#
|
#
|
||||||
# Piped as a shell-quoted argument like `controllerPolicyText`, so
|
# Piped as a shell-quoted argument like `controllerPolicyText`, so
|
||||||
# ../module-eval/bao-grants.nix can read it out of the unit script.
|
# ../module-eval/bao-grants.nix can read it out of the unit script.
|
||||||
|
|
@ -236,6 +239,30 @@ let
|
||||||
path "${servicesPkiMountPath}/root/generate/internal" {
|
path "${servicesPkiMountPath}/root/generate/internal" {
|
||||||
capabilities = ["create", "update"]
|
capabilities = ["create", "update"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path "sys/mounts/${agentPkiMountPath}" {
|
||||||
|
capabilities = ["create", "update"]
|
||||||
|
}
|
||||||
|
|
||||||
|
path "sys/mounts/${agentPkiMountPath}/tune" {
|
||||||
|
capabilities = ["create", "update"]
|
||||||
|
}
|
||||||
|
|
||||||
|
path "${agentPkiMountPath}/issuers" {
|
||||||
|
capabilities = ["list"]
|
||||||
|
}
|
||||||
|
|
||||||
|
path "${agentPkiMountPath}/cert/ca" {
|
||||||
|
capabilities = ["read"]
|
||||||
|
}
|
||||||
|
|
||||||
|
path "${agentPkiMountPath}/root/generate/internal" {
|
||||||
|
capabilities = ["create", "update"]
|
||||||
|
}
|
||||||
|
|
||||||
|
path "${agentPkiMountPath}/roles/swarm-*" {
|
||||||
|
capabilities = ["create", "update"]
|
||||||
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# What a granting unit prints when the store refuses the granter: the
|
# What a granting unit prints when the store refuses the granter: the
|
||||||
|
|
@ -473,6 +500,13 @@ let
|
||||||
# and has to spell it the same way.
|
# and has to spell it the same way.
|
||||||
servicesPkiMountPath = baoDeploy.servicesPkiMountPath;
|
servicesPkiMountPath = baoDeploy.servicesPkiMountPath;
|
||||||
|
|
||||||
|
# The PKI mount agent client certificates are issued from. Its root is
|
||||||
|
# generated inside the store, so the agent CA's key never exists outside it.
|
||||||
|
# A mount of its own because the services mount holds exactly one issuer; a
|
||||||
|
# root apart from ./glue-bao-tls.nix's CA because that is what keeps an
|
||||||
|
# agent's certificate from satisfying any host role.
|
||||||
|
agentPkiMountPath = baoDeploy.agentPkiMountPath;
|
||||||
|
|
||||||
# Subject of the root generated into that mount. A label for a human reading
|
# Subject of the root generated into that mount. A label for a human reading
|
||||||
# a chain, not an identity anything authenticates against — same fall-through
|
# a chain, not an identity anything authenticates against — same fall-through
|
||||||
# ./swarm-ca.nix:29-37 uses, and for the same reason: a hive that has set
|
# ./swarm-ca.nix:29-37 uses, and for the same reason: a hive that has set
|
||||||
|
|
@ -1221,6 +1255,20 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
agentPkiMountPath = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "pki-agents";
|
||||||
|
description = ''
|
||||||
|
Mount path of the PKI engine agent client certificates are issued
|
||||||
|
from. Its root is generated inside the store and its key never leaves
|
||||||
|
it.
|
||||||
|
|
||||||
|
An option rather than a literal because the store host sets the mount
|
||||||
|
up while swarm-controller, possibly on another host, issues through
|
||||||
|
it: both have to spell it identically.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
servicesPkiRoleName = lib.mkOption {
|
servicesPkiRoleName = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "swarm-services";
|
default = "swarm-services";
|
||||||
|
|
|
||||||
|
|
@ -820,7 +820,7 @@ let
|
||||||
{
|
{
|
||||||
# The granter's grants, whole. Pinned as the full list, because an added
|
# The granter's grants, whole. Pinned as the full list, because an added
|
||||||
# path or capability is exactly what a presence check misses.
|
# path or capability is exactly what a presence check misses.
|
||||||
name = "the granter's policy is exactly these eleven stanzas";
|
name = "the granter's policy is exactly these seventeen stanzas";
|
||||||
ok =
|
ok =
|
||||||
let
|
let
|
||||||
cu = [
|
cu = [
|
||||||
|
|
@ -876,6 +876,30 @@ let
|
||||||
path = "pki/root/generate/internal";
|
path = "pki/root/generate/internal";
|
||||||
caps = cu;
|
caps = cu;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
path = "sys/mounts/pki-agents";
|
||||||
|
caps = cu;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
path = "sys/mounts/pki-agents/tune";
|
||||||
|
caps = cu;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
path = "pki-agents/issuers";
|
||||||
|
caps = [ "list" ];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
path = "pki-agents/cert/ca";
|
||||||
|
caps = [ "read" ];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
path = "pki-agents/root/generate/internal";
|
||||||
|
caps = cu;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
path = "pki-agents/roles/swarm-*";
|
||||||
|
caps = cu;
|
||||||
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -908,6 +932,10 @@ let
|
||||||
"sys/policies/acl/root"
|
"sys/policies/acl/root"
|
||||||
"pki/issue/swarm-services"
|
"pki/issue/swarm-services"
|
||||||
"pki/sign/swarm-services"
|
"pki/sign/swarm-services"
|
||||||
|
"pki-agents/root"
|
||||||
|
"pki-agents/issue/swarm-agent"
|
||||||
|
"pki-agents/sign/swarm-agent"
|
||||||
|
"pki-agents/sign-verbatim"
|
||||||
"*"
|
"*"
|
||||||
]
|
]
|
||||||
&& !(lib.any (
|
&& !(lib.any (
|
||||||
|
|
@ -917,6 +945,7 @@ let
|
||||||
"sys/policies/acl/*"
|
"sys/policies/acl/*"
|
||||||
"auth/cert/certs/*"
|
"auth/cert/certs/*"
|
||||||
"pki/roles/*"
|
"pki/roles/*"
|
||||||
|
"pki-agents/roles/*"
|
||||||
]
|
]
|
||||||
) granterGrants);
|
) granterGrants);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue