nixos-config/config/service/wireguard-gateway.nix

91 lines
2.5 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
hostname = config.instance.hostname;
host = config.fudo.hosts.${hostname};
host-secrets = config.fudo.secrets.host-secrets.${hostname};
cfg = config.fudo.services.wireguard-gateway;
peerOpts = { name, ... }: {
options = with types; {
public-key = mkOption {
type = str;
description = "Peer public key.";
};
assigned-ip = mkOption {
type = str;
description = "IP address assigned to this peer.";
};
};
};
in {
options.fudo.services.wireguard-gateway = with types; {
enable = mkEnableOption "Enable WireGuard gateway: let external clients join the local network.";
network = mkOption {
type = str;
description = "IP address range to use for clients.";
default = "172.16.0.0/24";
};
listen-port = mkOption {
type = port;
description = "Port on which to listen for incoming connections.";
default = 51820;
};
peers = mkOption {
type = attrsOf (submodule peerOpts);
description = "Map of peer to peer options.";
default = {};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = all (peerOpts:
pkgs.lib.ip.ipv4OnNetwork peerOpts.assigned-ip cfg.network)
(attrValues cfg.peers);
message = "Peer IPs must be on the assigned network.";
}
{
assertion = host.wireguard.private-key-file != null;
message = "WireGuard gateway server private key file must be set.";
}
];
fudo.secrets.host-secrets.${hostname} = {
wireguard-gateway-privkey-file = {
source-file = host.wireguard.private-key-file;
target-file = "/run/wireguard-gateway/key";
};
};
networking = {
firewall.allowedUDPPorts = [ cfg.listen-port ];
wireguard.interfaces.wg-gw0 = {
ips = [ cfg.network ];
listenPort = cfg.listen-port;
postSetup =
"${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s ${cfg.network} -o ${cfg.external-interface} -j MASQUERADE";
postShutdown =
"${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s ${cfg.network} -o ${cfg.external-interface} -j MASQUERADE";
privateKeyFile = host-secrets.wireguard-gateway-privkey-file.target-file;
peers = let
peerList = attrValues cfg.peers;
in map (peerOpts: {
publicKey = peerOpts.public-key;
allowedIPs = [ "${peerOpts.ip}/32" ];
}) cfg.peers;
};
};
};
}