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
|
|
@ -83,8 +83,9 @@ the file every consumer anchors on. It holds whichever of these exist:
|
|||
issues under that CA; they stay in the bundle so a leaf it signed verifies
|
||||
until `hive-tls-resign` replaces it. Removing them is a deliberate later
|
||||
step.
|
||||
- the swarm root, `<swarm.ca.stateDir>/root.pem`, on the host that generates
|
||||
it.
|
||||
|
||||
No other anchor goes in: the store's `pki` root is the only root the swarm
|
||||
has.
|
||||
|
||||
No hive generates a CA or signs with a CA key. A
|
||||
`<deploy.hive-controller.tls.stateDir>/ca-key.pem` stays on disk, unread:
|
||||
|
|
@ -163,46 +164,34 @@ role's `allowed_domains`, enforced by the store at issue time: a hive's
|
|||
identity that leaks can get certificates for that hive's names and no
|
||||
others.
|
||||
|
||||
The swarm root's private key never reaches the nix store: the store is
|
||||
world-readable and content-addressed, so a key committed to a flake is a
|
||||
key published to everyone who builds it. The swarm distributes only
|
||||
certificates.
|
||||
No hive holds a root CA or its key, and nothing under `/var/lib/swarm-ca`
|
||||
exists: every host deletes that directory at boot and on every deploy. The
|
||||
swarm distributes only certificates.
|
||||
|
||||
## What to hand a peer
|
||||
|
||||
`hivectl peer-config` prints the `services.hyperhive.swarm.hives."<name>"`
|
||||
block a peer operator pastes into their own config. When this hive's
|
||||
gateway serves a self-signed leaf (detected by the presence of
|
||||
`<deploy.hive-controller.tls.stateDir>/trust-bundle.pem`), it also prints a
|
||||
one-time `scp` line installing the **swarm root** —
|
||||
`<swarm.ca.stateDir>/root.pem`, not this hive's own CA — on the peer's
|
||||
host:
|
||||
|
||||
```
|
||||
scp /var/lib/swarm-ca/root.pem <peer-host>:/var/lib/swarm-ca/root.pem
|
||||
```
|
||||
|
||||
It then prints the secret store's `pki` root itself, read from
|
||||
`<deploy.hive-controller.tls.stateDir>/trust-bundle.pem`), it also prints the
|
||||
secret store's `pki` root itself, read from
|
||||
`/var/lib/hive-tls/swarm-services-root.pem`. The store issues every hive's
|
||||
gateway leaf and the swarm's service names under that root, so a peer host
|
||||
trusting only the swarm root can't verify them.
|
||||
gateway leaf and the swarm's service names under that root, so it's the one
|
||||
anchor a peer host needs.
|
||||
|
||||
The operator installs the roots **once per swarm host**, not once per peer,
|
||||
The operator installs the root **once per swarm host**, not once per peer,
|
||||
so a hive joining later needs no edit on the hives already running. A hive
|
||||
whose cert already chains to a public CA has nothing to install —
|
||||
`peer-config` says so instead.
|
||||
|
||||
## Distributing the root
|
||||
|
||||
The root **key** is a runtime file for the reason in
|
||||
[Constraints on the material](#constraints-on-the-material).
|
||||
|
||||
The root **certificate** is a runtime file as a _consequence_ — it lives
|
||||
beside the key under `swarm.ca.stateDir` — and that has a cost worth
|
||||
The root **certificate** is a runtime file: each hive fetches it from the
|
||||
store at boot, so nothing can name it at build time. That has a cost worth
|
||||
naming, because it's subtle and it bites at a distance:
|
||||
|
||||
> **Nothing whose trust store nix assembles at build time can reference
|
||||
> the swarm root.** The derivation reads `security.pki.certificateFiles`
|
||||
> the store's root.** The derivation reads `security.pki.certificateFiles`
|
||||
> inside itself; the root doesn't exist there.
|
||||
|
||||
Two consumers, and only one of them is fine:
|
||||
|
|
@ -231,7 +220,7 @@ Two consumers, and only one of them is fine:
|
|||
> fixed. The same caveat applies to `hive-forge` (Go) for the same
|
||||
> reason.
|
||||
|
||||
To put the root on another host, copy the certificate to the same path
|
||||
there (`scp <stateDir>/root.pem <host>:<stateDir>/root.pem`). One anchor
|
||||
per host, not one per peer: a hive joining later needs no edit on the
|
||||
hives already running, which is the whole point of the hierarchy.
|
||||
A hive in the swarm fetches the root itself. A host outside it gets the
|
||||
certificate from `hivectl peer-config` ([What to hand a peer](#what-to-hand-a-peer)).
|
||||
One anchor per host, not one per peer: a hive joining later needs no edit
|
||||
on the hives already running.
|
||||
|
|
|
|||
Loading…
Reference in a new issue