hive-tls: issue the gateway leaf from bao with a per-hive identity
Every hive gets its own store identity (CN
<deploy.bao.hiveLeafCommonNamePrefix>-<hive>) and its own role on the
existing pki mount (<deploy.bao.hiveLeafPkiRolePrefix>-<hive>), whose
allowed_domains is the hive's domain and *.<domain>. The policy grants
update on that one issue path. swarm-bao-hive-leaf-policy writes role,
policy and cert-auth role for every hive in swarm.hives; the store's host
mints its own hive's identity in glue-bao-tls.nix and a new glue file
points deploy.hive-controller.tls.baoHiveIdentity{Cert,Key}File at it.
Hives on other hosts place it by hand. swarm.nix reserves the composed CN.
hive-tls-ca no longer generates a hive CA or signs a leaf: caGenScript,
signLeafScript/signHiveLeaf and the adoption block are gone, ca-key.pem
is deleted where it exists, and the unit only assembles trust-bundle.pem.
The retired ca.pem/ca-previous.pem stay in the bundle so leaves they
signed keep verifying.
hive-tls-resign becomes the bao issuance: at boot, on deploy and from a
daily timer it re-issues when the leaf is missing, past half the role's
lifetime, missing a name, or not chained to the store's pki root. Nothing
orders the gateway after it, so a valid leaf on disk never waits on the
store; a failed renewal leaves the leaf in place. A missing identity
fails the unit naming both options, as does the root fetch on a hive
fronting no swarm name, which now presents this identity instead of the
reader cert.
caValidityDays and leafValidityDays are removed (both spellings), since
nothing reads them.
Refs #4588
This commit is contained in:
parent
52037133e2
commit
5526daab97
16 changed files with 859 additions and 628 deletions
|
|
@ -106,6 +106,14 @@ let
|
|||
swarm.hives.qr-other.domain = "q.t.local";
|
||||
};
|
||||
|
||||
# The per-hive gateway-leaf subject, composed the same way.
|
||||
hiveNamedAfterHiveLeafSubject = hive {
|
||||
deploy.swarm-otel.enable = false;
|
||||
deploy.bao.hiveLeafCommonNamePrefix = "hl";
|
||||
swarm.hives.other.domain = "o.t.local";
|
||||
swarm.hives.hl-other.domain = "hl.t.local";
|
||||
};
|
||||
|
||||
hiveNameWithComposedWord = hive {
|
||||
deploy.swarm-otel.enable = false;
|
||||
swarm.hives."h1-agent".domain = "a.t.local";
|
||||
|
|
@ -203,6 +211,17 @@ let
|
|||
a: !a.assertion && lib.hasInfix "'qr-other'" a.message
|
||||
) hiveNamedAfterPerHiveReaderSubject.assertions;
|
||||
}
|
||||
{
|
||||
# A hive taking this spelling would present a leaf hive `other`'s
|
||||
# gateway-leaf role accepts, and could ask the store for that hive's
|
||||
# certificate. The control is the legal roster below.
|
||||
name = "a hive named after another hive's gateway-leaf subject is refused";
|
||||
ok =
|
||||
equalityGuardFired hiveNamedAfterHiveLeafSubject
|
||||
&& lib.any (
|
||||
a: !a.assertion && lib.hasInfix "'hl-other'" a.message
|
||||
) hiveNamedAfterHiveLeafSubject.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