138 lines
4.7 KiB
Nix
138 lines
4.7 KiB
Nix
{
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.services.hyperhive.network;
|
|
in
|
|
{
|
|
# Hive-internal network — host-side bridge + per-agent DNS resolver.
|
|
# Containers stay on shared host netns at v1; this module stands the
|
|
# bridge + resolver up so the endpoint is in place before network
|
|
# isolation flips containers to private netns. Full design: docs/network.md.
|
|
|
|
options.services.hyperhive.network = {
|
|
enable = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
example = true;
|
|
description = ''
|
|
Stand up the hive-internal bridge + dnsmasq resolver.
|
|
Off by default while v1 phases in. When enabled:
|
|
a bridge interface (`bridgeName`) appears on the host with
|
|
`bridgeIp` assigned, and the hive-gateway container runs a
|
|
dnsmasq listening on that IP for `<hive-domain>` +
|
|
sub-domains. Agent containers still default to shared host
|
|
netns at v1 — the endpoint is up but only used once #14
|
|
lands and flips containers to a private netns + veth peer
|
|
on this bridge.
|
|
'';
|
|
};
|
|
|
|
bridgeName = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "hive-br0";
|
|
example = "h0";
|
|
description = ''
|
|
Name of the host-side bridge interface the hive uses for
|
|
inter-container traffic. Kept short so it survives the
|
|
IFNAMSIZ (15-char) cap, and prefixed so it's obviously
|
|
hive-managed in `ip link` output.
|
|
'';
|
|
};
|
|
|
|
bridgeIp = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "10.42.0.1";
|
|
example = "172.30.0.1";
|
|
description = ''
|
|
IPv4 address assigned to the bridge interface on the host
|
|
side. Becomes the DNS server address agents point at (and
|
|
the upstream the gateway proxies to once netns isolation
|
|
lands). Default `10.42.0.1` is in RFC 1918 space and
|
|
unlikely to clash with operator's existing setup; override
|
|
if a different range is already in use.
|
|
'';
|
|
};
|
|
|
|
bridgePrefixLength = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = 24;
|
|
example = 16;
|
|
description = ''
|
|
Netmask prefix length for the bridge subnet. Default `/24`
|
|
gives 254 usable per-agent addresses, enough for any
|
|
single-host hive. Operator with a larger swarm or a tighter
|
|
addressing scheme overrides.
|
|
'';
|
|
};
|
|
|
|
upstreamDns = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [
|
|
"1.1.1.1"
|
|
"9.9.9.9"
|
|
];
|
|
example = [
|
|
"192.168.1.1"
|
|
"8.8.8.8"
|
|
];
|
|
description = ''
|
|
Upstream DNS servers dnsmasq forwards non-hive queries to.
|
|
Defaults to Cloudflare + Quad9. Override for operators on
|
|
private networks who need a specific resolver (corporate
|
|
DNS, pi-hole, etc.). The hive resolver itself stays
|
|
authoritative for `<hive-domain>` and its sub-domains
|
|
regardless of upstream choice.
|
|
'';
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
assertions = [
|
|
{
|
|
assertion = config.services.hyperhive.domain != null;
|
|
message = ''
|
|
services.hyperhive.network.enable = true requires
|
|
services.hyperhive.domain to be set — the resolver needs a
|
|
domain to be authoritative for. Either pin a hostname
|
|
(`services.hyperhive.domain = "example.com";`) or leave
|
|
`network.enable` at its default of false.
|
|
'';
|
|
}
|
|
{
|
|
assertion = config.services.hyperhive.gateway.enable;
|
|
message = ''
|
|
services.hyperhive.network.enable = true requires
|
|
services.hyperhive.gateway.enable = true — the dnsmasq
|
|
resolver runs inside the hive-gateway container (single
|
|
front-door for both DNS and HTTP). Enable the gateway or
|
|
leave `network.enable` at its default of false.
|
|
'';
|
|
}
|
|
];
|
|
|
|
# Bridge interface on the host. Empty interfaces list = purely
|
|
# virtual bridge (no slave NICs attached). Per-agent veth pairs
|
|
# will join this bridge once #14 lands; at v1 it stands alone.
|
|
networking.bridges.${cfg.bridgeName}.interfaces = [ ];
|
|
|
|
# Host-side IP assignment on the bridge. This is what dnsmasq
|
|
# (inside the gateway container, shared host netns) binds on.
|
|
networking.interfaces.${cfg.bridgeName}.ipv4.addresses = [
|
|
{
|
|
address = cfg.bridgeIp;
|
|
prefixLength = cfg.bridgePrefixLength;
|
|
}
|
|
];
|
|
|
|
# Open the resolver port in the host firewall for traffic from
|
|
# the bridge subnet only. Other interfaces stay closed —
|
|
# external DNS-amplification surface is not exposed.
|
|
networking.firewall.interfaces.${cfg.bridgeName} = {
|
|
allowedUDPPorts = [ 53 ];
|
|
allowedTCPPorts = [ 53 ];
|
|
};
|
|
};
|
|
}
|