swarm CA: retire the host-held root CA, the store holds the only anchor
The secret store's pki root issues every hive's gateway leaf and the
swarm's service names, so the root swarm-ca.service generated on the
host anchors nothing and its key is a secret outside the store.
- swarm-ca.nix is gone: swarm-ca.service, root.pem and root-key.pem,
and the swarm.ca.{autoConfigure,stateDir,validityDays} options. A
definition of any of them fails evaluation with a removal message
(swarm-ca-removed.nix), and a tmpfiles rule deletes /var/lib/swarm-ca
on every host. singleHostSwarm no longer sets a swarm.* option.
- hive-tls-ca drops the $root slot: trust-bundle.pem holds the store's
pki root and a hive CA's public ca.pem/ca-previous.pem only.
- hivectl peer-config no longer prints the scp line for the swarm root;
the store's pki root is the one step.
- The gateway's cert import no longer stands a hive leaf or a throwaway
in for a missing swarm-services leaf where it Requires= the issuing
unit: it fails, naming swarm-services-cert.service. The stand-in stays
where the gateway does not wait (no swarm name, or the store's UI
only, whose passthrough must start with the store sealed).
Comments and docs that named swarm-ca.nix, swarm.ca.* or the host root
now name the store's pki root.
Refs #4588
This commit is contained in:
parent
5d6ebda3e8
commit
93f1a76ea7
22 changed files with 305 additions and 395 deletions
|
|
@ -597,17 +597,15 @@ let
|
|||
#
|
||||
# The mount's own root is generated into it by the bootstrap unit below and
|
||||
# its private key never leaves — `root/generate/internal` keeps it inside
|
||||
# the store, which is the whole reason the mount exists rather than another
|
||||
# key beside ./swarm-ca.nix's.
|
||||
# the store.
|
||||
#
|
||||
# An option rather than a literal because ./hive-tls.nix issues through it
|
||||
# and has to spell it the same way.
|
||||
servicesPkiMountPath = baoDeploy.servicesPkiMountPath;
|
||||
|
||||
# Subject of the root generated into that mount. A label for a human reading
|
||||
# a chain, not an identity anything authenticates against — same fall-through
|
||||
# ./swarm-ca.nix:29-37 uses, and for the same reason: a hive that has set
|
||||
# neither a swarm name nor a domain must still evaluate.
|
||||
# a chain, not an identity anything authenticates against. Falls through so
|
||||
# a hive that has set neither a swarm name nor a domain still evaluates.
|
||||
servicesPkiRootLabel =
|
||||
if hyperhiveCfg.swarm.name != null then
|
||||
hyperhiveCfg.swarm.name
|
||||
|
|
@ -624,11 +622,9 @@ let
|
|||
servicesPkiRootDir = "/var/lib/swarm-bao-services-pki";
|
||||
servicesPkiRootFile = "${servicesPkiRootDir}/services-root.pem";
|
||||
|
||||
# ~30y, matching ./swarm-ca.nix's root rather than its services sub-CA. This
|
||||
# is an ANCHOR: an operator adds it to a browser's trust store by hand, and
|
||||
# every rotation is a manual re-trust on every machine that holds it. The
|
||||
# sub-CA's short window bought cheap rotation because the root above it
|
||||
# absorbed the churn; nothing sits above this one.
|
||||
# ~30y. This is an ANCHOR: an operator adds it to a browser's trust store by
|
||||
# hand, and every rotation is a manual re-trust on every machine that holds
|
||||
# it; nothing sits above this one to absorb the churn.
|
||||
servicesPkiRootTtl = "262800h";
|
||||
|
||||
# The leaf's window, pinned on the role rather than left to the mount's
|
||||
|
|
@ -645,16 +641,16 @@ let
|
|||
|
||||
# The role every swarm-service certificate will be issued through, and the
|
||||
# whole narrowing of this mount. A role rather than a name-constrained
|
||||
# sub-CA: the engine enforces the same "these names and no others" at issue
|
||||
# time that ./swarm-ca.nix builds into x509 `nameConstraints` today, so a
|
||||
# second CA in the chain would re-implement a check that already happens.
|
||||
# sub-CA: the engine enforces "these names and no others" at issue time, so
|
||||
# x509 `nameConstraints` on a second CA in the chain would re-implement a
|
||||
# check that already happens.
|
||||
servicesPkiRoleName = baoDeploy.servicesPkiRoleName;
|
||||
|
||||
# The names that role may issue for. Read out of the swarm-tier option
|
||||
# rather than assembled here, exactly as ./swarm-ca.nix:45 and
|
||||
# ./hive-tls.nix:16 read it — the thing that narrows what may be issued and
|
||||
# the leaf that carries those names as SANs must agree, and a second module
|
||||
# composing its own list is how they stop agreeing.
|
||||
# rather than assembled here, exactly as ./hive-tls.nix reads it — the thing
|
||||
# that narrows what may be issued and the leaf that carries those names as
|
||||
# SANs must agree, and a second module composing its own list is how they
|
||||
# stop agreeing.
|
||||
swarmServiceDomains = hyperhiveCfg.swarm.serviceDomains;
|
||||
|
||||
# The identity that asks this mount for a certificate. A FOURTH principal
|
||||
|
|
@ -1374,7 +1370,7 @@ in
|
|||
clientCaFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "/var/lib/swarm-ca/root.pem";
|
||||
example = "/var/lib/swarm-bao-pki/ca.pem";
|
||||
description = ''
|
||||
Authority the store validates hive **client** certificates against.
|
||||
|
||||
|
|
@ -1385,7 +1381,7 @@ in
|
|||
|
||||
On a hive that runs the store, a glue module supplies the CA it
|
||||
minted for exactly this, as a `mkDefault`. Point this at something
|
||||
else — the swarm root, an operator's own CA — and yours wins.
|
||||
else — an operator's own CA — and yours wins.
|
||||
|
||||
`null` leaves client-certificate verification off, which is only
|
||||
appropriate where something else authenticates the connection.
|
||||
|
|
@ -2806,21 +2802,18 @@ in
|
|||
#
|
||||
# Every narrowing is load-bearing, and three of them turn OFF a
|
||||
# default that is on:
|
||||
# * `allow_subdomains` — the x509 constraint ./swarm-ca.nix writes
|
||||
# permits a whole subtree per name; a swarm service is an exact
|
||||
# hostname, so the role is the narrower of the two.
|
||||
# * `allow_subdomains` — a swarm service is an exact hostname, not
|
||||
# a subtree.
|
||||
# * `allow_localhost` — bao's own default is `true`, which would
|
||||
# make this role issue for a name nobody configured.
|
||||
# * `allow_ip_sans` — the sub-CA excludes both IP subtrees
|
||||
# explicitly (./swarm-ca.nix:260-276); an unconstrained name type
|
||||
# is a name type this issuer is unconstrained for.
|
||||
# * `allow_ip_sans` — an unconstrained name type is a name type
|
||||
# this issuer is unconstrained for.
|
||||
# `server_flag` alone because that is what today's leaf carries
|
||||
# (`extendedKeyUsage=serverAuth`, ./hive-tls.nix:144), and rsa:4096
|
||||
# because that is the key the current implementation generates.
|
||||
#
|
||||
# An empty `swarm.serviceDomains` renders an empty `allowed_domains`,
|
||||
# which with `allow_any_name=false` is a role that issues nothing —
|
||||
# the same outcome as ./swarm-ca.nix's "nothing to issue for" exit,
|
||||
# which with `allow_any_name=false` is a role that issues nothing,
|
||||
# reached without a branch.
|
||||
bao write ${lib.escapeShellArg "${servicesPkiMountPath}/roles/${servicesPkiRoleName}"} \
|
||||
allowed_domains=${lib.escapeShellArg (lib.concatStringsSep "," swarmServiceDomains)} \
|
||||
|
|
|
|||
Loading…
Reference in a new issue