hive-tls: the gateway leaf uses the services-issuer identity, not a hive's
swarm-services-cert issues the swarm-services leaf a self-signed gateway
serves, and on a host fronting no swarm name fetches the store's pki root.
It is gated on the gateway, not on a hive, yet its leaf pair was named
under deploy.hive-controller.tls and defaulted from the hive reader's cert
directory, and the root fetch presented the hive's own identity. A gateway
host with no hive had no such identity, so that branch was red by
construction.
- The pair moves to deploy.bao.servicesIssuerClient{Cert,Key}File, beside
the store's other host-unit readers, and glue-bao-tls.nix defaults it on
the store's host from the leaf it already mints. The old
deploy.hive-controller.tls.baoClient{Cert,Key}File paths are
mkRenamedOptionModule aliases. glue-services-issuer-bao-identity.nix,
which derived the default from deploy.bao.clientCertFile, is gone.
- The no-swarm-name root fetch presents the services-issuer pair. The hive
identity is now only hive-tls-resign's.
- A self-signed gateway with no pair fails evaluation, naming both options.
A pair named but unreadable still fails the unit, naming the paths.
Refs #4921
This commit is contained in:
parent
c3ef18ad09
commit
5761398d60
13 changed files with 319 additions and 173 deletions
|
|
@ -1219,7 +1219,9 @@ let
|
|||
&& t.baoHiveIdentityKeyFile == "/var/lib/swarm-bao-pki/hive-leaf-key.pem"
|
||||
# Its own leaf, not the reader's or the services issuer's.
|
||||
&& t.baoHiveIdentityCertFile != baoGrantHere.services.hyperhive.deploy.bao.clientCertFile
|
||||
&& t.baoHiveIdentityCertFile != t.baoClientCertFile;
|
||||
&&
|
||||
t.baoHiveIdentityCertFile
|
||||
!= baoGrantHere.services.hyperhive.deploy.bao.servicesIssuerClientCertFile;
|
||||
}
|
||||
{
|
||||
name = "a gateway-leaf role prefix outside swarm-* is refused, naming the option";
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ 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 {
|
||||
|
|
@ -88,6 +90,8 @@ 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;
|
||||
|
|
|
|||
|
|
@ -41,11 +41,14 @@ let
|
|||
};
|
||||
|
||||
# Fronting none of the swarm's names, reading a store it does not run,
|
||||
# with the reader identity and the hive's own identity placed by hand.
|
||||
# with the reader identity, the services-issuer pair and the hive's own
|
||||
# identity placed by hand.
|
||||
noService = hiveWithController {
|
||||
deploy.bao.clientCertFile = "/etc/pki/bao-client.pem";
|
||||
deploy.bao.clientKeyFile = "/etc/pki/bao-client-key.pem";
|
||||
deploy.bao.serverCaFile = "/etc/pki/bao-ca.pem";
|
||||
deploy.bao.servicesIssuerClientCertFile = "/etc/pki/bao-services-issuer.pem";
|
||||
deploy.bao.servicesIssuerClientKeyFile = "/etc/pki/bao-services-issuer-key.pem";
|
||||
deploy.hive-controller.tls.baoHiveIdentityCertFile = "/etc/pki/bao-hive.pem";
|
||||
deploy.hive-controller.tls.baoHiveIdentityKeyFile = "/etc/pki/bao-hive-key.pem";
|
||||
};
|
||||
|
|
@ -55,6 +58,23 @@ let
|
|||
noIdentity = hiveWithController { };
|
||||
noIdFetch = noIdentity.systemd.services.swarm-services-cert.script;
|
||||
|
||||
# A gateway on a host with no hive and no store, fronting no swarm name,
|
||||
# with the services-issuer pair placed by hand; and the same host without it.
|
||||
gatewayNoHive = hive {
|
||||
gateway.enable = true;
|
||||
deploy.bao.serverCaFile = "/etc/pki/bao-ca.pem";
|
||||
deploy.bao.servicesIssuerClientCertFile = "/etc/pki/bao-services-issuer.pem";
|
||||
deploy.bao.servicesIssuerClientKeyFile = "/etc/pki/bao-services-issuer-key.pem";
|
||||
};
|
||||
gatewayNoHiveNoPair = hive { gateway.enable = true; };
|
||||
|
||||
# The store's host with the pair still named under its old path.
|
||||
renamedPair = hiveWithController {
|
||||
deploy.singleHostSwarm = true;
|
||||
deploy.hive-controller.tls.baoClientCertFile = "/etc/pki/old-issuer.pem";
|
||||
deploy.hive-controller.tls.baoClientKeyFile = "/etc/pki/old-issuer-key.pem";
|
||||
};
|
||||
|
||||
# The `want_svc=0` branch of a rendered script, up to the `fi` that closes it (the
|
||||
# only one followed by a blank line).
|
||||
noSvcBranch =
|
||||
|
|
@ -190,42 +210,124 @@ let
|
|||
&& lib.hasInfix ''cat "$svcroot" > "$bundle"'' noService.systemd.services.hive-tls-ca.script;
|
||||
}
|
||||
{
|
||||
# The hive's own identity, not its reader identity: the reader's policy
|
||||
# reads every secret the hive is entitled to.
|
||||
name = "the root fetch reaches the store with the hive's own identity and server CA";
|
||||
# The services-issuer pair, not the reader identity, whose policy reads
|
||||
# every secret the hive is entitled to, and not the hive's own.
|
||||
name = "the root fetch reaches the store with the services-issuer pair and server CA";
|
||||
ok =
|
||||
lib.hasInfix "--cacert ${lib.escapeShellArg "/etc/pki/bao-ca.pem"}" noSvcFetch
|
||||
&& lib.hasInfix (
|
||||
"--cert ${lib.escapeShellArg "/etc/pki/bao-hive.pem"}"
|
||||
+ " --key ${lib.escapeShellArg "/etc/pki/bao-hive-key.pem"}"
|
||||
"--cert ${lib.escapeShellArg "/etc/pki/bao-services-issuer.pem"}"
|
||||
+ " --key ${lib.escapeShellArg "/etc/pki/bao-services-issuer-key.pem"}"
|
||||
) noSvcFetch
|
||||
&& !(lib.hasInfix "/etc/pki/bao-client.pem" (noSvcBranch noSvcFetch));
|
||||
&& !(lib.hasInfix "/etc/pki/bao-client.pem" (noSvcBranch noSvcFetch))
|
||||
&& !(lib.hasInfix "/etc/pki/bao-hive" (noSvcBranch noSvcFetch));
|
||||
}
|
||||
{
|
||||
# No identity to present: the unit fails, naming both options, rather
|
||||
# than leaving the bundle without the root behind a green unit. The
|
||||
# control is the same hive with an identity, whose branch fetches.
|
||||
name = "a hive fronting no swarm name with no store identity fails the unit, naming both options";
|
||||
# control is the same hive with the pair, whose branch fetches.
|
||||
name = "a host fronting no swarm name with no services-issuer pair fails the unit, naming both options";
|
||||
ok =
|
||||
noIdentity.services.hyperhive.swarm.localServiceDomains == [ ]
|
||||
&& noIdentity.services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityCertFile == null
|
||||
&& noIdentity.services.hyperhive.deploy.bao.servicesIssuerClientCertFile == null
|
||||
&& !(lib.hasInfix "/v1/pki/ca/pem" noIdFetch)
|
||||
&& lib.hasInfix "baoHiveIdentityCertFile (unset)" (noSvcBranch noIdFetch)
|
||||
&& lib.hasInfix "baoHiveIdentityKeyFile (unset)" (noSvcBranch noIdFetch)
|
||||
&& lib.hasInfix "servicesIssuerClientCertFile (unset)" (noSvcBranch noIdFetch)
|
||||
&& lib.hasInfix "servicesIssuerClientKeyFile (unset)" (noSvcBranch noIdFetch)
|
||||
&& lib.hasSuffix "exit 1" (lib.removeSuffix "\n" (noSvcBranch noIdFetch))
|
||||
&& !(lib.hasInfix "exit 0" (noSvcBranch noIdFetch))
|
||||
&& !(lib.hasInfix "not staged" noIdFetch)
|
||||
&& lib.hasInfix "/v1/pki/ca/pem" (noSvcBranch noSvcFetch);
|
||||
}
|
||||
{
|
||||
# An identity named but not on disk fails before curl, naming the paths.
|
||||
name = "a hive fronting no swarm name whose identity files are absent fails the unit, naming the paths";
|
||||
# A pair named but not on disk fails before curl, naming the paths.
|
||||
name = "a host fronting no swarm name whose services-issuer files are absent fails the unit, naming the paths";
|
||||
ok =
|
||||
lib.hasInfix "for f in /etc/pki/bao-hive.pem /etc/pki/bao-hive-key.pem; do" (noSvcBranch noSvcFetch)
|
||||
lib.hasInfix "for f in /etc/pki/bao-services-issuer.pem /etc/pki/bao-services-issuer-key.pem; do" (
|
||||
noSvcBranch noSvcFetch
|
||||
)
|
||||
&& lib.hasInfix ''[ -r "$f" ] || missing="$missing $f"'' (noSvcBranch noSvcFetch)
|
||||
&& lib.hasInfix "cannot read$missing" (noSvcBranch noSvcFetch)
|
||||
&& lib.hasInfix "baoHiveIdentityCertFile (/etc/pki/bao-hive.pem)" (noSvcBranch noSvcFetch)
|
||||
&& lib.hasInfix "baoHiveIdentityKeyFile (/etc/pki/bao-hive-key.pem)" (noSvcBranch noSvcFetch);
|
||||
&& lib.hasInfix "servicesIssuerClientCertFile (/etc/pki/bao-services-issuer.pem)" (
|
||||
noSvcBranch noSvcFetch
|
||||
)
|
||||
&& lib.hasInfix "servicesIssuerClientKeyFile (/etc/pki/bao-services-issuer-key.pem)" (
|
||||
noSvcBranch noSvcFetch
|
||||
);
|
||||
}
|
||||
{
|
||||
# A gateway host with no hive, fronting no swarm name, the pair placed
|
||||
# by hand. The control is the hive host, whose gateway-leaf unit does
|
||||
# present the hive identity, so the scan can find one.
|
||||
name = "on a host without a hive the swarm-services units present no hive identity, and the root fetch runs";
|
||||
ok =
|
||||
let
|
||||
hiveRefs = [
|
||||
"baoHiveIdentity"
|
||||
"hive-leaf"
|
||||
"/etc/pki/bao-hive"
|
||||
];
|
||||
refsHive =
|
||||
units:
|
||||
lib.any (
|
||||
u: lib.any (r: lib.hasInfix r u.script || lib.hasInfix r (builtins.toJSON u.environment)) hiveRefs
|
||||
) units;
|
||||
units = gatewayNoHive.systemd.services;
|
||||
s = units.swarm-services-cert;
|
||||
in
|
||||
!gatewayNoHive.services.hyperhive.deploy.hive-controller.enable
|
||||
&& gatewayNoHive.services.hyperhive.swarm.localServiceDomains == [ ]
|
||||
&& !(refsHive [
|
||||
s
|
||||
units.swarm-services-cert-renew
|
||||
])
|
||||
&& lib.hasInfix "/v1/pki/ca/pem" (noSvcBranch s.script)
|
||||
&& lib.hasInfix "--cert ${lib.escapeShellArg "/etc/pki/bao-services-issuer.pem"}" (
|
||||
noSvcBranch s.script
|
||||
)
|
||||
&& s.environment.BAO_CLIENT_CERT == "/etc/pki/bao-services-issuer.pem"
|
||||
&& 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";
|
||||
ok =
|
||||
let
|
||||
refused =
|
||||
m:
|
||||
lib.any (
|
||||
a:
|
||||
!a.assertion
|
||||
&& lib.hasInfix "services.hyperhive.deploy.bao.servicesIssuerClientCertFile" a.message
|
||||
&& lib.hasInfix "services.hyperhive.deploy.bao.servicesIssuerClientKeyFile" a.message
|
||||
) m.assertions;
|
||||
in
|
||||
refused gatewayNoHiveNoPair
|
||||
&& refused noIdentity
|
||||
&& !(refused gatewayNoHive)
|
||||
&& !(refused noService)
|
||||
&& !(refused allLocal)
|
||||
&&
|
||||
allLocal.services.hyperhive.deploy.bao.servicesIssuerClientCertFile
|
||||
== "/var/lib/swarm-bao-pki/services-issuer.pem";
|
||||
}
|
||||
{
|
||||
# The old path's value reaches the new option over the store glue's
|
||||
# `mkDefault`, and the unit presents it. The control is the same store
|
||||
# host on its defaults.
|
||||
name = "the services-issuer pair set under deploy.hive-controller.tls reaches deploy.bao and the unit";
|
||||
ok =
|
||||
let
|
||||
b = renamedPair.services.hyperhive.deploy.bao;
|
||||
env = renamedPair.systemd.services.swarm-services-cert.environment;
|
||||
in
|
||||
b.servicesIssuerClientCertFile == "/etc/pki/old-issuer.pem"
|
||||
&& b.servicesIssuerClientKeyFile == "/etc/pki/old-issuer-key.pem"
|
||||
&& env.BAO_CLIENT_CERT == "/etc/pki/old-issuer.pem"
|
||||
&& env.BAO_CLIENT_KEY == "/etc/pki/old-issuer-key.pem"
|
||||
&&
|
||||
allLocal.systemd.services.swarm-services-cert.environment.BAO_CLIENT_CERT
|
||||
== "/var/lib/swarm-bao-pki/services-issuer.pem";
|
||||
}
|
||||
{
|
||||
# The fetch retries against a sealed store; a gateway `Requires=` on it
|
||||
|
|
@ -469,7 +571,9 @@ let
|
|||
&& leafUnit.environment.BAO_CLIENT_CERT == "/var/lib/swarm-bao-pki/hive-leaf.pem"
|
||||
&& leafUnit.environment.BAO_CLIENT_KEY == "/var/lib/swarm-bao-pki/hive-leaf-key.pem"
|
||||
&& t.baoHiveIdentityCertFile == leafUnit.environment.BAO_CLIENT_CERT
|
||||
&& leafUnit.environment.BAO_CLIENT_CERT != t.baoClientCertFile
|
||||
&&
|
||||
leafUnit.environment.BAO_CLIENT_CERT
|
||||
!= allLocal.services.hyperhive.deploy.bao.servicesIssuerClientCertFile
|
||||
&& leafUnit.environment.BAO_CLIENT_CERT != allLocal.services.hyperhive.deploy.bao.clientCertFile;
|
||||
}
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,14 +67,16 @@ 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 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.
|
||||
# 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.
|
||||
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; }
|
||||
|
|
|
|||
|
|
@ -27,9 +27,12 @@ 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.
|
||||
# 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.
|
||||
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";
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue