Watch
0
0
Fork
You've already forked hyperhive
0

hive-tls: the root fetch presents the hive identity, as on main

On a hive fronting no swarm name, swarm-services-cert's token-less
GET pki/ca/pem presents baoHiveIdentity{Cert,Key}File again. The fetch
never logs in and grants nothing; the client certificate only completes
the store listener's mTLS. A hive host without the store therefore needs
no copy of the services-issuer pair.

The issue path, which logs in to pki/issue/swarm-services, still presents
only deploy.bao.servicesIssuerClient{Cert,Key}File.

module-eval-hive-tls: the root-fetch cases pin the hive identity and the
absence of the services-issuer pair (a fixture holding both, and one
holding only the hive identity); the issue-path case pins the pair on a
hive host and on a host without a hive; a gateway without the pair
evaluates and its issue path names both options.

Root-fetch identity: option (a), mara on PR #5002 (comment 92591).

Refs #4921
This commit is contained in:
atlas 2026-10-06 13:32:55 +02:00 • committed by mara
commit a66670be87
4 changed files with 143 additions and 103 deletions

View file

@ -39,10 +39,11 @@ from the store's own client CA, with the subject
and set both options, before the host's next deploy. and set both options, before the host's next deploy.
Without it, `hive-tls-resign.service` fails with a message naming both Without it, `hive-tls-resign.service` fails with a message naming both
options. The unit checks the identity before the leaf, so it fails even while a options, and so does `swarm-services-cert.service` on a hive fronting no
swarm name. The unit checks the identity before the leaf, so it fails even while a
valid leaf keeps the gateway up. The identity is the hive's alone: valid leaf keeps the gateway up. The identity is the hive's alone:
it issues this hive's leaf and nothing else, and it's never the identity a it issues this hive's leaf and fetches the store's root, and it's never the
swarm service uses. identity a swarm service uses.
**When it issues.** The unit runs at boot, on every deploy, and from **When it issues.** The unit runs at boot, on every deploy, and from
`hive-tls-resign.timer` once a day. It asks the store for a new leaf when `hive-tls-resign.timer` once a day. It asks the store for a new leaf when
@ -113,8 +114,10 @@ the services-issuer identity, calls
copies from. The store's role, not a key on the host, decides which names a copies from. The store's role, not a key on the host, decides which names a
gateway can serve. gateway can serve.
**Every gateway that serves the self-signed leaf needs the services-issuer **Every self-signed gateway that fronts a swarm name needs the
identity**, whether or not a hive runs on its host. It's a client certificate services-issuer identity**, whether or not a hive runs on its host. A hive
fronting none needs no copy of it: it fetches the store's root with its own
store identity, as below. It's a client certificate
from the store's own client CA, with the subject from the store's own client CA, with the subject
`deploy.bao.servicesIssuerCommonName` (`swarm-services-issuer` by default), `deploy.bao.servicesIssuerCommonName` (`swarm-services-issuer` by default),
and it's named by `services.hyperhive.deploy.bao.servicesIssuerClientCertFile` and it's named by `services.hyperhive.deploy.bao.servicesIssuerClientCertFile`
@ -125,11 +128,11 @@ every gateway host:
- On the host running the store, `swarm-bao-pki.service` mints it at - On the host running the store, `swarm-bao-pki.service` mints it at
`/var/lib/swarm-bao-pki/services-issuer.pem` and the two options default to `/var/lib/swarm-bao-pki/services-issuer.pem` and the two options default to
it. it.
- On every other gateway host, copy `services-issuer.pem` and - On every other gateway host fronting a swarm name, copy
`services-issuer-key.pem` from the store's host and set both options. `services-issuer.pem` and `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 A host fronting a swarm name without both options set still evaluates and deploys, and `swarm-services-cert.service` fails, naming
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 them. One that names files it can't read fails the same unit, naming the
paths. The old spellings, paths. The old spellings,
`deploy.hive-controller.tls.baoClientCertFile` and `baoClientKeyFile`, are `deploy.hive-controller.tls.baoClientCertFile` and `baoClientKeyFile`, are
@ -146,10 +149,12 @@ gateway can't serve a swarm service that runs behind another.
**The root's public certificate is a file, on every self-signed gateway host:** **The root's public certificate is a file, on every self-signed gateway host:**
`/var/lib/hive-tls/swarm-services-root.pem` (0644), written beside the `/var/lib/hive-tls/swarm-services-root.pem` (0644), written beside the
leaf it signed and folded into `trust-bundle.pem`. A host fronting no leaf it signed and folded into `trust-bundle.pem`. A hive fronting no
swarm name asks for no services leaf and reads the root alone, from the store's swarm name asks for no services leaf and reads the root alone, from the store's
`pki/ca/pem`, presenting the services-issuer identity for the handshake `pki/ca/pem`, presenting its own store identity
without logging in with it. With either file absent, (`deploy.hive-controller.tls.baoHiveIdentityCertFile` /
`baoHiveIdentityKeyFile`) for the handshake without logging in with it.
Every hive must hold one: without it, or with either file absent,
`swarm-services-cert.service` fails with a message naming both options. `swarm-services-cert.service` fails with a message naming both options.
On the host running On the host running
the store it's also at the store it's also at

View file

@ -116,7 +116,9 @@ let
# The hive's own store identity: its subject is # The hive's own store identity: its subject is
# `<hiveLeafCommonNamePrefix>-<hiveName>`, and its policy may issue from # `<hiveLeafCommonNamePrefix>-<hiveName>`, and its policy may issue from
# `hiveLeafRole` alone. Every hive must hold one. # `hiveLeafRole` alone. It also carries the root fetch's handshake. Every
# hive must hold one.
haveHiveIdentity = cfg.baoHiveIdentityCertFile != null && cfg.baoHiveIdentityKeyFile != null;
requireHiveIdentity = requireIdentity { requireHiveIdentity = requireIdentity {
holder = "this hive"; holder = "this hive";
what = "store identity"; what = "store identity";
@ -126,13 +128,12 @@ let
keyOption = "services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityKeyFile"; keyOption = "services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityKeyFile";
}; };
# The swarm-wide services-issuer identity `swarm-services-cert` presents, # The swarm-wide services-issuer identity `swarm-services-cert` logs in
# whether or not a hive runs here. Its subject is # with to issue the services leaf, whether or not a hive runs here. Its
# `servicesIssuerCommonName`, and its policy may issue from # subject is `servicesIssuerCommonName`, and its policy may issue from
# `pki/issue/swarm-services` alone. # `pki/issue/swarm-services` alone.
servicesIssuerCert = baoDeploy.servicesIssuerClientCertFile; servicesIssuerCert = baoDeploy.servicesIssuerClientCertFile;
servicesIssuerKey = baoDeploy.servicesIssuerClientKeyFile; servicesIssuerKey = baoDeploy.servicesIssuerClientKeyFile;
haveServicesIssuer = servicesIssuerCert != null && servicesIssuerKey != null;
requireServicesIssuer = requireIdentity { requireServicesIssuer = requireIdentity {
holder = "this host"; holder = "this host";
what = "services-issuer identity"; what = "services-issuer identity";
@ -244,8 +245,9 @@ let
BAO_CACERT = baoDeploy.serverCaFile; BAO_CACERT = baoDeploy.serverCaFile;
}; };
# The root-only fetch: the same store, server CA and services-issuer pair # The root-only fetch. Same store and server CA as `servicesCertEnvironment`,
# as `servicesCertEnvironment`, handed to curl. # but the hive's own identity: a host fronting no swarm name holds no
# services-issuer pair.
storeRootCurlTls = lib.escapeShellArgs ( storeRootCurlTls = lib.escapeShellArgs (
lib.optionals (baoDeploy.serverCaFile != null) [ lib.optionals (baoDeploy.serverCaFile != null) [
"--cacert" "--cacert"
@ -253,9 +255,9 @@ let
] ]
++ [ ++ [
"--cert" "--cert"
servicesIssuerCert cfg.baoHiveIdentityCertFile
"--key" "--key"
servicesIssuerKey cfg.baoHiveIdentityKeyFile
] ]
); );
@ -303,15 +305,17 @@ in
example = "/var/lib/swarm-bao-pki/hive-leaf.pem"; example = "/var/lib/swarm-bao-pki/hive-leaf.pem";
description = '' description = ''
This hive's own store identity. `hive-tls-resign` presents it to ask This hive's own store identity. `hive-tls-resign` presents it to ask
the secret store for the gateway leaf. the secret store for the gateway leaf, and `swarm-services-cert` on a
hive fronting no swarm name presents it for the handshake of the root
fetch.
Its subject has to be Its subject has to be
`<services.hyperhive.deploy.bao.hiveLeafCommonNamePrefix>-<hiveName>`; `<services.hyperhive.deploy.bao.hiveLeafCommonNamePrefix>-<hiveName>`;
that cert-auth role's policy may issue from this hive's gateway-leaf that cert-auth role's policy may issue from this hive's gateway-leaf
role and nothing else. role and nothing else.
Every hive with a self-signed gateway needs it: without it that unit Every hive with a self-signed gateway needs it: without it both units
fails, naming this option and fail, naming this option and
{option}`services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityKeyFile`. {option}`services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityKeyFile`.
On the host that runs the store a glue module supplies the leaf as a On the host that runs the store a glue module supplies the leaf as a
`mkDefault`; on every other host an operator places it. `mkDefault`; on every other host an operator places it.
@ -637,12 +641,13 @@ in
# bundle: every other hive's swarm-service names chain to it. # bundle: every other hive's swarm-service names chain to it.
# `ca/pem` takes no token; the TLS client certificate is the # `ca/pem` takes no token; the TLS client certificate is the
# store's listener's demand, not bao's, so this presents the # store's listener's demand, not bao's, so this presents the
# services-issuer pair and never logs in with it. Without a # hive's own identity and never logs in with it.
# readable pair the unit fails here, naming the options. # A hive without a readable identity fails here, naming the
# options: every hive must hold one.
if [ "$want_svc" = 0 ]; then if [ "$want_svc" = 0 ]; then
${ ${
if haveServicesIssuer then if haveHiveIdentity then
requireServicesIssuer "fetch the store's ${baoServicesPkiMount} root" requireHiveIdentity "fetch the store's ${baoServicesPkiMount} root"
+ '' + ''
echo "no swarm service domains configured — fetching only the store's pki root" echo "no swarm service domains configured — fetching only the store's pki root"
err="$(mktemp)" err="$(mktemp)"
@ -676,7 +681,7 @@ in
fi fi
exit 0'' exit 0''
else else
requireServicesIssuer "fetch the store's ${baoServicesPkiMount} root" requireHiveIdentity "fetch the store's ${baoServicesPkiMount} root"
} }
fi fi

View file

@ -1955,10 +1955,8 @@ in
default = null; default = null;
example = "/var/lib/swarm-bao-pki/services-issuer.pem"; example = "/var/lib/swarm-bao-pki/services-issuer.pem";
description = '' description = ''
Certificate `swarm-services-cert` presents to the store: to log in and Certificate `swarm-services-cert` logs in to the store with to ask for
ask for the swarm-services leaf the gateway serves, and for the the swarm-services leaf the gateway serves. Its subject must be
handshake of the root fetch on a host fronting no swarm name. Its
subject must be
{option}`services.hyperhive.deploy.bao.servicesIssuerCommonName`. {option}`services.hyperhive.deploy.bao.servicesIssuerCommonName`.
⚠️ Neither the reader's ⚠️ Neither the reader's
@ -1967,13 +1965,17 @@ in
`pki/issue/swarm-services` and nothing else, and it is the same on `pki/issue/swarm-services` and nothing else, and it is the same on
every gateway host, whether or not a hive runs there. every gateway host, whether or not a hive runs there.
Required on every host whose gateway serves the self-signed leaf. Required on every self-signed gateway host that fronts a swarm-service
Unset, the host evaluates and `swarm-services-cert` fails, naming name ({option}`services.hyperhive.swarm.localServiceDomains` not
both options. empty). Unset there, the host evaluates and `swarm-services-cert`
fails, naming both options. A host fronting none only fetches the
store's root, presenting
{option}`services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityCertFile`,
and needs no services-issuer pair.
./glue-bao-tls.nix points it at the leaf it mints on the store's host. ./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 On any other gateway host that needs it, it is a file the operator
from the store's host. A path, never a value. copies from the store's host. A path, never a value.
''; '';
}; };

View file

@ -54,6 +54,17 @@ let
}; };
noSvcFetch = noService.systemd.services.swarm-services-cert.script; noSvcFetch = noService.systemd.services.swarm-services-cert.script;
# The same hive holding its own identity and no services-issuer pair: the
# shape of every hive host without the store that fronts no swarm name.
noServiceNoPair = 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.hive-controller.tls.baoHiveIdentityCertFile = "/etc/pki/bao-hive.pem";
deploy.hive-controller.tls.baoHiveIdentityKeyFile = "/etc/pki/bao-hive-key.pem";
};
noPairFetch = noServiceNoPair.systemd.services.swarm-services-cert.script;
# The same hive with no store identity at all. # The same hive with no store identity at all.
noIdentity = hiveWithController { }; noIdentity = hiveWithController { };
noIdFetch = noIdentity.systemd.services.swarm-services-cert.script; noIdFetch = noIdentity.systemd.services.swarm-services-cert.script;
@ -83,6 +94,15 @@ let
lib.splitString "\nfi\n\n" (lib.last (lib.splitString ''if [ "$want_svc" = 0 ]; then'' script)) lib.splitString "\nfi\n\n" (lib.last (lib.splitString ''if [ "$want_svc" = 0 ]; then'' script))
); );
# Everything after that branch: the path that logs in and issues the leaf.
issuePath =
script:
lib.concatStringsSep "\nfi\n\n" (
lib.tail (
lib.splitString "\nfi\n\n" (lib.last (lib.splitString ''if [ "$want_svc" = 0 ]; then'' script))
)
);
units = allLocal.systemd.services; units = allLocal.systemd.services;
boot = units.swarm-services-cert; boot = units.swarm-services-cert;
caUnit = units.hive-tls-ca; caUnit = units.hive-tls-ca;
@ -210,55 +230,59 @@ let
&& lib.hasInfix ''cat "$svcroot" > "$bundle"'' noService.systemd.services.hive-tls-ca.script; && lib.hasInfix ''cat "$svcroot" > "$bundle"'' noService.systemd.services.hive-tls-ca.script;
} }
{ {
# The services-issuer pair, not the reader identity, whose policy reads # The hive's own identity, not its reader identity, whose policy reads
# every secret the hive is entitled to, and not the hive's own. # every secret the hive is entitled to, and not the services-issuer
name = "the root fetch reaches the store with the services-issuer pair and server CA"; # pair, which `noService` also holds. A hive holding no pair fetches
# the same way.
name = "the root fetch reaches the store with the hive's own identity and server CA, never the services-issuer pair";
ok = ok =
let
hiveTls =
"--cert ${lib.escapeShellArg "/etc/pki/bao-hive.pem"}"
+ " --key ${lib.escapeShellArg "/etc/pki/bao-hive-key.pem"}";
in
lib.hasInfix "--cacert ${lib.escapeShellArg "/etc/pki/bao-ca.pem"}" noSvcFetch lib.hasInfix "--cacert ${lib.escapeShellArg "/etc/pki/bao-ca.pem"}" noSvcFetch
&& lib.hasInfix ( && lib.hasInfix hiveTls (noSvcBranch noSvcFetch)
"--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)); && !(lib.hasInfix "/etc/pki/bao-services-issuer" (noSvcBranch noSvcFetch))
&& noServiceNoPair.services.hyperhive.deploy.bao.servicesIssuerClientCertFile == null
&& lib.hasInfix hiveTls (noSvcBranch noPairFetch)
&& lib.hasInfix "/v1/pki/ca/pem" (noSvcBranch noPairFetch)
&& !(lib.hasInfix "servicesIssuerClient" (noSvcBranch noPairFetch));
} }
{ {
# No identity to present: the unit fails, naming both options, rather # No identity to present: the unit fails, naming both options, rather
# than leaving the bundle without the root behind a green unit. The # than leaving the bundle without the root behind a green unit. The
# control is the same hive with the pair, whose branch fetches. # control is the same hive with an identity, whose branch fetches.
name = "a host fronting no swarm name with no services-issuer pair fails the unit, naming both options"; name = "a hive fronting no swarm name with no store identity fails the unit, naming the hive identity's options";
ok = ok =
noIdentity.services.hyperhive.swarm.localServiceDomains == [ ] noIdentity.services.hyperhive.swarm.localServiceDomains == [ ]
&& noIdentity.services.hyperhive.deploy.bao.servicesIssuerClientCertFile == null && noIdentity.services.hyperhive.deploy.hive-controller.tls.baoHiveIdentityCertFile == null
&& !(lib.hasInfix "/v1/pki/ca/pem" noIdFetch) && !(lib.hasInfix "/v1/pki/ca/pem" noIdFetch)
&& lib.hasInfix "servicesIssuerClientCertFile (unset)" (noSvcBranch noIdFetch) && lib.hasInfix "baoHiveIdentityCertFile (unset)" (noSvcBranch noIdFetch)
&& lib.hasInfix "servicesIssuerClientKeyFile (unset)" (noSvcBranch noIdFetch) && lib.hasInfix "baoHiveIdentityKeyFile (unset)" (noSvcBranch noIdFetch)
&& !(lib.hasInfix "servicesIssuerClient" (noSvcBranch noIdFetch))
&& lib.hasSuffix "exit 1" (lib.removeSuffix "\n" (noSvcBranch noIdFetch)) && lib.hasSuffix "exit 1" (lib.removeSuffix "\n" (noSvcBranch noIdFetch))
&& !(lib.hasInfix "exit 0" (noSvcBranch noIdFetch)) && !(lib.hasInfix "exit 0" (noSvcBranch noIdFetch))
&& !(lib.hasInfix "not staged" noIdFetch) && !(lib.hasInfix "not staged" noIdFetch)
&& lib.hasInfix "/v1/pki/ca/pem" (noSvcBranch noSvcFetch); && lib.hasInfix "/v1/pki/ca/pem" (noSvcBranch noSvcFetch);
} }
{ {
# A pair named but not on disk fails before curl, naming the paths. # An identity 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"; name = "a hive fronting no swarm name whose identity files are absent fails the unit, naming the paths";
ok = ok =
lib.hasInfix "for f in /etc/pki/bao-services-issuer.pem /etc/pki/bao-services-issuer-key.pem; do" ( lib.hasInfix "for f in /etc/pki/bao-hive.pem /etc/pki/bao-hive-key.pem; do" (noSvcBranch noSvcFetch)
noSvcBranch noSvcFetch
)
&& lib.hasInfix ''[ -r "$f" ] || missing="$missing $f"'' (noSvcBranch noSvcFetch) && lib.hasInfix ''[ -r "$f" ] || missing="$missing $f"'' (noSvcBranch noSvcFetch)
&& lib.hasInfix "cannot read$missing" (noSvcBranch noSvcFetch) && lib.hasInfix "cannot read$missing" (noSvcBranch noSvcFetch)
&& lib.hasInfix "servicesIssuerClientCertFile (/etc/pki/bao-services-issuer.pem)" ( && lib.hasInfix "baoHiveIdentityCertFile (/etc/pki/bao-hive.pem)" (noSvcBranch noSvcFetch)
noSvcBranch noSvcFetch && lib.hasInfix "baoHiveIdentityKeyFile (/etc/pki/bao-hive-key.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 # Each path presents one identity: the issue path the services-issuer
# by hand. The control is the hive host, whose gateway-leaf unit does # pair, on a hive host and on a host without a hive alike, and the root
# present the hive identity, so the scan can find one. # fetch the hive's own. The control for the scan is `hive-tls-resign`,
name = "on a host without a hive the swarm-services units present no hive identity, and the root fetch runs"; # which does present the hive identity.
name = "the issue path presents only the services-issuer pair, and the root fetch only the hive identity";
ok = ok =
let let
hiveRefs = [ hiveRefs = [
@ -266,33 +290,40 @@ let
"hive-leaf" "hive-leaf"
"/etc/pki/bao-hive" "/etc/pki/bao-hive"
]; ];
refsHive = refsHive = s: lib.any (r: lib.hasInfix r s) hiveRefs;
units: issuesWithPair =
lib.any ( m:
u: lib.any (r: lib.hasInfix r u.script || lib.hasInfix r (builtins.toJSON u.environment)) hiveRefs let
) units; u = m.systemd.services;
units = gatewayNoHive.systemd.services; path = issuePath u.swarm-services-cert.script;
s = units.swarm-services-cert; in
lib.hasInfix "for f in /etc/pki/bao-services-issuer.pem /etc/pki/bao-services-issuer-key.pem; do" path
&& !(refsHive path)
&&
lib.all
(
e:
e.BAO_CLIENT_CERT == "/etc/pki/bao-services-issuer.pem"
&& e.BAO_CLIENT_KEY == "/etc/pki/bao-services-issuer-key.pem"
)
[
u.swarm-services-cert.environment
u.swarm-services-cert-renew.environment
];
in in
!gatewayNoHive.services.hyperhive.deploy.hive-controller.enable issuesWithPair noService
&& gatewayNoHive.services.hyperhive.swarm.localServiceDomains == [ ] && issuesWithPair gatewayNoHive
&& !(refsHive [ && !gatewayNoHive.services.hyperhive.deploy.hive-controller.enable
s && refsHive (noSvcBranch noSvcFetch)
units.swarm-services-cert-renew && !(lib.hasInfix "/etc/pki/bao-services-issuer" (noSvcBranch noSvcFetch))
]) && refsHive noService.systemd.services.hive-tls-resign.script;
&& 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 ];
} }
{ {
# A host with no store and no pair placed is a supported shape: it # 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 # evaluates, and its issue path goes red. A hive among them still
# the pair placed, whose branch fetches, and the store's host, where # fetches the root. The controls are the same host without a hive with
# the glue supplies the pair. # the pair placed, and the store's host, where the glue supplies it.
name = "a self-signed gateway with no services-issuer pair evaluates, and its unit fails naming both options"; name = "a self-signed gateway with no services-issuer pair evaluates, and its issue path fails naming both options";
ok = ok =
let let
refused = refused =
@ -305,24 +336,21 @@ let
|| lib.hasInfix "servicesIssuerClientKeyFile" a.message || lib.hasInfix "servicesIssuerClientKeyFile" a.message
) )
) m.assertions; ) m.assertions;
redUnit = redIssue =
m: m:
let lib.hasInfix (
branch = noSvcBranch m.systemd.services.swarm-services-cert.script; "set services.hyperhive.deploy.bao.servicesIssuerClientCertFile (unset)"
in + " and services.hyperhive.deploy.bao.servicesIssuerClientKeyFile (unset)"
lib.hasInfix "services.hyperhive.deploy.bao.servicesIssuerClientCertFile (unset)" branch ) (issuePath m.systemd.services.swarm-services-cert.script);
&& 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 in
!(refused gatewayNoHiveNoPair) !(refused gatewayNoHiveNoPair)
&& !(refused noIdentity) && !(refused noIdentity)
&& redUnit gatewayNoHiveNoPair && !(refused noServiceNoPair)
&& redUnit noIdentity && redIssue gatewayNoHiveNoPair
&& !(redUnit gatewayNoHive) && redIssue noIdentity
&& lib.hasInfix "/v1/pki/ca/pem" ( && redIssue noServiceNoPair
noSvcBranch gatewayNoHive.systemd.services.swarm-services-cert.script && !(redIssue gatewayNoHive)
) && lib.hasInfix "/v1/pki/ca/pem" (noSvcBranch noPairFetch)
&& &&
allLocal.services.hyperhive.deploy.bao.servicesIssuerClientCertFile allLocal.services.hyperhive.deploy.bao.servicesIssuerClientCertFile
== "/var/lib/swarm-bao-pki/services-issuer.pem"; == "/var/lib/swarm-bao-pki/services-issuer.pem";