Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/host-modules/local-defaults.nix
atlas 93f1a76ea7 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
2026-10-05 21:17:10 +02:00

113 lines
5.6 KiB
Nix

# The all-local deployment mode.
#
# `singleHostSwarm` is a *mode*, not a default other options read:
# it says "this box is the whole deployment" and then asserts the values
# that follow from that. mara, on the issue: it is "more of a deployment
# mode via settings set, less a default setting".
#
# That distinction is why the derivations live here as `mkDefault` in a
# `config` block rather than as `default =` inside each option. An option
# declares what IT is and what it is when nobody asks; a mode declares
# what a deployment shape implies. Written the other way round, every
# service option had to name a flag it has no relationship to, and the
# answer to "what does all-local turn on?" was spread across five files.
#
# Adding an autoconfigurable thing later means one line here — not a
# `default =` in the new module pointing back at this flag.
{
lib,
config,
...
}:
let
cfg = config.services.hyperhive;
in
{
options.services.hyperhive.deploy.singleHostSwarm = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = ''
Run the whole swarm on this host. Turning this on asserts the
toggles that an all-on-one-box deployment implies: the swarm's
shared services
(`services.hyperhive.deploy.allSwarmServices`), the swarm
controller (`services.hyperhive.deploy.swarm-controller.enable`), and the
host's `/etc/hosts` entries for the names this hive serves
(`services.hyperhive.gateway.localHostsEntry`) — with no real DNS
for those names, the operator is browsing them from the same box
that answers for them.
**Off by default, and that is the load-bearing part.** A swarm's
services and its hives can live on different hosts, and a host has
no way to tell which ones it is meant to be — so this is an
operator saying "this is that box", never something inferred.
Turn it on for a dev box or a single-hive swarm and get a working
deployment with no further configuration; leave it off and every
swarm-level artifact is operator-provided.
Each toggle it asserts can still be set explicitly, which wins —
so "all local except X" needs no new option.
'';
};
# What the mode asserts. `mkDefault` (priority 1000) beats an option's
# own `default` (1500) and loses to any explicit definition, which is
# exactly the precedence a deployment mode wants: it fills in for an
# operator who hasn't spoken, and never argues with one who has.
# The gateway's own all-local bit. `localHostsEntry` maps every name
# this hive answers for to 127.0.0.1 in the HOST's /etc/hosts, which is
# exactly what "this box is the whole deployment" implies: there is no
# real DNS for these names, and the operator is browsing them from the
# same machine that serves them.
#
# ⚠️ It does NOT affect what containers resolve. dnsmasq sets
# `no-hosts = true` unconditionally (see hive-gateway/dnsmasq.nix), so
# agents keep getting the bridge IP from the authoritative `address=`
# rules rather than the host's 127.0.0.1 — an entry that would point
# every agent at its own netns. That guard already existing is what
# makes turning this on by default safe; without it this line would
# break every agent's access to the forge.
config.services.hyperhive.gateway.localHostsEntry = lib.mkDefault cfg.deploy.singleHostSwarm;
# A `deploy.*` option (./deploy.nix): "does THIS host run the swarm's
# services" is a per-host decision.
config.services.hyperhive.deploy.allSwarmServices = lib.mkDefault cfg.deploy.singleHostSwarm;
# The queue's auth-callout nkeys. Generating them is safe exactly
# when one operator owns both the queue and its responder, which is
# what this mode asserts. On any other topology the seeds have to
# reach whoever runs the responder, and minting them here would move
# that hand-off somewhere less visible rather than removing it.
config.services.hyperhive.deploy.nats.autoGenerateCallout =
lib.mkDefault cfg.deploy.singleHostSwarm;
# The controller is asserted by the MODE and by nothing else. Its own
# option stays `default = false` precisely because running it is a
# statement about swarm topology — but "this box is the whole
# deployment" IS that statement, and it is the one shape where the
# answer isn't ambiguous. Deriving it from `allSwarmServices`
# instead would be wrong: a hive in a larger swarm can legitimately
# want the shared services without being the host that controls them.
#
# A `deploy.*` option (./deploy.nix): "does THIS host run the controller"
# is exactly the per-host fact `swarm.*` may not carry.
config.services.hyperhive.deploy.swarm-controller.enable = lib.mkDefault cfg.deploy.singleHostSwarm;
# Where the operator drops the token that writes the swarm's first bao
# grants. All-local supplies the path, never the file: `bao operator init`
# stays a human step in every shape (see ./swarm-bao.nix), so what
# co-location makes derivable is only *where* it goes. The granting unit
# skips until the file appears, so naming the path early costs a boot
# nothing.
#
# ⚠️ Deliberately NOT under `/var/lib/swarm-bao-token`, which already holds
# the PKCS11 seal material. Those are both "a bao token" and neither can
# substitute for the other: one unseals the store, this one authorises the
# first write.
#
# A path on this host is a `deploy.*` fact, like the controller's options.
config.services.hyperhive.deploy.bao.bootstrapTokenFile = lib.mkIf cfg.deploy.singleHostSwarm (
lib.mkDefault "/var/lib/swarm-bao-bootstrap/grant.token"
);
}