Follow-up to the peer-hives removal: docs/web-ui/dashboard.md drops the whole "P33R H1V3S" section + its stale #peers hash and tab-strip mentions; docs/swarm/README.md's runtime-effects list and cross-references point at swarm-ui's roster page instead. Nix comments in hive-c0re/environment.nix, swarm.nix and swarm-wireguard.nix that described HYPERHIVE_PEERS/certFingerprint as dashboard-consumed are updated to say what's actually still true (agent identity only). Deliberately NOT removed: the `certFingerprint` nix option itself. It has no remaining Rust consumer, but deleting a documented, potentially already-set option is a bigger, breaking change than removing dead display code — flagged in docs/swarm/README.md with a note instead of silently dropped, so an operator or reviewer can make that call explicitly rather than have it made for them here.
145 lines
5.3 KiB
Nix
145 lines
5.3 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 (data hive-c0re
|
|
# serialises into HYPERHIVE_PEERS for agent identity), 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.
|
|
{
|
|
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.swarm.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
|
|
`swarm.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 the c0re daemon. 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, and under
|
|
# the old `c0re.enable` gate it silently got no `wg-hive` interface
|
|
# at all. Nothing below is c0re-specific; the peer data
|
|
# c0re consumes (HYPERHIVE_PEERS / HIVE_PEER_CA_PATHS) is rendered in
|
|
# ./hive-c0re and stays gated there.
|
|
config = lib.mkIf config.services.hyperhive.swarm.wireguard.enable {
|
|
assertions = [
|
|
{
|
|
assertion = config.services.hyperhive.swarm.wireguard.privateKeyFile != null;
|
|
message = ''
|
|
services.hyperhive.swarm.wireguard.enable requires
|
|
services.hyperhive.swarm.wireguard.privateKeyFile to be set.
|
|
Generate a key: wg genkey > /etc/wireguard/hive.key
|
|
'';
|
|
}
|
|
{
|
|
assertion = config.services.hyperhive.swarm.wireguard.address != "";
|
|
message = ''
|
|
services.hyperhive.swarm.wireguard.enable requires
|
|
services.hyperhive.swarm.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.swarm.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.swarm.wireguard.listenPort
|
|
];
|
|
};
|
|
}
|