Watch
0
0
Fork
You've already forked hyperhive
0

hive-tls: a gateway host without the services-issuer pair evaluates and goes red at runtime

Drop the eval assertion b78190e1 added. It refused every self-signed
gateway host that does not run the store, which is the default hive
shape, and contradicts docs/swarm/secrets.md's supported no-store
deployment. The approved #4921 plan has such a host evaluate and fail
at runtime; `requireServicesIssuer` already exits 1 naming both
options, on the root-fetch branch and before issuing.

The module-eval case that pinned `hiveWithController { }` as refused
now pins it, and a hive-less gateway with no pair, as evaluating with
the unit's refusal in the script. The fixture pairs the assertion
forced into forge-placement, nats-tls and swarm-otel-identity are
reverted.

Refs #4921
This commit is contained in:
atlas 2026-10-06 11:53:17 +02:00 • committed by mara
commit 6a9c819136
7 changed files with 37 additions and 52 deletions

View file

@ -129,8 +129,9 @@ every gateway host:
`services-issuer-key.pem` from the store's host and set both options.
A host whose gateway serves the self-signed leaf without both options set
fails evaluation, naming them. One that names files it can't read fails
`swarm-services-cert.service`, naming the paths. The old spellings,
still evaluates and deploys, and `swarm-services-cert.service` fails, naming
them. One that names files it can't read fails the same unit, naming the
paths. The old spellings,
`deploy.hive-controller.tls.baoClientCertFile` and `baoClientKeyFile`, are
renames of these two: a config that still sets them evaluates with a warning
naming both paths.

View file

@ -333,30 +333,6 @@ in
};
config = lib.mkIf active {
assertions = [
{
assertion = haveServicesIssuer;
message = ''
services.hyperhive.gateway serves the self-signed leaf on this host,
which needs the swarm-services issuer's store identity: set both
services.hyperhive.deploy.bao.servicesIssuerClientCertFile
services.hyperhive.deploy.bao.servicesIssuerClientKeyFile
swarm-services-cert.service presents it to ask the swarm secret
store for the swarm-services leaf and to fetch the store's pki root.
Both default to the pair glue-bao-tls.nix mints when
services.hyperhive.deploy.bao.enable is true (the host that runs
the store). Otherwise copy services-issuer.pem and
services-issuer-key.pem from the store host's /var/lib/swarm-bao-pki/
and name them in those two options, or give the gateway a
certificate of its own (services.hyperhive.gateway.tls.certDir or
services.hyperhive.gateway.tls.acme.enable).
'';
}
];
# The state dir and the trust bundle. Never waits on the store: the
# store's container is ordered after this unit, which writes the
# bundle it bind-mounts, so the leaf is `hive-tls-resign`'s.

View file

@ -1967,8 +1967,9 @@ in
`pki/issue/swarm-services` and nothing else, and it is the same on
every gateway host, whether or not a hive runs there.
Required on every host whose gateway serves the self-signed leaf;
unset fails evaluation.
Required on every host whose gateway serves the self-signed leaf.
Unset, the host evaluates and `swarm-services-cert` fails, naming
both options.
./glue-bao-tls.nix points it at the leaf it mints on the store's host.
On a gateway host without the store, it is a file the operator copies

View file

@ -73,8 +73,6 @@ let
deploy.forgejo.ci.jobTimeout = "2h";
deploy.bao.ciRunnerClientCertFile = "/etc/pki/bao-ci-runner.pem";
deploy.bao.ciRunnerClientKeyFile = "/etc/pki/bao-ci-runner-key.pem";
deploy.bao.servicesIssuerClientCertFile = "/etc/pki/bao-services-issuer.pem";
deploy.bao.servicesIssuerClientKeyFile = "/etc/pki/bao-services-issuer-key.pem";
};
# The old name alone, with no store identity placed and none defaulted.
ciUnderForgeNoIdentity = hive {
@ -90,8 +88,6 @@ let
swarm.forge.ci.package = pkgs.hello;
deploy.bao.ciRunnerClientCertFile = "/etc/pki/bao-ci-runner.pem";
deploy.bao.ciRunnerClientKeyFile = "/etc/pki/bao-ci-runner-key.pem";
deploy.bao.servicesIssuerClientCertFile = "/etc/pki/bao-services-issuer.pem";
deploy.bao.servicesIssuerClientKeyFile = "/etc/pki/bao-services-issuer-key.pem";
};
runsForge = m: m.services.hyperhive.deploy.forgejo.enable && m.containers ? hive-forge;

View file

@ -288,9 +288,11 @@ let
&& refsHive [ noService.systemd.services.hive-tls-resign ];
}
{
# The control is the same host with the pair placed, and the store's
# host, where the glue supplies it.
name = "a self-signed gateway with no services-issuer pair fails evaluation, naming both options";
# A host with no store and no pair placed is a supported shape: it
# evaluates, and its unit goes red. The control is the same host with
# the pair placed, whose branch fetches, and the store's host, where
# the glue supplies the pair.
name = "a self-signed gateway with no services-issuer pair evaluates, and its unit fails naming both options";
ok =
let
refused =
@ -298,15 +300,29 @@ let
lib.any (
a:
!a.assertion
&& lib.hasInfix "services.hyperhive.deploy.bao.servicesIssuerClientCertFile" a.message
&& lib.hasInfix "services.hyperhive.deploy.bao.servicesIssuerClientKeyFile" a.message
&& (
lib.hasInfix "servicesIssuerClientCertFile" a.message
|| lib.hasInfix "servicesIssuerClientKeyFile" a.message
)
) m.assertions;
redUnit =
m:
let
branch = noSvcBranch m.systemd.services.swarm-services-cert.script;
in
refused gatewayNoHiveNoPair
&& refused noIdentity
&& !(refused gatewayNoHive)
&& !(refused noService)
&& !(refused allLocal)
lib.hasInfix "services.hyperhive.deploy.bao.servicesIssuerClientCertFile (unset)" branch
&& lib.hasInfix "services.hyperhive.deploy.bao.servicesIssuerClientKeyFile (unset)" branch
&& lib.hasSuffix "exit 1" (lib.removeSuffix "\n" branch)
&& !(lib.hasInfix "/v1/pki/ca/pem" branch);
in
!(refused gatewayNoHiveNoPair)
&& !(refused noIdentity)
&& redUnit gatewayNoHiveNoPair
&& redUnit noIdentity
&& !(redUnit gatewayNoHive)
&& lib.hasInfix "/v1/pki/ca/pem" (
noSvcBranch gatewayNoHive.systemd.services.swarm-services-cert.script
)
&&
allLocal.services.hyperhive.deploy.bao.servicesIssuerClientCertFile
== "/var/lib/swarm-bao-pki/services-issuer.pem";

View file

@ -67,16 +67,14 @@ let
# address set by hand: what every hive but one in a multi-host swarm looks
# like. The controller is on too, since it may run away from the queue.
#
# The forge's secret, the controller's store identity and the gateway's
# services-issuer pair are what a hive away from authelia and the store
# already has to be handed, and none is an address; without them this hive
# would fail assertions that have nothing to do with the queue.
# The forge's secret and the controller's store identity are what a hive
# away from authelia and the store already has to be handed, and none is an
# address; without them this hive would fail assertions that have nothing to
# do with the queue.
remoteSecrets = {
deploy.forgejo.sso.clientSecretFile = "/var/lib/forgejo-oidc/by-hand.secret";
deploy.swarm-controller.baoClientCertFile = "/var/lib/swarm-controller/bao-client.pem";
deploy.swarm-controller.baoClientKeyFile = "/var/lib/swarm-controller/bao-client-key.pem";
deploy.bao.servicesIssuerClientCertFile = "/etc/pki/bao-services-issuer.pem";
deploy.bao.servicesIssuerClientKeyFile = "/etc/pki/bao-services-issuer-key.pem";
};
remote = hiveWithController (
lib.recursiveUpdate remoteSecrets { deploy.swarm-controller.enable = true; }

View file

@ -27,12 +27,9 @@ let
# hive's telemetry with nothing to push authenticated with, which is the
# already-supported degrade `haveCollectorSecret` names above the module's
# `let`. What this fixture is for is checking the reading unit itself does
# not render, rather than rendering with an env var nothing filled in. Its
# gateway has a certificate of its own: a self-signed one needs the
# services-issuer identity.
# not render, rather than rendering with an env var nothing filled in.
otelNoIdentity = hive {
deploy.swarm-otel.enable = true;
gateway.tls.certDir = "/var/lib/acme/t.local";
swarm.authelia.url = "https://auth.example.invalid";
deploy.forgejo.sso.clientSecretFile = "/var/lib/forgejo-oidc/by-hand.secret";
};