Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/host-modules/swarm-wireguard.nix
atlas 3202cde704 nix: gate hive-c0re on deploy.hive-controller.enable, drop hyperhive.enable
`services.hyperhive.enable` and `services.hyperhive.c0re.enable` are gone.
One switch, `services.hyperhive.deploy.hive-controller.enable` (default
false, as the old toggle was), now gates hive-c0re and hive-priv. Both old
paths are `mkRenamedOptionModule` shims in deploy.nix, so a host config
that still sets either evaluates as before and gets a rename warning.

Every other read of the old toggle is resolved, including the 29 made
through the `hyperhiveCfg`/`hiveCfg` aliases:

- Dropped: each swarm service and its glue keeps only its own deploy
  toggle (authelia, bao and its PKI glue, grafana, victorialogs,
  victoriametrics, the secret publisher, swarm-ca, the OIDC client rows,
  the controller/nats/matrix-ctl/publisher/services-issuer identities),
  the forge, and the `domain` deprecation warning.
- To deploy.hive-controller.enable: the queue-agent credential reader and
  its assertion, which feed hive-c0re and write under its state dir, plus
  their policy-order entry; the network identity assertions; hive-tls's
  two writes into hive-c0re's environment.
- hive-tls runs where the gateway runs self-signed
  (`gateway.enable && useSelfSigned`), not on every host.
- The matrix appservice-token reader and its assertion stay on
  `deploy.matrix.enable` plus their client-identity checks. They read
  deploy.matrix's token file and registration script; their deploy.bao
  inputs are the client-half options a hive sets to read a store it does
  not run, so gating on deploy.bao.enable would drop the tested
  remote-reader case.
- The `hiveName` assertion moves from hive-network.nix to hyperhive.nix
  and fires wherever the hive, the store or the homeserver runs: each
  turns the name into an identifier with no fallback.

On a host with `deploy.allSwarmServices` and no hive, the documented
services-host recipe, authelia, bao, grafana, victorialogs,
victoriametrics, the OIDC client rows and the hive CA now render; before,
the old toggle being off left them out.

Refs #4500
2026-09-26 01:19:49 +02:00

151 lines
5.7 KiB
Nix

# The WireGuard inter-hive mesh for the local host. Split out of
# ./swarm.nix because the two are different concerns with different
# audiences: that file declares WHO the peers are (consumed by
# swarm-controller's hive roster and, here, the mesh), while this one
# is plain host networking that a machine which runs no hive at all
# --- the snapshot store, for one --- still needs.
#
# The two stay coupled by data, not by structure: the per-peer
# `wireguard*` fields live on the peer submodule in ./swarm.nix, since
# that is where a peer is described, and this module reads them.
#
# Everything declared here is `deploy.*`, not `swarm.*`: by ./deploy.nix's
# rule, `swarm.*` is what a hive needs to be a *client* of the swarm, and
# none of this is. A peer needs this host's `wireguardEndpoint` (the roster
# entry in ./swarm.nix); what interface this host brings up, on which
# address, with which key, is nobody else's business. `listenPort` included
# — it is what this host binds, while the port a peer dials is the one
# inside `wireguardEndpoint`.
{
lib,
config,
...
}:
{
# WireGuard mesh config for the local host.
# When enabled, a `wg-hive` interface connects to all peers that have
# `wireguardPublicKey` declared. Peers reachable over the mesh are
# preferred for inter-hive traffic (no public TLS round-trip needed);
# peers without a public key still work via normal HTTPS.
options.services.hyperhive.deploy.wireguard = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Enable the WireGuard inter-hive mesh. When true, a `wg-hive`
interface is brought up connecting to all swarm peers that
declare a `wireguardPublicKey`. Requires
`privateKeyFile` to be set.
'';
};
privateKeyFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
example = "/etc/wireguard/hive.key";
description = ''
Path to the host's WireGuard private key file. The file must
be readable by root and should have mode 0400. Generate with
`wg genkey > /etc/wireguard/hive.key`. Required when
`deploy.wireguard.enable = true`.
'';
};
address = lib.mkOption {
type = lib.types.str;
default = "";
example = "10.100.0.1/24";
description = ''
IP address (with prefix) of this host on the WireGuard mesh.
Use a /24 (or broader) prefix so the routing table covers all
peer /32 routes. Example: `"10.100.0.1/24"` for a 256-host mesh.
'';
};
listenPort = lib.mkOption {
type = lib.types.port;
default = 51820;
description = ''
UDP port the local WireGuard interface listens on. Must be
reachable from peer hosts when they initiate the tunnel.
Default: 51820 (standard WireGuard port).
'';
};
persistentKeepalive = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = 25;
example = 25;
description = ''
Seconds between keepalive packets sent to each peer. Useful
when this host (or a peer) is behind NAT — keeps the UDP hole
open. Set to null to disable. Default: 25 seconds.
'';
};
};
# Gated on the mesh itself, NOT on `deploy.hive-controller.enable`. The
# mesh is host networking, not a c0re feature: a swarm host that runs no
# hive — the snapshot store, for one — still has to join the mesh.
# Nothing below is c0re-specific; the peer data c0re consumes
# (HIVE_PEER_CA_PATHS) is rendered in ./hive-c0re and stays gated there.
config = lib.mkIf config.services.hyperhive.deploy.wireguard.enable {
assertions = [
{
assertion = config.services.hyperhive.deploy.wireguard.privateKeyFile != null;
message = ''
services.hyperhive.deploy.wireguard.enable requires
services.hyperhive.deploy.wireguard.privateKeyFile to be set.
Generate a key: wg genkey > /etc/wireguard/hive.key
'';
}
{
assertion = config.services.hyperhive.deploy.wireguard.address != "";
message = ''
services.hyperhive.deploy.wireguard.enable requires
services.hyperhive.deploy.wireguard.address to be set
(e.g. "10.100.0.1/24").
'';
}
];
# WireGuard inter-hive mesh. Brings up a `wg-hive` interface and
# connects to each peer that has `wireguardPublicKey` set.
networking.wireguard.interfaces =
let
wgCfg = config.services.hyperhive.deploy.wireguard;
# `peerHives` is `swarm.hives` minus this hive (../swarm.nix) —
# a mesh that included our own entry would configure a tunnel to
# ourselves.
meshPeers = lib.filterAttrs (
_: p: p.wireguardPublicKey != null && p.wireguardAddress != null
) config.services.hyperhive.swarm.peerHives;
in
{
wg-hive = {
ips = [ wgCfg.address ];
listenPort = wgCfg.listenPort;
privateKeyFile = wgCfg.privateKeyFile;
peers = lib.mapAttrsToList (
_name: p:
{
publicKey = p.wireguardPublicKey;
allowedIPs = [ p.wireguardAddress ];
}
// lib.optionalAttrs (p.wireguardEndpoint != null) {
endpoint = p.wireguardEndpoint;
}
// lib.optionalAttrs (wgCfg.persistentKeepalive != null) {
persistentKeepalive = wgCfg.persistentKeepalive;
}
) meshPeers;
};
};
# Open the WireGuard UDP port on the host firewall (host-level
# networking — not inside containers).
networking.firewall.allowedUDPPorts = [
config.services.hyperhive.deploy.wireguard.listenPort
];
};
}