{ inputs, pkgs, lib, config, hostName, ... }: let wgIface = "wg-intra"; peers = import wg-intra/peers.nix; wg = config.networking.wireguard.interfaces.${wgIface}; in { # Each peer select the other peers allowed to connect to it options.networking.wireguard.${wgIface}.peers = lib.genAttrs (lib.attrNames peers) (peerName: { enable = lib.mkEnableOption "this peer"; }); config = { systemd.services."wireguard-${wgIface}".serviceConfig.LoadCredentialEncrypted = [ ("privateKey:${inputs.self}/hosts/${hostName}/wireguard/${wgIface}/privateKey.cred") ]; networking.wireguard.interfaces.${wgIface} = lib.recursiveUpdate (removeAttrs peers.${hostName} ["ipv4" "persistentKeepalive" "peer"]) { peers = lib.mapAttrsToList (peerName: peer: lib.recursiveUpdate { persistentKeepalive = peer.persistentKeepalive # Useful if this peer is behind a NAT or peers.${hostName}.persistentKeepalive # Useful if this host is behind a NAT or null; } peer.peer) (removeAttrs (lib.filterAttrs (peerName: _: config.networking.wireguard.${wgIface}.peers.${peerName}.enable) peers) [hostName]); privateKeyFile = "\$CREDENTIALS_DIRECTORY/privateKey"; # Set the MTU to a minimum # (IPv4 requires at least 68 but it's 1280 for IPv6). # This prevents connections to stall on huge packets, # or delaying their initializing due to TCP PMTU probing. postSetup = '' ip link set dev ${wgIface} mtu 1280 ''; }; networking.hosts = lib.mkMerge [ (lib.mapAttrs' (hostName: host: lib.nameValuePair host.ipv4 [ "${hostName}.wg" ]) peers) { "${peers.losurdo.ipv4}" = [ "nix-extracache.losurdo.wg" "nix-localcache.losurdo.wg" "sftp.losurdo.wg" ]; } ]; networking.firewall.extraCommands = lib.optionalString (wg.listenPort != null) '' ip46tables -A nixos-fw -i any -p udp -m udp --dport ${toString wg.listenPort} -j ACCEPT ''; networking.nftables.ruleset = lib.optionalString (wg.listenPort != null) '' table inet filter { chain input-lan { udp dport ${toString wg.listenPort} counter accept \ comment "Wireguard ${wgIface} input from peers" } chain input-net { udp dport ${toString wg.listenPort} counter accept \ comment "Wireguard ${wgIface} input from peers" } chain input-intra { ${lib.optionalString (peers.${hostName}.peer.endpointsUpdater.enable or false) '' tcp dport ${toString peers.${hostName}.listenPort} ip daddr ${peers.${hostName}.ipv4} counter accept comment "Wireguard ${wgIface} from peers to endpointUpdater" '' } } chain input { iifname ${wgIface} jump input-intra iifname ${wgIface} log level warn prefix "input-intra: " counter drop } chain output-lan { udp sport ${toString wg.listenPort} counter accept \ comment "Wireguard ${wgIface} output to peers" } chain output-net { udp sport ${toString wg.listenPort} counter accept \ comment "Wireguard ${wgIface} output to peers" } chain output-intra { ${lib.concatStringsSep "\n" (lib.mapAttrsToList (peerName: peer: '' ip daddr ${peer.ipv4} \ tcp dport ${toString peer.listenPort} \ counter accept \ comment "Wireguard ${wgIface} to endpointUpdater ${peerName}" '') (lib.filterAttrs (peerName: peer: config.networking.wireguard.${wgIface}.peers.${peerName}.enable && (peers.${peerName}.peer.endpointsUpdater.enable or false)) peers)) } } chain output { oifname ${wgIface} jump output-intra oifname ${wgIface} log level warn prefix "output-intra: " counter drop } } ''; services.fail2ban.ignoreIP = lib.concatMap (host: host.peer.allowedIPs) (lib.attrValues peers); networking.networkmanager.unmanaged = [ wgIface ]; systemd.services.sshd.after = ["wireguard-${wgIface}.service"]; services.openssh.listenAddresses = [ { addr = peers.${hostName}.ipv4; port = 22; } ]; }; }