swarm-bao: the agent-token checkers' cert roles issue batch tokens
This commit is contained in:
parent
af914eb875
commit
de4871cab1
3 changed files with 56 additions and 7 deletions
|
|
@ -465,6 +465,13 @@ names the hive's own `clientCertFile` and misses a principal's pair has the
|
||||||
build refused, by the module of the reader it missed, naming that pair — see
|
build refused, by the module of the reader it missed, naming that pair — see
|
||||||
[what a missing leaf costs](#what-a-missing-leaf-costs) below.
|
[what a missing leaf costs](#what-a-missing-leaf-costs) below.
|
||||||
|
|
||||||
|
The roles of `swarm-nats-auth`, `swarm-logs-auth` and `swarm-metrics-auth` issue
|
||||||
|
batch tokens with a five-minute TTL (`token_type=batch`, `token_ttl=5m`). The
|
||||||
|
responders log in on every check, and the store keeps no record of a batch token,
|
||||||
|
so unauthenticated requests don't grow its token storage. Nothing can renew
|
||||||
|
or revoke a batch token. The other roles keep service tokens, because some of
|
||||||
|
their readers hold a handle for longer than five minutes.
|
||||||
|
|
||||||
### What a missing leaf costs
|
### What a missing leaf costs
|
||||||
|
|
||||||
Each of the three modules asserts its own pair, on the same condition: **this host
|
Each of the three modules asserts its own pair, on the same condition: **this host
|
||||||
|
|
|
||||||
|
|
@ -1001,6 +1001,7 @@ let
|
||||||
{
|
{
|
||||||
name = "swarm-nats-auth";
|
name = "swarm-nats-auth";
|
||||||
cn = baoDeploy.natsAuthCommonName;
|
cn = baoDeploy.natsAuthCommonName;
|
||||||
|
batchToken = true;
|
||||||
policyText =
|
policyText =
|
||||||
readStanza "${credentialMountPath}/data/swarm/agents/+/queue"
|
readStanza "${credentialMountPath}/data/swarm/agents/+/queue"
|
||||||
+ readStanza "${credentialMountPath}/data/swarm/services/${hyperhiveCfg.swarm.nats.clientId}/oidc/client"
|
+ readStanza "${credentialMountPath}/data/swarm/services/${hyperhiveCfg.swarm.nats.clientId}/oidc/client"
|
||||||
|
|
@ -1052,6 +1053,7 @@ let
|
||||||
{
|
{
|
||||||
name = "swarm-logs-auth";
|
name = "swarm-logs-auth";
|
||||||
cn = baoDeploy.logsAuthCommonName;
|
cn = baoDeploy.logsAuthCommonName;
|
||||||
|
batchToken = true;
|
||||||
policyText =
|
policyText =
|
||||||
readStanza "${credentialMountPath}/data/swarm/agents/+/queue"
|
readStanza "${credentialMountPath}/data/swarm/agents/+/queue"
|
||||||
+ readStanza "${credentialMountPath}/data/${grafanaMetricsBearerLeaf}"
|
+ readStanza "${credentialMountPath}/data/${grafanaMetricsBearerLeaf}"
|
||||||
|
|
@ -1069,6 +1071,7 @@ let
|
||||||
{
|
{
|
||||||
name = "swarm-metrics-auth";
|
name = "swarm-metrics-auth";
|
||||||
cn = baoDeploy.metricsAuthCommonName;
|
cn = baoDeploy.metricsAuthCommonName;
|
||||||
|
batchToken = true;
|
||||||
policyText =
|
policyText =
|
||||||
readStanza "${credentialMountPath}/data/swarm/agents/+/queue"
|
readStanza "${credentialMountPath}/data/swarm/agents/+/queue"
|
||||||
+ readStanza "${credentialMountPath}/data/${grafanaMetricsBearerLeaf}"
|
+ readStanza "${credentialMountPath}/data/${grafanaMetricsBearerLeaf}"
|
||||||
|
|
@ -1182,13 +1185,25 @@ let
|
||||||
# `swarm` in one — and ./swarm.nix reserves the concrete per-hive spellings
|
# `swarm` in one — and ./swarm.nix reserves the concrete per-hive spellings
|
||||||
# anyway, because the prefixes are operator-settable and an operator may spell
|
# anyway, because the prefixes are operator-settable and an operator may spell
|
||||||
# one without that substring.
|
# one without that substring.
|
||||||
readerRoleWrite = obj: ''
|
#
|
||||||
bao write auth/cert/certs/${lib.escapeShellArg obj.name} \
|
# `batchToken = true` on an object makes its logins batch tokens, which the
|
||||||
certificate=@${tlsDir}/client-ca.pem \
|
# store does not persist and cannot renew or revoke. Only for a principal
|
||||||
allowed_common_names=${lib.escapeShellArg obj.cn} \
|
# that logs in, reads and drops the token within one call: the five
|
||||||
token_policies=${lib.escapeShellArg obj.name} \
|
# minutes outlast that read, and a leaked token dies as fast. A principal
|
||||||
display_name=${lib.escapeShellArg obj.cn}
|
# that holds a handle longer must not set it.
|
||||||
'';
|
readerRoleWrite =
|
||||||
|
obj:
|
||||||
|
let
|
||||||
|
batchArgs = lib.optionalString (obj.batchToken or false
|
||||||
|
) " \\\n token_type=batch \\\n token_ttl=5m";
|
||||||
|
in
|
||||||
|
''
|
||||||
|
bao write auth/cert/certs/${lib.escapeShellArg obj.name} \
|
||||||
|
certificate=@${tlsDir}/client-ca.pem \
|
||||||
|
allowed_common_names=${lib.escapeShellArg obj.cn} \
|
||||||
|
token_policies=${lib.escapeShellArg obj.name} \
|
||||||
|
display_name=${lib.escapeShellArg obj.cn}${batchArgs}
|
||||||
|
'';
|
||||||
|
|
||||||
# A unit that logs in as the granter and runs `body`, ordered after the
|
# A unit that logs in as the granter and runs `body`, ordered after the
|
||||||
# controller's unit. `after` and not `requires`: the controller's and the
|
# controller's unit. `after` and not `requires`: the controller's and the
|
||||||
|
|
|
||||||
|
|
@ -815,6 +815,33 @@ let
|
||||||
&& lib.hasInfix "allowed_common_names=swarm-metrics-auth" s
|
&& lib.hasInfix "allowed_common_names=swarm-metrics-auth" s
|
||||||
&& lib.hasInfix "token_policies=swarm-metrics-auth" s;
|
&& lib.hasInfix "token_policies=swarm-metrics-auth" s;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
# The three agent-token checkers log in once per check; a batch token
|
||||||
|
# leaves nothing stored per request. The CI runner's role, written by the
|
||||||
|
# same helper, keeps service tokens, and still carries its policy, so a
|
||||||
|
# misspelled script name cannot make the absence pass.
|
||||||
|
name = "the agent-token checkers' roles issue batch tokens and a holder's role does not";
|
||||||
|
ok =
|
||||||
|
let
|
||||||
|
script = unit: baoGrantHere.systemd.services.${unit}.script;
|
||||||
|
batch =
|
||||||
|
unit: role:
|
||||||
|
let
|
||||||
|
s = script unit;
|
||||||
|
in
|
||||||
|
lib.hasInfix "auth/cert/certs/${role} " s
|
||||||
|
&& lib.hasInfix "token_type=batch" s
|
||||||
|
&& lib.hasInfix "token_ttl=5m" s
|
||||||
|
&& !(lib.hasInfix "token_max_ttl" s);
|
||||||
|
ci = script "swarm-bao-ci-runner-policy";
|
||||||
|
in
|
||||||
|
batch "swarm-bao-nats-auth-policy" "swarm-nats-auth"
|
||||||
|
&& batch "swarm-bao-logs-auth-policy" "swarm-logs-auth"
|
||||||
|
&& batch "swarm-bao-metrics-auth-policy" "swarm-metrics-auth"
|
||||||
|
&& lib.hasInfix "token_policies=swarm-ci-runner" ci
|
||||||
|
&& !(lib.hasInfix "token_type" ci)
|
||||||
|
&& !(lib.hasInfix "token_ttl" ci);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
name = "the PKI unit signs the metrics store responder's leaf under its own subject";
|
name = "the PKI unit signs the metrics store responder's leaf under its own subject";
|
||||||
ok =
|
ok =
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue