swarm-bao, swarm: give the secret publisher its own subject, reserved like the controller's
The unit that will copy authelia's minted OIDC client secrets into the store needs an identity of its own. Not the controller's: that grant includes rewriting every hive's policy and login role, which a unit whose whole job is copying one file has no business holding. The subject joins `certAuthCns`, so it is unrepresentable as a hive name for the same reason the controller's is — cert auth trusts the CA, and a hive's own leaf carries its name as the CN. The module-eval case collides with the SECOND list element and leaves the controller's subject at its default. A list with one consulted element and one dead one is indistinguishable from the first element's case, so without this the addition could be inert and nothing would say so. Refs #3853
This commit is contained in:
parent
395ecbdf41
commit
e8ff633c6b
3 changed files with 47 additions and 1 deletions
|
|
@ -554,6 +554,29 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
secretPublisherCommonName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "swarm-secret-publisher";
|
||||
example = "swarm-secret-publisher.svc";
|
||||
description = ''
|
||||
Subject the store's secret-publisher cert-auth role accepts — the
|
||||
identity that copies authelia's minted OIDC client secrets into the
|
||||
store so a hive that does not host authelia can read its own.
|
||||
|
||||
A **second** identity rather than reuse of
|
||||
{option}`services.hyperhive.deploy.bao.controllerCommonName`: the
|
||||
controller's grant includes rewriting every hive's policy and login
|
||||
role, which is not something a unit whose whole job is copying one file
|
||||
should be able to do. This one's grant is `create`/`update` under the
|
||||
hive prefix and nothing else.
|
||||
|
||||
⚠️ Same collision as its sibling above, and the same answer: ./swarm.nix
|
||||
feeds this value into the guard on
|
||||
{option}`services.hyperhive.swarm.hives`, so a hive named after it fails
|
||||
evaluation rather than silently receiving the publisher's grants.
|
||||
'';
|
||||
};
|
||||
|
||||
serverCaFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,10 @@ let
|
|||
# every role added beside these widens what a hive name must not collide
|
||||
# with. A hive's own leaf carries its name as the CN, so a hive named after
|
||||
# one of these presents a certificate that role accepts.
|
||||
certAuthCns = [ deployCfg.bao.controllerCommonName ];
|
||||
certAuthCns = [
|
||||
deployCfg.bao.controllerCommonName
|
||||
deployCfg.bao.secretPublisherCommonName
|
||||
];
|
||||
|
||||
# Public hostnames of the swarm's own services, in declaration order.
|
||||
# `serviceDomains` below is this set sorted + deduplicated.
|
||||
|
|
|
|||
|
|
@ -539,6 +539,15 @@ let
|
|||
deploy.bao.controllerCommonName = "ctl";
|
||||
};
|
||||
|
||||
# The reserved subjects are a LIST, and a list with one consulted element and
|
||||
# one dead one looks identical from the first element's case. This fixture
|
||||
# collides with the SECOND, leaving the controller's at its default.
|
||||
hiveNamedAfterPublisherSubject = hive {
|
||||
deploy.swarm-otel.enable = false;
|
||||
deploy.bao.secretPublisherCommonName = "pubctl";
|
||||
swarm.hives.pubctl.domain = "p.t.local";
|
||||
};
|
||||
|
||||
hiveNameWithComposedWord = hive {
|
||||
deploy.swarm-otel.enable = false;
|
||||
swarm.hives."h1-agent".domain = "a.t.local";
|
||||
|
|
@ -565,6 +574,17 @@ let
|
|||
equalityGuardFired hiveNamedAfterCertSubject
|
||||
&& lib.any (a: !a.assertion && lib.hasInfix "'ctl'" a.message) hiveNamedAfterCertSubject.assertions;
|
||||
}
|
||||
{
|
||||
# Every cert-auth subject is reserved, not just the first one in the
|
||||
# list. Without this case the second element could be dead and the case
|
||||
# above would still pass.
|
||||
name = "a hive named after the secret publisher's subject is refused too";
|
||||
ok =
|
||||
equalityGuardFired hiveNamedAfterPublisherSubject
|
||||
&& lib.any (
|
||||
a: !a.assertion && lib.hasInfix "'pubctl'" a.message
|
||||
) hiveNamedAfterPublisherSubject.assertions;
|
||||
}
|
||||
{
|
||||
# Without this the case above proves nothing: an arm that fires for every
|
||||
# roster is not a guard, and `hives` is non-empty in both fixtures.
|
||||
|
|
|
|||
Loading…
Reference in a new issue