{ inputs, 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 ];
};
}