swarm-bao: build the granter policy units from one helper
The six hand-written granter policy units (secret-publisher, matrix-ctl, services-issuer, nats-tls, hive-leaf, operator-viewer) repeated the same skeleton readerPolicyUnit already carried: ordering after the controller's unit, pki requirement, path, granter environment, unseal retry window and oneshot serviceConfig. They differed only in description and the script after the granter login. granterPolicyUnit now owns that skeleton; the six units and readerPolicyUnit pass a description and a script body. Every rendered unit is unchanged byte-for-byte.
This commit is contained in:
parent
4fa1cee620
commit
54226e027d
1 changed files with 151 additions and 310 deletions
|
|
@ -969,18 +969,13 @@ let
|
||||||
display_name=${lib.escapeShellArg obj.cn}
|
display_name=${lib.escapeShellArg obj.cn}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# One unit per PRINCIPAL, not one unit for all of them: these names are
|
# A unit that logs in as the granter and runs `body`, ordered after the
|
||||||
# operator-facing strings, the same reason `swarm-bao-secret-publisher-policy`
|
# controller's unit. `after` and not `requires`: the controller's and the
|
||||||
# above gives for not being more script inside the controller's unit. A hive
|
# granter's units create the mounts these write into, but a failed oneshot
|
||||||
# whose queue credential never arrives is diagnosed by the state of the unit named
|
# still counts as finished, so ordering plus this unit's own retry is what
|
||||||
# after it.
|
# converges. `body` follows the login with no separator.
|
||||||
#
|
granterPolicyUnit =
|
||||||
# `after` and not `requires`, for the reason the publisher's unit states: the
|
description: body:
|
||||||
# controller's and the granter's units create the mounts this one writes
|
|
||||||
# into, but a failed oneshot still counts as finished, so ordering plus this
|
|
||||||
# unit's own retry is what converges.
|
|
||||||
readerPolicyUnit =
|
|
||||||
description: objects:
|
|
||||||
lib.mkIf haveGranter {
|
lib.mkIf haveGranter {
|
||||||
inherit description;
|
inherit description;
|
||||||
after = [
|
after = [
|
||||||
|
|
@ -995,8 +990,8 @@ let
|
||||||
pkgs.coreutils
|
pkgs.coreutils
|
||||||
];
|
];
|
||||||
environment = granterEnv;
|
environment = granterEnv;
|
||||||
# Same unseal wait as its siblings above, for the reason stated there:
|
# Same unseal wait as `swarm-bao-controller-policy`, for the reason stated
|
||||||
# under `seal = "shamir"` a human unseals by hand.
|
# there: under `seal = "shamir"` a human unseals by hand.
|
||||||
startLimitBurst = 2880;
|
startLimitBurst = 2880;
|
||||||
startLimitIntervalSec = 90000;
|
startLimitIntervalSec = 90000;
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
|
@ -1010,11 +1005,20 @@ let
|
||||||
|
|
||||||
${granterLogin}
|
${granterLogin}
|
||||||
''
|
''
|
||||||
+ lib.concatMapStrings readerPolicyWrite objects
|
+ body;
|
||||||
+ "\n"
|
|
||||||
+ lib.concatMapStrings readerRoleWrite objects;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# One unit per PRINCIPAL, not one unit for all of them: these names are
|
||||||
|
# operator-facing strings, the same reason `swarm-bao-secret-publisher-policy`
|
||||||
|
# below gives for not being more script inside the controller's unit. A hive
|
||||||
|
# whose queue credential never arrives is diagnosed by the state of the unit named
|
||||||
|
# after it.
|
||||||
|
readerPolicyUnit =
|
||||||
|
description: objects:
|
||||||
|
granterPolicyUnit description (
|
||||||
|
lib.concatMapStrings readerPolicyWrite objects + "\n" + lib.concatMapStrings readerRoleWrite objects
|
||||||
|
);
|
||||||
|
|
||||||
# Every listener serves the same identity: they differ in which address
|
# Every listener serves the same identity: they differ in which address
|
||||||
# they answer on, not in who they are. Client verification is separate and
|
# they answer on, not in who they are. Client verification is separate and
|
||||||
# optional — a store with no `clientCaFile` still serves TLS, it just does
|
# optional — a store with no `clientCaFile` still serves TLS, it just does
|
||||||
|
|
@ -3013,34 +3017,7 @@ in
|
||||||
# finished, so `requires` would neither wait for its success nor re-run
|
# finished, so `requires` would neither wait for its success nor re-run
|
||||||
# this one when its own retry eventually lands. Ordering plus this unit's
|
# this one when its own retry eventually lands. Ordering plus this unit's
|
||||||
# own retry is what actually converges.
|
# own retry is what actually converges.
|
||||||
systemd.services.swarm-bao-secret-publisher-policy = lib.mkIf haveGranter {
|
systemd.services.swarm-bao-secret-publisher-policy = granterPolicyUnit "write the swarm secret publisher's bao policy and cert-auth role" ''
|
||||||
description = "write the swarm secret publisher's bao policy and cert-auth role";
|
|
||||||
after = [
|
|
||||||
"container@${cfg.machine}.service"
|
|
||||||
"swarm-bao-controller-policy.service"
|
|
||||||
]
|
|
||||||
++ granterAfter;
|
|
||||||
requires = [ "swarm-bao-pki.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
path = [
|
|
||||||
baoCli
|
|
||||||
pkgs.coreutils
|
|
||||||
];
|
|
||||||
environment = granterEnv;
|
|
||||||
# Same unseal wait as its sibling above, for the reason stated there:
|
|
||||||
# under `seal = "shamir"` a human unseals by hand, which can take a day.
|
|
||||||
startLimitBurst = 2880;
|
|
||||||
startLimitIntervalSec = 90000;
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 30;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
${granterLogin}
|
|
||||||
|
|
||||||
printf '%s' ${lib.escapeShellArg secretPublisherPolicyText} |
|
printf '%s' ${lib.escapeShellArg secretPublisherPolicyText} |
|
||||||
bao policy write ${lib.escapeShellArg secretPublisherPolicyName} -
|
bao policy write ${lib.escapeShellArg secretPublisherPolicyName} -
|
||||||
|
|
@ -3051,7 +3028,6 @@ in
|
||||||
token_policies=${lib.escapeShellArg secretPublisherPolicyName} \
|
token_policies=${lib.escapeShellArg secretPublisherPolicyName} \
|
||||||
display_name=${lib.escapeShellArg secretPublisherCn}
|
display_name=${lib.escapeShellArg secretPublisherCn}
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
|
|
||||||
# A THIRD sibling, for the reason the second one's comment gives: these
|
# A THIRD sibling, for the reason the second one's comment gives: these
|
||||||
# unit names are operator-facing strings, and the grant written here
|
# unit names are operator-facing strings, and the grant written here
|
||||||
|
|
@ -3060,34 +3036,7 @@ in
|
||||||
# creates the mounts this one writes into, but a failed oneshot still
|
# creates the mounts this one writes into, but a failed oneshot still
|
||||||
# counts as finished, so only ordering plus this unit's own retry
|
# counts as finished, so only ordering plus this unit's own retry
|
||||||
# converges.
|
# converges.
|
||||||
systemd.services.swarm-bao-matrix-ctl-policy = lib.mkIf haveGranter {
|
systemd.services.swarm-bao-matrix-ctl-policy = granterPolicyUnit "write swarm-matrix-ctl's bao policy and cert-auth role" ''
|
||||||
description = "write swarm-matrix-ctl's bao policy and cert-auth role";
|
|
||||||
after = [
|
|
||||||
"container@${cfg.machine}.service"
|
|
||||||
"swarm-bao-controller-policy.service"
|
|
||||||
]
|
|
||||||
++ granterAfter;
|
|
||||||
requires = [ "swarm-bao-pki.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
path = [
|
|
||||||
baoCli
|
|
||||||
pkgs.coreutils
|
|
||||||
];
|
|
||||||
environment = granterEnv;
|
|
||||||
# Same unseal wait as its two siblings above, for the reason stated
|
|
||||||
# there: under `seal = "shamir"` a human unseals by hand.
|
|
||||||
startLimitBurst = 2880;
|
|
||||||
startLimitIntervalSec = 90000;
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 30;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
${granterLogin}
|
|
||||||
|
|
||||||
printf '%s' ${lib.escapeShellArg matrixCtlPolicyText} |
|
printf '%s' ${lib.escapeShellArg matrixCtlPolicyText} |
|
||||||
bao policy write ${lib.escapeShellArg matrixCtlPolicyName} -
|
bao policy write ${lib.escapeShellArg matrixCtlPolicyName} -
|
||||||
|
|
@ -3098,7 +3047,6 @@ in
|
||||||
token_policies=${lib.escapeShellArg matrixCtlPolicyName} \
|
token_policies=${lib.escapeShellArg matrixCtlPolicyName} \
|
||||||
display_name=${lib.escapeShellArg matrixCtlCn}
|
display_name=${lib.escapeShellArg matrixCtlCn}
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
|
|
||||||
# 🩸 The principals that each log in with a leaf of their own, not as the
|
# 🩸 The principals that each log in with a leaf of their own, not as the
|
||||||
# hive. See the block around `perHiveReaders` for what each grant is and
|
# hive. See the block around `perHiveReaders` for what each grant is and
|
||||||
|
|
@ -3128,34 +3076,7 @@ in
|
||||||
#
|
#
|
||||||
# The policy text lives beside the role that carries it: a policy and
|
# The policy text lives beside the role that carries it: a policy and
|
||||||
# its role belong in one place, with the principal they grant.
|
# its role belong in one place, with the principal they grant.
|
||||||
systemd.services.swarm-bao-services-issuer-policy = lib.mkIf haveGranter {
|
systemd.services.swarm-bao-services-issuer-policy = granterPolicyUnit "write the swarm services issuer's bao policy and cert-auth role" ''
|
||||||
description = "write the swarm services issuer's bao policy and cert-auth role";
|
|
||||||
after = [
|
|
||||||
"container@${cfg.machine}.service"
|
|
||||||
"swarm-bao-controller-policy.service"
|
|
||||||
]
|
|
||||||
++ granterAfter;
|
|
||||||
requires = [ "swarm-bao-pki.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
path = [
|
|
||||||
baoCli
|
|
||||||
pkgs.coreutils
|
|
||||||
];
|
|
||||||
environment = granterEnv;
|
|
||||||
# Same unseal wait as its three siblings above, for the reason stated
|
|
||||||
# there: under `seal = "shamir"` a human unseals by hand.
|
|
||||||
startLimitBurst = 2880;
|
|
||||||
startLimitIntervalSec = 90000;
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 30;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
${granterLogin}
|
|
||||||
|
|
||||||
printf '%s' ${lib.escapeShellArg servicesIssuerPolicyText} |
|
printf '%s' ${lib.escapeShellArg servicesIssuerPolicyText} |
|
||||||
bao policy write ${lib.escapeShellArg servicesIssuerPolicyName} -
|
bao policy write ${lib.escapeShellArg servicesIssuerPolicyName} -
|
||||||
|
|
@ -3166,7 +3087,6 @@ in
|
||||||
token_policies=${lib.escapeShellArg servicesIssuerPolicyName} \
|
token_policies=${lib.escapeShellArg servicesIssuerPolicyName} \
|
||||||
display_name=${lib.escapeShellArg servicesIssuerCn}
|
display_name=${lib.escapeShellArg servicesIssuerCn}
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
|
|
||||||
# A FIFTH sibling: the queue's issuing role, its policy and its login
|
# A FIFTH sibling: the queue's issuing role, its policy and its login
|
||||||
# role, together. The `pki` role lives here rather than beside
|
# role, together. The `pki` role lives here rather than beside
|
||||||
|
|
@ -3176,33 +3096,7 @@ in
|
||||||
# The role narrows exactly as `swarm-services` does, to one name. It is
|
# The role narrows exactly as `swarm-services` does, to one name. It is
|
||||||
# the queue's domain alone, since the same name reaches it from every
|
# the queue's domain alone, since the same name reaches it from every
|
||||||
# hive; no IP SANs, since nothing dials an address.
|
# hive; no IP SANs, since nothing dials an address.
|
||||||
systemd.services.swarm-bao-nats-tls-policy = lib.mkIf haveGranter {
|
systemd.services.swarm-bao-nats-tls-policy = granterPolicyUnit "write the swarm queue's pki role, bao policy and cert-auth role" ''
|
||||||
description = "write the swarm queue's pki role, bao policy and cert-auth role";
|
|
||||||
after = [
|
|
||||||
"container@${cfg.machine}.service"
|
|
||||||
"swarm-bao-controller-policy.service"
|
|
||||||
]
|
|
||||||
++ granterAfter;
|
|
||||||
requires = [ "swarm-bao-pki.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
path = [
|
|
||||||
baoCli
|
|
||||||
pkgs.coreutils
|
|
||||||
];
|
|
||||||
environment = granterEnv;
|
|
||||||
# Same unseal wait as its siblings above.
|
|
||||||
startLimitBurst = 2880;
|
|
||||||
startLimitIntervalSec = 90000;
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 30;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
${granterLogin}
|
|
||||||
|
|
||||||
bao write ${lib.escapeShellArg "${servicesPkiMountPath}/roles/${natsPkiRoleName}"} \
|
bao write ${lib.escapeShellArg "${servicesPkiMountPath}/roles/${natsPkiRoleName}"} \
|
||||||
allowed_domains=${lib.escapeShellArg hyperhiveCfg.swarm.nats.domain} \
|
allowed_domains=${lib.escapeShellArg hyperhiveCfg.swarm.nats.domain} \
|
||||||
|
|
@ -3229,40 +3123,14 @@ in
|
||||||
token_policies=${lib.escapeShellArg natsPolicyName} \
|
token_policies=${lib.escapeShellArg natsPolicyName} \
|
||||||
display_name=${lib.escapeShellArg natsCn}
|
display_name=${lib.escapeShellArg natsCn}
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
|
|
||||||
# A SIXTH sibling, the nats unit's shape once per hive: each hive's
|
# A SIXTH sibling, the nats unit's shape once per hive: each hive's
|
||||||
# gateway-leaf role, its policy and its login role. The role allows the
|
# gateway-leaf role, its policy and its login role. The role allows the
|
||||||
# hive's domain and `*.` that domain, and no IP SANs or localhost.
|
# hive's domain and `*.` that domain, and no IP SANs or localhost.
|
||||||
systemd.services.swarm-bao-hive-leaf-policy = lib.mkIf haveGranter {
|
systemd.services.swarm-bao-hive-leaf-policy =
|
||||||
description = "write the per-hive gateway-leaf pki roles, bao policies and cert-auth roles";
|
granterPolicyUnit "write the per-hive gateway-leaf pki roles, bao policies and cert-auth roles"
|
||||||
after = [
|
(
|
||||||
"container@${cfg.machine}.service"
|
lib.concatMapStrings (obj: ''
|
||||||
"swarm-bao-controller-policy.service"
|
|
||||||
]
|
|
||||||
++ granterAfter;
|
|
||||||
requires = [ "swarm-bao-pki.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
path = [
|
|
||||||
baoCli
|
|
||||||
pkgs.coreutils
|
|
||||||
];
|
|
||||||
environment = granterEnv;
|
|
||||||
# Same unseal wait as its siblings above.
|
|
||||||
startLimitBurst = 2880;
|
|
||||||
startLimitIntervalSec = 90000;
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 30;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
${granterLogin}
|
|
||||||
''
|
|
||||||
+ lib.concatMapStrings (obj: ''
|
|
||||||
|
|
||||||
bao write ${lib.escapeShellArg "${servicesPkiMountPath}/roles/${obj.name}"} \
|
bao write ${lib.escapeShellArg "${servicesPkiMountPath}/roles/${obj.name}"} \
|
||||||
allowed_domains=${lib.escapeShellArg "${obj.domain},*.${obj.domain}"} \
|
allowed_domains=${lib.escapeShellArg "${obj.domain},*.${obj.domain}"} \
|
||||||
|
|
@ -3293,8 +3161,8 @@ in
|
||||||
allowed_common_names=${lib.escapeShellArg obj.cn} \
|
allowed_common_names=${lib.escapeShellArg obj.cn} \
|
||||||
token_policies=${lib.escapeShellArg obj.name} \
|
token_policies=${lib.escapeShellArg obj.name} \
|
||||||
display_name=${lib.escapeShellArg obj.cn}
|
display_name=${lib.escapeShellArg obj.cn}
|
||||||
'') hiveLeafIssuers;
|
'') hiveLeafIssuers
|
||||||
};
|
);
|
||||||
|
|
||||||
# The agent PKI mount: its root, its one role, the host's copy of the
|
# The agent PKI mount: its root, its one role, the host's copy of the
|
||||||
# root's certificate, and the listener's trust in it.
|
# root's certificate, and the listener's trust in it.
|
||||||
|
|
@ -3469,33 +3337,7 @@ in
|
||||||
# this writes the policy and stops with exit 0: nothing is broken, the UI
|
# this writes the policy and stops with exit 0: nothing is broken, the UI
|
||||||
# still takes a token, and a day of retries would change nothing.
|
# still takes a token, and a day of retries would change nothing.
|
||||||
# `swarm-bao-granter-role` restarts this unit each time it succeeds.
|
# `swarm-bao-granter-role` restarts this unit each time it succeeds.
|
||||||
systemd.services.swarm-bao-operator-viewer-policy = lib.mkIf haveGranter {
|
systemd.services.swarm-bao-operator-viewer-policy = granterPolicyUnit "write the bao UI's OIDC login: the operator viewer policy, the oidc config and its role" ''
|
||||||
description = "write the bao UI's OIDC login: the operator viewer policy, the oidc config and its role";
|
|
||||||
after = [
|
|
||||||
"container@${cfg.machine}.service"
|
|
||||||
"swarm-bao-controller-policy.service"
|
|
||||||
]
|
|
||||||
++ granterAfter;
|
|
||||||
requires = [ "swarm-bao-pki.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
path = [
|
|
||||||
baoCli
|
|
||||||
pkgs.coreutils
|
|
||||||
];
|
|
||||||
environment = granterEnv;
|
|
||||||
# Same unseal wait as its siblings above, for the reason stated there.
|
|
||||||
startLimitBurst = 2880;
|
|
||||||
startLimitIntervalSec = 90000;
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 30;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
${granterLogin}
|
|
||||||
|
|
||||||
printf '%s' ${lib.escapeShellArg operatorViewerPolicyText} |
|
printf '%s' ${lib.escapeShellArg operatorViewerPolicyText} |
|
||||||
bao policy write ${lib.escapeShellArg operatorViewerPolicyName} -
|
bao policy write ${lib.escapeShellArg operatorViewerPolicyName} -
|
||||||
|
|
@ -3538,7 +3380,6 @@ in
|
||||||
printf '%s' ${lib.escapeShellArg operatorViewerRole} |
|
printf '%s' ${lib.escapeShellArg operatorViewerRole} |
|
||||||
bao write auth/oidc/role/${lib.escapeShellArg operatorViewerPolicyName} -
|
bao write auth/oidc/role/${lib.escapeShellArg operatorViewerPolicyName} -
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
|
|
||||||
# The CA bind source is written at runtime by a host unit, so the
|
# The CA bind source is written at runtime by a host unit, so the
|
||||||
# container has to start after it — otherwise nspawn sets up a mount
|
# container has to start after it — otherwise nspawn sets up a mount
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue