feat(nix): make the swarm CA hierarchy opt-in

A swarm's services and its hives can live on different hosts, and a host
has no way to tell whether it is the one holding the root — so setting
the swarm CA up is an operator action, not something a host infers.
`swarm.ca.autoConfigure` is off by default and is the only thing that
issues a hive sub-CA, which is also the only case that *can*: signing
one needs the root's private key, and that key is deliberately not on a
hive host otherwise.

With the flag off, a hive self-signs its CA exactly as it always has.
That keeps a plain hive working out of the box; what it gives up is
membership of a swarm's trust hierarchy, which is the right thing to
give up for a hive nobody has federated.

Replaces a default derived from `swarm.peers == { }`. That read "no
peers declared" as "everything is local", which is not the same claim —
a hive can belong to a swarm it has not declared yet, or to one whose
services run elsewhere entirely.
This commit is contained in:
atlas 2026-08-05 15:11:22 +02:00 committed by mara
commit cc74a2c1f6
3 changed files with 118 additions and 78 deletions

View file

@ -66,16 +66,25 @@ artifacts on disk:
| | swarm root | this hive's CA |
| --- | --- | --- |
| all on one host (default) | generated by `swarm-ca.service` on first boot | issued by `hive-tls-ca.service` under the root |
| split across hosts | operator-provided | operator-provided |
| default | operator-provided | operator-provided, else self-signed as before |
| `autoConfigure = true` (all on one host) | generated by `swarm-ca.service` on first boot | issued by `hive-tls-ca.service` under the root |
`services.hyperhive.swarm.ca.autoConfigure` selects between them. It
defaults to true exactly while this hive declares no `swarm.peers`, so a
single-host swarm costs no configuration and declaring a peer stops the
host from minting a root that could not be the swarm's. Moving the swarm
CA onto its own host is then a matter of moving
`services.hyperhive.swarm.ca.stateDir` and setting `autoConfigure =
false` — there is no second code path to switch to.
`services.hyperhive.swarm.ca.autoConfigure` selects between them, and is
**off by default**: a swarm's services and its hives can live on
different hosts, and a host cannot tell whether it is the one holding
the root, so setting the swarm CA up is an operator action rather than
something a host assumes. Turn it on for an all-on-one-host deployment
and the hierarchy costs no configuration.
**A hive given neither artifact keeps the self-signed CA it has always
had.** It serves TLS exactly as before and simply isn't part of a
swarm's trust hierarchy — the right outcome for a hive nobody has
federated yet. Only `autoConfigure` issues a hive sub-CA, because only
that case can: signing one needs the root's private key.
Moving the swarm CA onto its own host is then a matter of moving
`services.hyperhive.swarm.ca.stateDir` and leaving `autoConfigure` off —
there is no second code path to switch to.
The root's private key never reaches the nix store: the store is
world-readable, so a key committed to a flake is a key published to