Watch
0
0
Fork
You've already forked hyperhive
0

hive-gateway: no hive-domain vhost on a host without a hive

The hive-domain vhost renders only where a hive runs. On a host without
one the only certificate is the swarm-services leaf, which does not name
the hive domain, so a homeserver host without a hive serves matrix on the
homeserver's own name only; apex matrix discovery is #4878.

Comments and test names describe the code's current behaviour.

Refs #4588
This commit is contained in:
atlas 2026-10-04 18:57:12 +02:00 • committed by mara
commit 01ec29da48
6 changed files with 68 additions and 76 deletions

View file

@ -248,34 +248,32 @@ in
'';
};
}
// lib.optionalAttrs (runsHive || matrixDeployCfg.enable) {
// lib.optionalAttrs runsHive {
# The hive domain's own vhost, reachable by NAME, so the catch-all can
# reject everything else. It exists where it has something to serve:
# matrix discovery and the `/matrix/` redirect where the homeserver runs
# here, and the dashboard, agent routes and swagger UI where a hive runs
# (they proxy to hive-c0re, which runs only with the hive controller).
# reject everything else. Only where a hive runs: the dashboard, agent
# routes and swagger UI proxy to hive-c0re, which runs only with the hive
# controller, and the certificate naming the hive domain is the hive
# leaf, which exists only there.
${hyperhiveDomain} = (vhostTlsFor hyperhiveDomain) // {
listen = vhostListen;
locations =
matrixRedirectLocations
// wellKnownLocations
// lib.optionalAttrs runsHive (
agentLocations
// dashboardProxyLocation
// swaggerUiLocations
// lib.optionalAttrs cfg.auth.enable {
# Internal-only target for the dashboard's 401 error_page.
# `internal` prevents direct client access; `alias` serves
# the pre-built HTML from the Nix store.
"= /__hive_auth_unauthorized" = {
extraConfig = ''
internal;
alias ${errorPages.unauthorized};
default_type text/html;
'';
};
}
);
// agentLocations
// dashboardProxyLocation
// swaggerUiLocations
// lib.optionalAttrs cfg.auth.enable {
# Internal-only target for the dashboard's 401 error_page.
# `internal` prevents direct client access; `alias` serves
# the pre-built HTML from the Nix store.
"= /__hive_auth_unauthorized" = {
extraConfig = ''
internal;
alias ${errorPages.unauthorized};
default_type text/html;
'';
};
};
# Per-agent location blocks, generated at runtime by
# hive-c0re and written to /var/lib/hive-gateway/conf/agents.conf
# on the host — the same machine nginx runs on. nginx parses
@ -284,11 +282,9 @@ in
# agents without a nixos-rebuild. nginx's longest-prefix-
# match rule ensures `/agent/<name>/` from this file beats
# the `/agent/` catch-all above.
extraConfig =
securityHeaders
+ lib.optionalString runsHive ''
include /var/lib/hive-gateway/conf/agents.conf;
'';
extraConfig = securityHeaders + ''
include /var/lib/hive-gateway/conf/agents.conf;
'';
};
};
}

View file

@ -594,15 +594,10 @@ in
# The swarm-services leaf, issued by the secret store's `pki` mount.
#
# ⚠️ This unit replaces a chain, not a command. What used to happen
# was two openssl hops on whichever host held the swarm root key: a
# name-constrained `swarm-services` sub-CA (../swarm-ca.nix), then a
# leaf signed under it here. Both are gone. The store's
# `pki/roles/swarm-services` carries the same narrowing as an
# `allowed_domains` list enforced at issue time, so the intermediate
# that used to encode it in x509 `nameConstraints` has nothing left
# to express — and with the root inside the mount there is nothing
# for it to be an intermediate OF.
# The leaf chains straight to the mount's root, with no intermediate:
# the store's `pki/roles/swarm-services` narrows the names with an
# `allowed_domains` list enforced at issue time, so there is no x509
# `nameConstraints` for an intermediate to carry.
#
# The names it may carry are not this unit's to assert: the role
# refuses anything outside `allowed_domains`, read from the
@ -613,14 +608,10 @@ in
systemd.services.swarm-services-cert = {
description = "Issue the swarm-services TLS leaf from the secret store's PKI";
wantedBy = [ "multi-user.target" ];
# ⚠️ The ordering the old shape got by ACCIDENT, written down.
# Nothing used to declare "no TLS until the store is up" — it held
# because `swarm-services-ca.service` happened to block the gateway.
# Now it is a real edge: the gateway's certificate comes out of the
# store, so the store being up is a precondition rather than a
# coincidence, and `requiredBy` is what makes a store that never
# comes up an outage that says so instead of a gateway serving the
# wrong name.
# ⚠️ Where the gateway waits for this leaf, the store being up is a
# precondition of the gateway's certificate, and `requiredBy` is
# what makes a store that never comes up an outage that says so
# instead of a gateway serving the wrong name.
#
# 🩸 NOT `Before=hive-tls-ca.service`, however much the trust bundle
# wants it. That edge closed a cycle — the store's container is