1 { pkgs, lib, config, inputs, ... }:
3 inherit (config.security) gnupg;
4 inherit (config.boot) initrd;
6 wg = config.networking.wireguard.interfaces.${iface};
7 wg-intra-hosts = import (inputs.julm-nix + "/networking/wireguard/wg-intra/hosts.nix");
8 relay = wg-intra-hosts.mermet;
12 (inputs.julm-nix + "/networking/wireguard/wg-intra.nix")
14 networking.wireguard.interfaces.${iface} = {
15 privateKeyFile = gnupg.secrets."wireguard/${iface}/privateKey".path;
17 security.gnupg.secrets."wireguard/${iface}/privateKey" = {
19 systemdConfig.serviceConfig = {
20 before = [ "wireguard-${iface}.service" ];
21 wantedBy = [ "wireguard-${iface}.service" ];
22 requiredBy = [ "wireguard-${iface}.service" ];
26 systemd.services."wireguard-${iface}" = {
27 after = [ gnupg.secrets."wireguard/${iface}/privateKey".service ];
28 requires = [ gnupg.secrets."wireguard/${iface}/privateKey".service ];
29 unitConfig.Upholds = [ "upnpc-${toString wg.listenPort}.service" ];
31 networking.nftables.ruleset = ''
32 # Allow initiating connection to and from other peers
33 add rule inet filter fw2net udp sport ${toString wg.listenPort} counter accept comment "WireGuard ${iface} output to peers"
34 add rule inet filter net2fw udp dport ${toString wg.listenPort} counter accept comment "WireGuard ${iface} input from peers"
36 # Hook ${iface} into relevant chains
37 add rule inet filter input iifname "${iface}" jump intra2fw
38 add rule inet filter input iifname "${iface}" log level warn prefix "intra2fw: " counter drop
39 add rule inet filter output oifname "${iface}" jump fw2intra
40 add rule inet filter output oifname "${iface}" log level warn prefix "fw2intra: " counter drop
42 # ${iface} firewalling
43 add rule inet filter fw2intra counter accept
44 ${lib.concatMapStringsSep "\n" (ip: ''
45 add rule inet filter intra2fw ip saddr ${ip} counter accept comment "relay"
47 add rule inet filter forward iifname "${iface}" jump fwd-intra
49 # Apparently required to get NAT reflection.
50 services.upnpc.redirections = [
51 { description = "WireGuard"; externalPort = wg.listenPort; protocol = "UDP"; duration = 30 * 60;
52 service.requiredBy = [ "wireguard-${iface}.service" ];
53 service.before = [ "wireguard-${iface}.service" ];
56 boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
58 # Open a wireguard tunnel to a relay
59 # in case the host is hosted behind a NAT and has no SSH port forwarding.
60 # This enables to send the disk password to the initrd, like that:
61 # ssh -J mermet.sourcephile.fr root@losurdo.wg -p 2222
62 boot.initrd.secrets."/root/initrd/${iface}.key" = "/root/initrd/${iface}.key";
64 installer.ssh-nixos.script = ''
65 # Send the wireguard key of the initrd
66 gpg --decrypt '${gnupg.store}/wireguard/${iface}/privateKey.gpg' |
67 ssh '${config.installer.ssh-nixos.target}' \
68 install -D -m 400 -o root -g root /dev/stdin /root/initrd/${iface}.key
71 boot.initrd.kernelModules = [ "wireguard" ];
72 boot.initrd.extraUtilsCommands = ''
73 #copy_bin_and_libs ${pkgs.wireguard-tools}/bin/wg
74 cp -fpdv ${pkgs.wireguard-tools}/bin/.wg-wrapped $out/bin/wg
76 boot.initrd.network.postCommands = ''
77 ip link add dev ${iface} type wireguard
78 ${lib.concatMapStringsSep "\n" (ip: ''
79 ip address add ${ip} dev ${iface}
81 wg set ${iface} private-key /root/initrd/${iface}.key \
82 listen-port ${toString wg.listenPort}
83 ip link set up dev ${iface}
84 wg set ${iface} peer ${relay.peer.publicKey} \
85 endpoint ${relay.ipv4}:${toString relay.listenPort} \
86 allowed-ips ${relay.ipv4}/32 \
87 persistent-keepalive 5
88 ip route replace ${relay.ipv4}/32 dev ${iface} table main
90 boot.initrd.postMountCommands = lib.mkIf initrd.network.flushBeforeStage2 ''
91 ip link del dev ${iface}