move hiveName to deploy.hive-controller; only a hive host needs a name
This commit is contained in:
parent
67f0d6a9d3
commit
0c6e8fc5a2
37 changed files with 402 additions and 215 deletions
|
|
@ -131,7 +131,7 @@ covers spreading a swarm across hosts.
|
|||
deploy.hive-controller.enable = true; # …and a hive to run agents on
|
||||
|
||||
swarm.domain = "hive.example"; # the swarm's DNS domain
|
||||
hiveName = "pr1ma"; # this hive's label in it
|
||||
deploy.hive-controller.hiveName = "pr1ma"; # this hive's label in it
|
||||
swarm.hives.pr1ma = { }; # the directory: just us
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ You rarely switch it on yourself. `gateway.enable` defaults to off, and every mo
|
|||
|
||||
A service module declares its vhost as `services.hyperhive.gateway.vhosts.<name>`: the locations, `forceSSL` and any `extraConfig` it needs. The gateway renders it into `services.nginx.virtualHosts.<name>` and adds the `listen` set, the certificate for that name and the [security headers](#security-headers) (ahead of the vhost's own `extraConfig`), and drops `addSSL` from a vhost that sets `forceSSL`. The eval fails for a vhost that sets `listen`, `addSSL`, `onlySSL`, `enableACME`, `useACMEHost`, `sslCertificate` or `sslCertificateKey` itself, and for any vhost declared while `gateway.enable` is false. A name with a certificate from outside the gateway's leaves (the queue's) sets `certificate = { cert; key; }` instead. `hive-gateway/vhosts.nix` declares the gateway's own catch-all (`_`) the same way, `hive-c0re/vhosts.nix` the dashboard and the hive domain, and `glue-matrix-hive-discovery.nix` adds the matrix redirect to the hive domain where the homeserver runs, and discovery there when the hive domain is the pinned server name. The catch-all sets `securityHeaders = false` because it sends no response, and the gateway renders a vhost's `default` at `mkDefault` priority.
|
||||
|
||||
**The hive's own vhosts**: the dashboard's, named `<name>.hives.<swarm>` (`swarm.dashboardDomain`), and one named for the hive domain. They exist only on a host that runs a hive (`deploy.hive-controller.enable`); a host without a hive has none of these rows:
|
||||
**The hive's own vhosts**: the dashboard's, named `<name>.hives.<swarm>` (`deploy.hive-controller.dashboardDomain`), and one named for the hive domain. They exist only on a host that runs a hive (`deploy.hive-controller.enable`); a host without a hive has none of these rows:
|
||||
|
||||
| URL | upstream | when |
|
||||
| --- | --- | --- |
|
||||
|
|
@ -116,7 +116,7 @@ Give the gateway the real cert (`tls.certDir` or `tls.acme`) so it serves proper
|
|||
|
||||
## Dashboard access
|
||||
|
||||
The dashboard answers on `<name>.hives.<swarm>` (`swarm.dashboardDomain`, derived from the hive name and `swarm.domain`), behind an authelia `auth_request`. Log in with your authelia account; only accounts in the `admins` group get in, the same rule as the swarm UI. Add one with `swarmctl user add <name> --group admins` ([`swarm/sso.md`](../swarm/sso.md)).
|
||||
The dashboard answers on `<name>.hives.<swarm>` (`deploy.hive-controller.dashboardDomain`, derived from the hive name and `swarm.domain`), behind an authelia `auth_request`. Log in with your authelia account; only accounts in the `admins` group get in, the same rule as the swarm UI. Add one with `swarmctl user add <name> --group admins` ([`swarm/sso.md`](../swarm/sso.md)).
|
||||
|
||||
The name sits under the swarm domain so authelia's session cookie reaches it, whatever the hive's own domain is. Any path on the hive domain other than the matrix routes redirects there, so old bookmarks still land.
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ listener sits on `bridgeIp`, on the host's bridge interface.
|
|||
{
|
||||
services.hyperhive = {
|
||||
deploy.hive-controller.enable = true;
|
||||
hiveName = "pr1ma";
|
||||
deploy.hive-controller.hiveName = "pr1ma";
|
||||
swarm.domain = "darkest.space";
|
||||
swarm.hives.pr1ma = { }; # -> domain = pr1ma.darkest.space
|
||||
# network.bridgeIp = "10.42.0.1"; # default
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ status_text, status_set_at, hive_name, swarm_name, matrix_accounts }`:
|
|||
or when `running = false` (see above).
|
||||
- `hive_name` / `swarm_name`: display names read from
|
||||
`HYPERHIVE_HIVE_NAME` / `HYPERHIVE_SWARM_NAME` env (sourced from
|
||||
`services.hyperhive.hiveName` / `services.hyperhive.swarm.name`).
|
||||
`services.hyperhive.deploy.hive-controller.hiveName` / `services.hyperhive.swarm.name`).
|
||||
Both `None` when the options aren't configured.
|
||||
- `matrix_accounts`: one `MatrixIdentity` per configured + live matrix
|
||||
account the agent can act as. Empty for agents with no matrix
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ refused delivery logs `webhook: refused delivery` with the reason.
|
|||
```nix
|
||||
services.hyperhive = {
|
||||
swarm.domain = "example.com"; # required — the swarm's DNS domain
|
||||
hiveName = "pr1ma"; # required — this hive's label in it
|
||||
deploy.hive-controller.hiveName = "pr1ma"; # required on a hive host — this hive's label in it
|
||||
swarm.name = "constellat1on"; # shared swarm display name (optional)
|
||||
|
||||
# required — the directory, identical on every host in the swarm.
|
||||
|
|
@ -503,7 +503,7 @@ services.hyperhive = {
|
|||
Swarm options are identical on every host in the swarm, so `swarm.domain` is
|
||||
**required** on every host that runs any hyperhive service; a host that
|
||||
imports the module and enables nothing evaluates without it. `hiveName` is
|
||||
required on a host that runs a hive, the secret store or the homeserver. Eval fails with a hint naming
|
||||
required on a host that runs a hive (`deploy.hive-controller.hiveName`), and on no other. Eval fails with a hint naming
|
||||
each. Neither defaults, because a guessed value here is a wrong hostname
|
||||
that evaluates cleanly and deploys.
|
||||
|
||||
|
|
@ -518,7 +518,7 @@ directory without this host would make every hive a peer, itself included.
|
|||
|
||||
```
|
||||
# hive A # hive B
|
||||
hiveName = "pr1ma"; hiveName = "edge";
|
||||
deploy.hive-controller.hiveName = "pr1ma"; deploy.hive-controller.hiveName = "edge";
|
||||
swarm.hives = { … }; swarm.hives = { … }; # byte-identical
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ impl AgentServer {
|
|||
and the target's self-reported `status` text (set via `set_status`) plus how \
|
||||
long ago it was set. Also returns the hive + swarm display names (`hive_name`, \
|
||||
`swarm_name`) when the operator has configured \
|
||||
`services.hyperhive.hiveName` / `services.hyperhive.swarm.name`; both lines \
|
||||
`services.hyperhive.deploy.hive-controller.hiveName` / `services.hyperhive.swarm.name`; both lines \
|
||||
omitted when unset. Pass `name` to query a peer (e.g. \
|
||||
check whether iris is idle before pinging them); omit `name` to get your own \
|
||||
identity stamp — handy for state files / commit messages / cross-agent \
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ pub fn hive_domain() -> Option<String> {
|
|||
/// [`hive_domain`] — the domain is the machine-readable DNS address;
|
||||
/// this is the prose label humans use in conversation. Reads the
|
||||
/// `HYPERHIVE_HIVE_NAME` env var; returns None when it is unset or empty
|
||||
/// (the host's `services.hyperhive.hiveName` is unset), in which case
|
||||
/// (the host's `services.hyperhive.deploy.hive-controller.hiveName` is unset), in which case
|
||||
/// callers fall back to the domain or the short label at their discretion.
|
||||
#[must_use]
|
||||
pub fn hive_name() -> Option<String> {
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ fn read_active_model(name: &hive_types::Ident) -> Option<String> {
|
|||
|
||||
/// Host-side hive + swarm display names, read from the c0re service's
|
||||
/// own process env. The hyperhive NixOS module sets these from
|
||||
/// `services.hyperhive.hiveName` + `services.hyperhive.swarm.name`
|
||||
/// `services.hyperhive.deploy.hive-controller.hiveName` + `services.hyperhive.swarm.name`
|
||||
/// (the hive names itself; the swarm it joins is named one level out).
|
||||
/// The agent-side
|
||||
/// `hive-agent::identity::{hive_name, swarm_name}` accessors read the
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ pub(super) struct StateSnapshot {
|
|||
authelia_public_url: Option<String>,
|
||||
/// Human name of this single-host hive instance (e.g. `"pr1ma"`).
|
||||
/// Sourced from `HYPERHIVE_HIVE_NAME` env var, set by the c0re
|
||||
/// NixOS module from `services.hyperhive.hiveName`. `None` when
|
||||
/// NixOS module from `services.hyperhive.deploy.hive-controller.hiveName`. `None` when
|
||||
/// the option is unset — chrome falls back to `hostname`.
|
||||
hive_name: Option<String>,
|
||||
/// Human name of the wider swarm this hive belongs to (e.g.
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
//! same host, each internally consistent.
|
||||
//!
|
||||
//! **The key is this hive's `hiveName`.** Nothing here has to arrange for
|
||||
//! that to match the controller's roster: `swarm.nix` asserts that
|
||||
//! `services.hyperhive.hiveName` is a key of `services.hyperhive.swarm.hives`,
|
||||
//! that to match the controller's roster: `hyperhive.nix` asserts that
|
||||
//! `services.hyperhive.deploy.hive-controller.hiveName` is a key of `services.hyperhive.swarm.hives`,
|
||||
//! so a hive that evaluates at all publishes under a name the roster
|
||||
//! knows. The alternative — a key the controller has never heard of —
|
||||
//! renders as `unknown` rather than being silently dropped, but the
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ pub struct HiveUrls {
|
|||
/// Canonical hive domain (`services.hyperhive.domain`).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub domain: Option<String>,
|
||||
/// Operator dashboard root (`https://<services.hyperhive.swarm.dashboardDomain>/`).
|
||||
/// Operator dashboard root (`https://<services.hyperhive.deploy.hive-controller.dashboardDomain>/`).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub home: Option<String>,
|
||||
/// Forge browser URL (`HIVE_FORGE_PUBLIC_URL`) — `None` when
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ const HIVE_TLS_TRUST_BUNDLE_PATH: &str = "/var/lib/hive-tls/trust-bundle.pem";
|
|||
/// *and future* hive validates.
|
||||
const STORE_PKI_ROOT_PATH: &str = "/var/lib/hive-tls/swarm-services-root.pem";
|
||||
|
||||
/// The option whose value keys a hive's entry in `services.hyperhive.swarm.hives`.
|
||||
const HIVE_NAME_OPTION: &str = "services.hyperhive.deploy.hive-controller.hiveName";
|
||||
|
||||
/// Attrset key for a hive in `services.hyperhive.swarm.hives`, derived
|
||||
/// from its domain's first DNS label.
|
||||
///
|
||||
|
|
@ -177,6 +180,16 @@ fn wg_pubkey(privkey: &[u8]) -> Result<String> {
|
|||
Ok(String::from_utf8_lossy(&out.stdout).trim().to_owned())
|
||||
}
|
||||
|
||||
/// The closing comment of the `wg peer` snippet.
|
||||
fn wg_peer_key_note() -> String {
|
||||
format!(" # the key must be that hive's {HIVE_NAME_OPTION}")
|
||||
}
|
||||
|
||||
/// The first closing comment line of the `peer-config` snippet.
|
||||
fn peer_config_key_note() -> String {
|
||||
format!("# the key must be this hive's {HIVE_NAME_OPTION}, and the")
|
||||
}
|
||||
|
||||
/// `wg peer` — print the nix snippet to add a peer hive to the mesh.
|
||||
/// Pure output (no fallible work), so it returns `()`; the dispatch arm
|
||||
/// wraps it in `Ok` to match the sibling verbs.
|
||||
|
|
@ -193,7 +206,7 @@ pub(crate) fn wg_peer(domain: &str, pubkey: &str, address: &str, endpoint: Optio
|
|||
println!(" wireguardEndpoint = \"{ep}\";");
|
||||
}
|
||||
println!(" }};");
|
||||
println!(" # the key must be that hive's services.hyperhive.hiveName");
|
||||
println!("{}", wg_peer_key_note());
|
||||
}
|
||||
|
||||
/// The `peer-config` step carrying the secret store's `pki` root: the
|
||||
|
|
@ -248,7 +261,7 @@ pub(crate) fn peer_config(domain: &str, wg_address: Option<&str>, wg_endpoint: O
|
|||
println!(" wireguardEndpoint = \"{ep}\";");
|
||||
}
|
||||
println!("}};");
|
||||
println!("# the key must be this hive's services.hyperhive.hiveName, and the");
|
||||
println!("{}", peer_config_key_note());
|
||||
println!("# same entry belongs in every hive's config — `hives` is the swarm.");
|
||||
if !self_signed {
|
||||
println!(
|
||||
|
|
@ -276,10 +289,26 @@ pub(crate) fn wg_status() -> Result<()> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{STORE_PKI_ROOT_PATH, store_root_step, write_key_0400};
|
||||
use super::{
|
||||
STORE_PKI_ROOT_PATH, peer_config_key_note, store_root_step, wg_peer_key_note,
|
||||
write_key_0400,
|
||||
};
|
||||
|
||||
const PEM: &str = "-----BEGIN CERTIFICATE-----\nMIIB\n-----END CERTIFICATE-----";
|
||||
|
||||
/// Both snippets tell the operator to set the deploy option, never the
|
||||
/// removed `services.hyperhive` spelling.
|
||||
#[test]
|
||||
fn key_notes_name_the_deploy_option() {
|
||||
for note in [wg_peer_key_note(), peer_config_key_note()] {
|
||||
assert!(
|
||||
note.contains("services.hyperhive.deploy.hive-controller.hiveName"),
|
||||
"{note}"
|
||||
);
|
||||
assert!(!note.contains("services.hyperhive.hiveName"), "{note}");
|
||||
}
|
||||
}
|
||||
|
||||
/// The certificate is printed whole, on lines of its own, so a peer
|
||||
/// operator can copy it out of the output as a PEM file.
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -143,6 +143,12 @@ in
|
|||
#
|
||||
# The runner moved from `deploy.forgejo.ci` to `deploy.ci-runner` with
|
||||
# every option keeping its type and meaning, so the old paths forward.
|
||||
# `hiveName` names the hive a host runs, so it moved under the service
|
||||
# that runs one. Same type and meaning.
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "hyperhive" "hiveName" ]
|
||||
[ "services" "hyperhive" "deploy" "hive-controller" "hiveName" ]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "hyperhive" "deploy" "forgejo" "ci" "enable" ]
|
||||
[ "services" "hyperhive" "deploy" "ci-runner" "enable" ]
|
||||
|
|
@ -514,6 +520,39 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
hive-controller.hiveName = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "pr1ma";
|
||||
description = ''
|
||||
Name of the hive this host runs, and the key of its entry in
|
||||
{option}`services.hyperhive.swarm.hives`. **Required** when
|
||||
{option}`services.hyperhive.deploy.hive-controller.enable` is set;
|
||||
a host that runs no hive needs none.
|
||||
|
||||
Not merely a display name: the hive occupies
|
||||
`<hiveName>.<swarm.domain>`, and the name is the hive's identity to
|
||||
the swarm (its secret-store certificate subject, its OIDC client, its
|
||||
status key). Distinct from {option}`services.hyperhive.domain`, the
|
||||
machine-addressable DNS name. Exposed to agents as
|
||||
`HYPERHIVE_HIVE_NAME`; surfaced in the dashboard chrome and per-agent
|
||||
system prompt. The identity surfaces are listed in
|
||||
`docs/process/conventions.md`, § Hive identity.
|
||||
'';
|
||||
};
|
||||
|
||||
hive-controller.dashboardDomain = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
readOnly = true;
|
||||
internal = true;
|
||||
description = ''
|
||||
Read-only: this hive's entry in
|
||||
{option}`services.hyperhive.swarm.dashboardDomains`, or null where
|
||||
`hiveName` has no entry in {option}`services.hyperhive.swarm.hives`
|
||||
(asserted).
|
||||
'';
|
||||
};
|
||||
|
||||
swarm-controller.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ let
|
|||
|
||||
hiveOtelSecret = import ./lib/hive-otel-secret.nix {
|
||||
inherit (hyperhiveCfg.swarm.authelia) hiveClientPrefix;
|
||||
inherit (hyperhiveCfg) hiveName;
|
||||
inherit (hyperhiveCfg.deploy.hive-controller) hiveName;
|
||||
};
|
||||
|
||||
havePair = cert: key: cert != null && key != null;
|
||||
|
|
@ -47,7 +47,7 @@ let
|
|||
# under the hive's own leaf.
|
||||
swarm-bao-hive-otel-oidc =
|
||||
otel.collector.enable
|
||||
&& hyperhiveCfg.hiveName != null
|
||||
&& hyperhiveCfg.deploy.hive-controller.hiveName != null
|
||||
&& havePair baoDeploy.clientCertFile baoDeploy.clientKeyFile
|
||||
&& otel.clientSecretFile == hiveOtelSecret.path;
|
||||
# ./swarm-grafana.nix
|
||||
|
|
|
|||
|
|
@ -41,16 +41,18 @@ let
|
|||
# re-issuing every client certificate in the swarm.
|
||||
pkiDir = import ./lib/bao-pki-dir.nix;
|
||||
|
||||
# What a reader calls itself to the store. The hive's name, because a bao
|
||||
# cert-auth role matches on the CN — this is an interface, not a label.
|
||||
# No fallback: `hiveName` is asserted set wherever `deploy.bao.enable` is
|
||||
# (./hyperhive.nix), the same condition this file's `config` is gated on. A
|
||||
# fallback here reads as a second supported spelling and there is no such
|
||||
# thing.
|
||||
clientCn = hyperhiveCfg.hiveName;
|
||||
# The hive this host runs, if any, and what it calls itself to the store: the
|
||||
# hive's name, because a bao cert-auth role matches on the CN — this is an
|
||||
# interface, not a label. `hiveName` is asserted set wherever
|
||||
# `deploy.hive-controller.enable` is (./hyperhive.nix), and the reader leaf
|
||||
# below exists only there: a store host that runs no hive has no hive to
|
||||
# name, and a fallback CN would read as a second supported spelling.
|
||||
runsHive = deployCfg.hive-controller.enable;
|
||||
clientCn = hyperhiveCfg.deploy.hive-controller.hiveName;
|
||||
|
||||
# Every other hive in the swarm directory. This host's own hive is signed
|
||||
# into the top of the directory, beside the leaves its units read.
|
||||
# Every other hive in the swarm directory. This host's own hive, where there
|
||||
# is one, is signed into the top of the directory, beside the leaves its
|
||||
# units read.
|
||||
otherHives = lib.filter (h: h != clientCn) (lib.attrNames hyperhiveCfg.swarm.hives);
|
||||
|
||||
# $1 dir $2 basename $3 CN $4 SAN or "" $5 EKU
|
||||
|
|
@ -83,15 +85,16 @@ in
|
|||
serverCertFile = lib.mkDefault "${pkiDir}/server.pem";
|
||||
serverKeyFile = lib.mkDefault "${pkiDir}/server-key.pem";
|
||||
clientCaFile = lib.mkDefault "${pkiDir}/ca.pem";
|
||||
|
||||
# A reader on this host, which happens to be the host that mints. Only
|
||||
# these three are what a reader elsewhere needs placed by hand; that they
|
||||
# collapse to the same CA file here is a property of self-signing, not of
|
||||
# the pairing.
|
||||
clientCertFile = lib.mkDefault "${pkiDir}/client.pem";
|
||||
clientKeyFile = lib.mkDefault "${pkiDir}/client-key.pem";
|
||||
serverCaFile = lib.mkDefault "${pkiDir}/ca.pem";
|
||||
|
||||
# The hive's own reader on this host, which happens to be the host that
|
||||
# mints. Only where a hive runs: the leaf's CN is the hive's name, and a
|
||||
# store host without a hive has no reader to name. That the pair collapses
|
||||
# to the same CA file as the server's here is a property of
|
||||
# self-signing, not of the pairing.
|
||||
clientCertFile = lib.mkIf runsHive (lib.mkDefault "${pkiDir}/client.pem");
|
||||
clientKeyFile = lib.mkIf runsHive (lib.mkDefault "${pkiDir}/client-key.pem");
|
||||
|
||||
# 🩸 The readers below each present a leaf of their own rather than
|
||||
# `client.pem` above. The leaf is what bao sees, so this pairing is the
|
||||
# whole of what turns "one principal with the union of their grants" into
|
||||
|
|
@ -181,8 +184,10 @@ in
|
|||
# CA is a file rather than a service.
|
||||
[ -s ${pkiDir}/server.pem ] || ${signLeaf} ${pkiDir} server \
|
||||
${lib.escapeShellArg cfg.domain} ${lib.escapeShellArg "DNS:${cfg.domain}"} serverAuth
|
||||
${lib.optionalString runsHive ''
|
||||
[ -s ${pkiDir}/client.pem ] || ${signLeaf} ${pkiDir} client \
|
||||
${lib.escapeShellArg clientCn} "" clientAuth
|
||||
''}
|
||||
|
||||
# Minted whether or not a controller runs here, because the case it
|
||||
# serves is the one where it does not: a controller elsewhere needs a
|
||||
|
|
@ -329,7 +334,7 @@ in
|
|||
[ -s ${pkiDir}/forge-publisher.pem ] || ${signLeaf} ${pkiDir} forge-publisher \
|
||||
${lib.escapeShellArg deployCfg.bao.forgePublisherCommonName} "" clientAuth
|
||||
|
||||
${lib.optionalString deployCfg.hive-controller.enable ''
|
||||
${lib.optionalString runsHive ''
|
||||
# This hive's gateway-leaf identity, which opens
|
||||
# `pki/issue/<hiveLeafPkiRolePrefix>-<hive>` and nothing else. Its
|
||||
# subject carries this hive's name, because ./swarm-bao.nix writes
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@
|
|||
# second signer would duplicate that file's `openssl` helper to no benefit.
|
||||
# What belongs here is the pairing: which paths this host's controller reads.
|
||||
#
|
||||
# ⚠️ Gated on the leaf existing, not on the store being enabled. A controller
|
||||
# on the store's own host is one deployment; a controller three networks away
|
||||
# holding a leaf issued out of band is another, and both want the same wiring.
|
||||
# `deploy.bao.enable` would have made the first one the only supported shape.
|
||||
# ⚠️ Gated on a PKI directory existing (the store runs here, or the operator
|
||||
# named a reader leaf), not on the store alone. A controller on the store's own
|
||||
# host is one deployment; a controller three networks away holding a leaf
|
||||
# issued out of band is another, and both want the same wiring.
|
||||
#
|
||||
# Everything is `mkDefault`. An operator naming their own paths wins.
|
||||
{
|
||||
|
|
@ -25,11 +25,18 @@ let
|
|||
deployCfg = hyperhiveCfg.deploy;
|
||||
baoDeploy = deployCfg.bao;
|
||||
|
||||
# Where ./glue-bao-tls.nix puts the leaves. Derived from the reader's own
|
||||
# path rather than repeating that file's directory literal: an operator who
|
||||
# moves the PKI moves both, and the two cannot drift apart.
|
||||
haveMintedPki = baoDeploy.clientCertFile != null;
|
||||
pkiDir = if haveMintedPki then builtins.dirOf baoDeploy.clientCertFile else null;
|
||||
# Where ./glue-bao-tls.nix puts the leaves. An operator's own `clientCertFile`
|
||||
# names the directory when one is set (an operator who moves the PKI moves
|
||||
# both, and the two cannot drift apart); on a store host that runs no hive
|
||||
# there is no reader leaf to derive from, so it is the store's directory.
|
||||
haveMintedPki = baoDeploy.clientCertFile != null || baoDeploy.enable;
|
||||
pkiDir =
|
||||
if baoDeploy.clientCertFile != null then
|
||||
builtins.dirOf baoDeploy.clientCertFile
|
||||
else if baoDeploy.enable then
|
||||
import ./lib/bao-pki-dir.nix
|
||||
else
|
||||
null;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf (deployCfg.swarm-controller.enable && haveMintedPki) {
|
||||
|
|
|
|||
|
|
@ -23,13 +23,13 @@ let
|
|||
autheliaMachine = hyperhiveCfg.swarm.authelia.machine;
|
||||
|
||||
# ./otel.nix: `senderAuth`, `hiveLeaf`, `fetches`, `fetchedSecretPath`.
|
||||
senderAuth = otel.clientSecretFile != null && hyperhiveCfg.hiveName != null;
|
||||
senderAuth = otel.clientSecretFile != null && hyperhiveCfg.deploy.hive-controller.hiveName != null;
|
||||
hiveLeaf =
|
||||
hyperhiveCfg.deploy.bao.clientCertFile != null && hyperhiveCfg.deploy.bao.clientKeyFile != null;
|
||||
fetchedSecretPath =
|
||||
(import ./lib/hive-otel-secret.nix {
|
||||
inherit (hyperhiveCfg.swarm.authelia) hiveClientPrefix;
|
||||
inherit (hyperhiveCfg) hiveName;
|
||||
inherit (hyperhiveCfg.deploy.hive-controller) hiveName;
|
||||
}).path;
|
||||
fetches = senderAuth && hiveLeaf && otel.clientSecretFile == fetchedSecretPath;
|
||||
waits = senderAuth && !fetches;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ let
|
|||
matrixCfg.gatewayHost != null
|
||||
&& hyperhiveCfg.deploy.hive-controller.enable
|
||||
&& gatewayCfg.enable
|
||||
&& hyperhiveCfg.swarm.dashboardDomain != null;
|
||||
&& hyperhiveCfg.deploy.hive-controller.dashboardDomain != null;
|
||||
|
||||
# Same default as `effectiveServerName` in ./hive-matrix.nix.
|
||||
serverName =
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
# belongs here is the pairing: which host paths go to the publisher in
|
||||
# authelia's container.
|
||||
#
|
||||
# ⚠️ Gated on the leaf existing, not on the store being enabled — the same rule
|
||||
# ⚠️ Gated on a PKI directory existing, not on the store alone — the same rule
|
||||
# ./glue-controller-bao-identity.nix states. A publisher on the store's own
|
||||
# host is one deployment; a publisher beside a remote authelia holding a leaf
|
||||
# issued out of band is another, and both want this wiring.
|
||||
|
|
@ -25,11 +25,18 @@ let
|
|||
deployCfg = hyperhiveCfg.deploy;
|
||||
baoDeploy = deployCfg.bao;
|
||||
|
||||
# Where ./glue-bao-tls.nix puts the leaves, derived from the reader's own
|
||||
# path rather than repeating that file's directory literal: an operator who
|
||||
# moves the PKI moves both, and the two cannot drift apart.
|
||||
haveMintedPki = baoDeploy.clientCertFile != null;
|
||||
pkiDir = if haveMintedPki then builtins.dirOf baoDeploy.clientCertFile else null;
|
||||
# Where ./glue-bao-tls.nix puts the leaves. An operator's own `clientCertFile`
|
||||
# names the directory when one is set (an operator who moves the PKI moves
|
||||
# both, and the two cannot drift apart); on a store host that runs no hive
|
||||
# there is no reader leaf to derive from, so it is the store's directory.
|
||||
haveMintedPki = baoDeploy.clientCertFile != null || baoDeploy.enable;
|
||||
pkiDir =
|
||||
if baoDeploy.clientCertFile != null then
|
||||
builtins.dirOf baoDeploy.clientCertFile
|
||||
else if baoDeploy.enable then
|
||||
import ./lib/bao-pki-dir.nix
|
||||
else
|
||||
null;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf (deployCfg.swarm-secret-publisher.enable && haveMintedPki) {
|
||||
|
|
|
|||
|
|
@ -49,13 +49,13 @@ in
|
|||
# required (asserted in hive-network.nix), so it's always set.
|
||||
HYPERHIVE_HIVE_DOMAIN = config.services.hyperhive.domain;
|
||||
}
|
||||
// lib.optionalAttrs (config.services.hyperhive.swarm.dashboardDomain != null) {
|
||||
// lib.optionalAttrs (config.services.hyperhive.deploy.hive-controller.dashboardDomain != null) {
|
||||
# The host the dashboard and the agent UIs answer on, for the URLs c0re
|
||||
# hands out (`hivectl open home`, each agent's UI link).
|
||||
HYPERHIVE_DASHBOARD_DOMAIN = config.services.hyperhive.swarm.dashboardDomain;
|
||||
HYPERHIVE_DASHBOARD_DOMAIN = config.services.hyperhive.deploy.hive-controller.dashboardDomain;
|
||||
}
|
||||
// lib.optionalAttrs (config.services.hyperhive.hiveName != null) {
|
||||
HYPERHIVE_HIVE_NAME = config.services.hyperhive.hiveName;
|
||||
// lib.optionalAttrs (config.services.hyperhive.deploy.hive-controller.hiveName != null) {
|
||||
HYPERHIVE_HIVE_NAME = config.services.hyperhive.deploy.hive-controller.hiveName;
|
||||
}
|
||||
// lib.optionalAttrs (config.services.hyperhive.swarm.name != null) {
|
||||
HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarm.name;
|
||||
|
|
@ -221,7 +221,7 @@ in
|
|||
# The identity swarm-authelia.nix already declares for every entry in
|
||||
# `swarm.hives` — the hive does not choose its own name here, it uses
|
||||
# the one the roster gave it.
|
||||
HIVE_C0RE_OIDC_CLIENT_ID = "hive-${config.services.hyperhive.hiveName}";
|
||||
HIVE_C0RE_OIDC_CLIENT_ID = "hive-${config.services.hyperhive.deploy.hive-controller.hiveName}";
|
||||
}
|
||||
//
|
||||
# Where the agents reach the queue: the address goes into every container in
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue