nix(tls): host hive-CA + gateway leaf for self-signed mode
Replace the gateway's bare in-container self-signed leaf with a leaf signed by a host-held hive CA. A bare self-signed leaf is its own trust anchor, so every regeneration is a fresh anchor every consumer would have to re-trust, and a runtime-generated in-container leaf cannot be wired into an agent's build-time trust store at all. A stable CA fixes both: a single anchor that agents and federation peers trust once, surviving leaf rotation. New hive-tls module: a host oneshot generates a long-lived CA (default ~20y) under services.hyperhive.tls.stateDir and signs a gateway leaf (default ~10y, SAN covering the bare domain, forge., matrix. and the wildcard). It is ordered before the gateway container so the leaf exists when nginx starts. Active only when the gateway uses self-signed TLS (default) and a domain is set; inert under operator-cert or ACME modes. Gateway: bind-mount the host CA dir read-only at /run/hive-ca; the existing in-container cert unit now imports the host leaf into nginx's state dir (copy as root, key left root:nginx 0640 for the pre-start config test) instead of generating one. Cert/key paths nginx serves are unchanged. Foundational step toward agent + federation trust of self-signed hives; no behaviour change for agents yet (they still reach the forge over plain http on port 80). Eval-proven across self-signed, certDir and the inert default paths.
This commit is contained in:
parent
4297436d94
commit
74a90fd7d6
4 changed files with 216 additions and 71 deletions
|
|
@ -168,7 +168,7 @@ Four modes:
|
|||
|
||||
| mode | config | cert source | `.well-known` scheme |
|
||||
|---|---|---|---|
|
||||
| self-signed (default) | `selfSignedTls = true` | auto-generated RSA-4096, 10-year | `https` |
|
||||
| self-signed (default) | `selfSignedTls = true` | host hive-CA signs a gateway leaf (RSA-4096) | `https` |
|
||||
| ACME (Let's Encrypt) | `selfSignedTls = false` + `tls.acme.enable = true` | nginx inside container via HTTP-01 | `https` |
|
||||
| operator cert | `selfSignedTls = false` + `tls.certDir` set | bind-mounted from host | `https` |
|
||||
| http-only | `selfSignedTls = false`, no `tls.certDir`, no `tls.acme` | none | `http` |
|
||||
|
|
@ -198,15 +198,19 @@ Mutual exclusion: `selfSignedTls = true` or `tls.certDir` set together with `tls
|
|||
|
||||
### Self-signed TLS (`selfSignedTls`)
|
||||
|
||||
On by default. The gateway generates a self-signed RSA-4096 cert at first boot (10-year validity) and listens on `httpsPort` (default 443) on every vhost beside the plain-http `port` (default 80).
|
||||
On by default, and listens on `httpsPort` (default 443) on every vhost beside the plain-http `port` (default 80).
|
||||
|
||||
The anchor is a **host-held hive CA**, not a bare self-signed leaf. A host service (`hive-tls-ca.service`, from the `hive-tls` module) generates a long-lived CA (`services.hyperhive.tls.caValidityDays`, default ~20y) under `services.hyperhive.tls.stateDir` (default `/var/lib/hive-tls`), then signs a gateway **leaf** (`leafValidityDays`, default ~10y) with it. The leaf dir is bind-mounted read-only into the gateway container at `/run/hive-ca`; an in-container import unit copies the leaf into nginx's state dir (`/var/lib/hive-gateway/tls/{cert,key}.pem`) with the owner/mode nginx needs.
|
||||
|
||||
**Why a CA, not a bare leaf**: a bare self-signed leaf is its own trust anchor, so every regeneration is a new anchor every consumer must re-trust — and a runtime-generated, in-container leaf can't be wired into an agent's build-time trust store at all. With a stable CA, agents and federation peers trust the CA *once* (`ca.pem`); leaf rotation never re-breaks them.
|
||||
|
||||
**Why on by default**: matrix-dart-sdk (FluffyChat's SDK) hardcodes `https://<host>/.well-known/matrix/client` for homeserver discovery and refuses to fall back to plain http. Without TLS the browser client cannot bootstrap.
|
||||
|
||||
**Cert shape**: subject CN = bare hive domain; subjectAltName covers `<hive>` + wildcard `*.<hive>` so all current and future sub-domain vhosts (matrix, forge, ...) validate under the same cert. Stored at `/var/lib/hive-gateway/tls/{cert,key}.pem` inside the gateway container (`ephemeral = false`, so persisted across container restart).
|
||||
**Cert shape**: leaf subject CN = bare hive domain; subjectAltName covers `<hive>`, `forge.<hive>`, `matrix.<hive>`, and wildcard `*.<hive>` so all current and future sub-domain vhosts validate under the same leaf + the hive CA.
|
||||
|
||||
**Regeneration**: the generator unit (`hive-gateway-self-signed-cert.service`) always runs (idempotent). To rotate (e.g. cert leak, expiry approaching), delete `cert.pem` inside the gateway container and restart `nginx.service`.
|
||||
**Rotation**: `hive-tls-ca.service` is idempotent — it re-signs the leaf when it is missing or within 30 days of expiry, always under the same CA (so consumer trust is undisturbed). The CA itself is regenerated only if missing or already expired. To force a leaf rotation, delete `gateway.pem` under the state dir and restart the unit, then reload `nginx`.
|
||||
|
||||
**Cert prompts**: browsers warn once per host on first visit. With the wildcard SAN, `https://<hive>/`, `https://matrix.<hive>/`, and `https://forge.<hive>/` are covered by the same cert, but the browser still prompts per origin.
|
||||
**Cert prompts**: browsers still warn once per host until the hive CA is added to the browser/OS trust store (the CA, not the leaf, is the thing to trust). Agent trust of the CA is wired separately (see the agent-trust work for `/run/hive-ca`).
|
||||
|
||||
### Operator-provided cert (`tls.certDir`)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue