{ pkgs, lib, config, hostName, credentials, ... }: let iface = "wg-intra"; peers = import wg-intra/peers.nix; wg = config.networking.wireguard.interfaces.${iface}; in { # Each peer select the other peers allowed to connect to it options.networking.wireguard.${iface}.peers = lib.genAttrs (lib.attrNames peers) (peerName: { enable = lib.mkEnableOption "this peer"; }); config = { systemd.services."wireguard-${iface}".serviceConfig.LoadCredentialEncrypted = "privateKey:${credentials}/wireguard/${iface}/privateKey.secret"; networking.wireguard.interfaces.${iface} = 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.${iface}.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 ${iface} 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) '' # Allow initiating connection to and from other peers add rule inet filter net2fw udp dport ${toString wg.listenPort} counter accept comment "Wireguard ${iface} input from peers" add rule inet filter fw2net udp sport ${toString wg.listenPort} counter accept comment "Wireguard ${iface} output to peers" add rule inet filter lan2fw udp dport ${toString wg.listenPort} counter accept comment "Wireguard ${iface} input from peers" add rule inet filter fw2lan udp sport ${toString wg.listenPort} counter accept comment "Wireguard ${iface} output to peers" # Hook ${iface} into the input chain add chain inet filter intra2fw add rule inet filter input iifname ${iface} jump intra2fw add rule inet filter input iifname ${iface} log level warn prefix "intra2fw: " counter drop # Hook ${iface} into the output chain add chain inet filter fw2intra add rule inet filter output oifname ${iface} jump fw2intra add rule inet filter output oifname ${iface} log level warn prefix "fw2intra: " counter drop # Allow connections to peers acting as an endpointsUpdater ${lib.concatStringsSep "\n" (lib.mapAttrsToList (peerName: peer: '' add rule inet filter fw2intra tcp dport ${toString peer.listenPort} ip daddr ${peer.ipv4} \ counter accept comment "Wireguard ${iface} to endpointUpdater ${peerName}" '') (lib.filterAttrs (peerName: peer: config.networking.wireguard.${iface}.peers.${peerName}.enable && (peers.${peerName}.peer.endpointsUpdater.enable or false)) peers)) } ${lib.optionalString (peers.${hostName}.peer.endpointsUpdater.enable or false) '' # Allow connections from peers when acting as an endpointsUpdater add rule inet filter intra2fw tcp dport ${toString peers.${hostName}.listenPort} ip daddr ${peers.${hostName}.ipv4} \ counter accept comment "Wireguard ${iface} from peers to endpointUpdater" '' } ''; services.fail2ban.ignoreIP = lib.concatMap (host: host.peer.allowedIPs) (lib.attrValues peers); networking.networkmanager.unmanaged = ["wg-intra"]; }; }