diff --git a/nix/modules/hive-tls.nix b/nix/modules/hive-tls.nix index d8e82df7..0931e035 100644 --- a/nix/modules/hive-tls.nix +++ b/nix/modules/hive-tls.nix @@ -73,10 +73,13 @@ in when it is missing or near expiry; because it shares the CA anchor, a rotation does not disturb consumer trust. Agents and federation peers validate against the CA, not browser CA/B-forum - limits. The weekly `hive-tls-resign` timer re-signs the leaf once - it is within half its validity of expiry and propagates the new - leaf into the running gateway, so a long-uptime host renews - automatically without a reboot. + limits. NOTE: at this short a window the re-sign must run more + often than the leaf lifetime. Today `hive-tls-ca` re-signs at + service activation (boot/rebuild) only — there is no periodic + re-sign timer yet — so a hive that does not reboot within the + validity window would let the leaf expire. Keep that in mind (or + add a re-sign timer) when running a hive that stays up for long + stretches without a rebuild. ''; }; }; @@ -162,109 +165,6 @@ in ''; }; - # Weekly re-sign of the gateway leaf so short-lived leaves renew - # without depending on a reboot. - # - # `hive-tls-ca` only re-signs at service activation (boot/rebuild); a - # long-uptime host would otherwise let a 30-day leaf lapse silently. - # This service re-signs the leaf directly (not by bouncing hive-tls-ca) - # and propagates the new leaf into the running gateway container when - # the file actually changed. - # - # Propagation mechanism: nginx in the gateway container serves a *copy* - # of the leaf written by `hive-gateway-self-signed-cert` (which runs at - # container start). A host-side `systemctl -M hive-gateway` call - # triggers the re-import + reload, mirroring how hive-c0re reloads the - # gateway after each agents.conf write. A path unit *inside* the - # container was tried first but does not work: IN_MOVED_TO from an - # atomic rename on the host does not propagate across the nspawn - # mount-namespace boundary. - # - # `|| true` on propagation so a stopped gateway never fails the unit — - # its next boot will import the already-rotated leaf anyway. - systemd.services.hive-tls-resign = { - description = "Re-sign the gateway TLS leaf and propagate it into the gateway container"; - # hive-tls-ca must have run first so the CA key exists before we try - # to re-sign under it. On first boot `Persistent=true` on the weekly - # timer fires immediately; without this ordering the resign could race - # the CA initialisation and fail with "no such file" on the CA key. - after = [ "hive-tls-ca.service" ]; - path = [ - pkgs.openssl - pkgs.coreutils - pkgs.systemd - ]; - serviceConfig = { - Type = "oneshot"; - UMask = "0077"; - SyslogIdentifier = "hive-tls-resign"; - }; - script = '' - set -euo pipefail - d=${lib.escapeShellArg cfg.stateDir} - ca="$d/ca.pem" - cak="$d/ca-key.pem" - leaf="$d/gateway.pem" - leafk="$d/gateway-key.pem" - - # Re-sign only when the leaf is within half its validity of expiry. - # The weekly cadence catches this window well before the leaf lapses. - halflife=$(( ${toString cfg.leafValidityDays} * 86400 / 2 )) - if [ -s "$leaf" ] && \ - openssl x509 -in "$leaf" -noout -checkend "$halflife" >/dev/null 2>&1; then - echo "gateway leaf valid for more than half its lifetime — no resign needed" - exit 0 - fi - - echo "gateway leaf missing or near expiry — re-signing under current CA" - before="$(sha256sum "$leaf" 2>/dev/null || true)" - - csr="$(mktemp "$d/gateway.csr.XXXXXX")" - ext="$(mktemp "$d/leaf.ext.XXXXXX")" - trap 'rm -f "$csr" "$ext"' EXIT - - openssl req -newkey rsa:4096 -nodes -sha256 \ - -keyout "$leafk" -out "$csr" \ - -subj "/CN=${domain}" - - { - printf 'subjectAltName=DNS:%s,DNS:forge.%s,DNS:matrix.%s,DNS:*.%s\n' \ - ${lib.escapeShellArg domain} ${lib.escapeShellArg domain} \ - ${lib.escapeShellArg domain} ${lib.escapeShellArg domain} - printf 'basicConstraints=critical,CA:FALSE\n' - printf 'keyUsage=critical,digitalSignature,keyEncipherment\n' - printf 'extendedKeyUsage=serverAuth\n' - } > "$ext" - - openssl x509 -req -in "$csr" -CA "$ca" -CAkey "$cak" \ - -CAcreateserial -days ${toString cfg.leafValidityDays} -sha256 \ - -extfile "$ext" -out "$leaf" - chmod 0600 "$leafk" - chmod 0644 "$leaf" - - after="$(sha256sum "$leaf" 2>/dev/null || true)" - if [ "$before" != "$after" ]; then - echo "gateway leaf rotated — propagating into hive-gateway" - systemctl -M hive-gateway restart hive-gateway-self-signed-cert.service || true - systemctl -M hive-gateway reload nginx.service || true - else - echo "gateway leaf unchanged (already up to date)" - fi - ''; - }; - - systemd.timers.hive-tls-resign = { - description = "Weekly gateway-leaf re-sign and propagation"; - wantedBy = [ "timers.target" ]; - timerConfig = { - # Run weekly; Persistent=true fires a missed run on next boot if - # the timer was not active (e.g. the host was off on the scheduled - # day), preventing a dormant timer from letting the leaf lapse. - OnCalendar = "weekly"; - Persistent = true; - }; - }; - # Signal the hive-c0re lifecycle that a hive CA exists: it bind-mounts # this file (read-only, the CA cert ONLY — never the key) into each # agent container so agents + their tools can trust the gateway's