{ config, lib, hostname, masterDomain, ... }: let cfg = config.os.srv.wireguard; in { options.os.srv.wireguard = { enable = lib.mkEnableOption "enables wireguard vpn"; role = lib.mkOption { type = lib.types.enum [ "server" "client" ]; default = "client"; description = "where the machine is accepting connections or connecting"; }; server = { externalInterface = lib.mkOption { type = lib.types.str; default = "eth0"; description = "The public WAN interface of the server"; }; peers = lib.mkOption { type = lib.types.listOf ( lib.types.submodule { options = { name = lib.mkOption { type = lib.types.str; }; publicKey = lib.mkOption { type = lib.types.str; }; }; } ); default = [ ]; description = "List of client peers authorized to connect to this server"; }; }; client = { index = lib.mkOption { type = lib.types.nullOr lib.types.int; default = null; description = "The assigned host index number for the client IP address"; }; routeAllTraffic = lib.mkOption { type = lib.types.bool; default = false; description = "Routes 100% of your internet traffic through the server when active"; }; }; }; config = lib.mkIf cfg.enable ( lib.mkMerge [ { assertions = [ { assertion = config.os.srv.sops.enable; message = "required for wg private key"; } ]; sops.secrets."wg_private_key/${hostname}" = { owner = "root"; group = "root"; mode = "0600"; }; } (lib.mkIf (cfg.role == "server") { assertions = [ { assertion = config.os.srv.firewall.enable; message = "required for opening ports and passthrough"; } ]; boot.kernel.sysctl."net.ipv4.ip_forward" = 1; networking.firewall.allowedUDPPorts = [ 51280 ]; networking.nftables = { tables.wg-nat = { family = "inet"; content = '' chain forward { type filter hook forward priority 0; policy accept; iifname "wg0" accept oifname "wg0" accept } chain postrouting { type nat hook postrouting priority 100; policy accept; iifname "wg0" oifname "${cfg.server.externalInterface}" masquerade } ''; }; }; networking.wireguard.interfaces.wg0 = { ips = [ "10.255.1.1/16" ]; listenPort = 51280; privateKeyFile = config.sops.secrets."wg_private_key/${hostname}".path; peers = lib.imap1 (i: peer: { publicKey = peer.publicKey; allowedIPs = [ "10.255.0.${toString i}/32" ]; persistentKeepalive = 25; }) cfg.server.peers; }; }) (lib.mkIf (cfg.role == "client") { assertions = [ { assertion = cfg.client.index != null; message = "WireGuard client role requires a valid 'client.index' integer designation."; } ]; networking.nameservers = [ "10.255.1.1" "9.9.9.9" ]; networking.wireguard.interfaces.wg0 = { ips = [ "10.255.0.${toString cfg.client.index}/16" ]; privateKeyFile = config.sops.secrets."wg_private_key/${hostname}".path; peers = [ { # TODO get the server public key publicKey = ""; endpoint = "${masterDomain}:51280"; persistentKeepalive = 25; allowedIPs = if cfg.client.routeAllTraffic then [ "0.0.0.0/0" ] else [ "10.255.0.0/16" ]; } ]; }; }) ] ); }