diff --git a/fuji/configuration.nix b/fuji/configuration.nix index e25f5f4..1788095 100644 --- a/fuji/configuration.nix +++ b/fuji/configuration.nix @@ -10,7 +10,7 @@ let USER = "akill"; in { - imports = [ ]; + imports = [ ./wireguard.nix ]; system = { stateVersion = "23.05"; @@ -29,22 +29,6 @@ in group = config.users.users.nobody.group; }; - "wg_privkey" = { - sopsFile = ./secrets/wg_privkey.yaml; - }; - - "wg_preshared/nixy" = { - sopsFile = ../common/secrets/wg_preshared.yaml; - }; - - "wg_privkey_proton" = { - sopsFile = ./secrets/wg_privkey_proton.yaml; - }; - - "wg_endpoint_proton" = { - sopsFile = ./secrets/wg_privkey_proton.yaml; - }; - "borgbase_enc_key" = { sopsFile = ./secrets/borgbase_enc_key.yaml; owner = config.users.users.${USER}.name; @@ -199,21 +183,6 @@ in }; }; - wireguard.interfaces = { - wg0 = { - ips = [ "10.100.0.6/24" ]; - privateKeyFile = config.sops.secrets."wg_privkey".path; - peers = [ - { - publicKey = builtins.readFile ../magpie/wg_pubkey; - presharedKeyFile = config.sops.secrets."wg_preshared/nixy".path; - allowedIPs = [ "10.100.0.0/24" ]; - endpoint = "5.75.229.224:51820"; - persistentKeepalive = 25; - } - ]; - }; - }; }; time.timeZone = "Europe/Sarajevo"; @@ -311,107 +280,8 @@ in }; }; - "netns@" = { - description = "%I network namespace"; - before = [ "network.target" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = "${pkgs.iproute2}/bin/ip netns add %I"; - ExecStop = "${pkgs.iproute2}/bin/ip netns del %I"; - }; - }; - - "wg_proton" = { - description = "wg network interface"; - bindsTo = [ "netns@wg.service" ]; - requires = [ "network-online.target" ]; - wants = [ "dnscrypt-proxy_proton.service" ]; - after = [ "netns@wg.service" ]; - before = [ "dnscrypt-proxy_proton.service" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = pkgs.writers.writeBash "wg-up" '' - set -e - ENDPOINT_IP=$(${pkgs.coreutils-full}/bin/cat "${config.sops.secrets."wg_endpoint_proton".path}") - ${pkgs.iproute2}/bin/ip link add proton_wg type wireguard - ${pkgs.iproute2}/bin/ip link set proton_wg netns wg - ${pkgs.iproute2}/bin/ip -n wg address add 10.2.0.2/32 dev proton_wg - ${pkgs.iproute2}/bin/ip netns exec wg \ - ${pkgs.wireguard-tools}/bin/wg set "proton_wg" private-key "${ - config.sops.secrets."wg_privkey_proton".path - }" - ${pkgs.iproute2}/bin/ip netns exec wg \ - ${pkgs.wireguard-tools}/bin/wg set "proton_wg" peer "g6DkXWKI/68RsLjROIwCEcyB/ZhyK5Q7OWcz1TtqER0=" \ - endpoint "$ENDPOINT_IP:51820" \ - persistent-keepalive "25" \ - allowed-ips "0.0.0.0/0" - ${pkgs.iproute2}/bin/ip -n wg link set lo up - ${pkgs.iproute2}/bin/ip -n wg link set proton_wg up - ${pkgs.iproute2}/bin/ip -n wg route add default dev proton_wg - ''; - ExecStop = pkgs.writers.writeBash "wg-down" '' - ${pkgs.iproute2}/bin/ip -n wg route del default dev proton_wg - ${pkgs.iproute2}/bin/ip -n wg link del proton_wg - ''; - }; - }; - - "dnscrypt-proxy_proton" = { - description = "DNSCrypt-proxy client proton"; - wants = [ - "network-online.target" - "nss-lookup.target" - ]; - before = [ "nss-lookup.target" ]; - after = [ "wg_proton.service" ]; - partOf = [ "wg_proton.service" ]; - serviceConfig = { - AmbientCapabilities = "CAP_NET_BIND_SERVICE"; - CacheDirectory = "dnscrypt-proxy"; - DynamicUser = true; - ExecStart = "${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy -config ${config.services.dnscrypt-proxy.configFile}"; - LockPersonality = true; - LogsDirectory = "dnscrypt-proxy"; - MemoryDenyWriteExecute = true; - NetworkNamespacePath = "/var/run/netns/wg"; - NonBlocking = true; - NoNewPrivileges = true; - PrivateDevices = true; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectSystem = "strict"; - Restart = "always"; - RestrictAddressFamilies = [ - "AF_INET" - "AF_INET6" - ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RuntimeDirectory = "dnscrypt-proxy"; - StateDirectory = "dnscrypt-proxy"; - SystemCallArchitectures = "native"; - SystemCallFilter = [ - "@system-service" - "@chown" - "~@aio" - "~@keyring" - "~@memlock" - "~@setuid" - "~@timer" - ]; - }; - }; }; - targets."wireguard-wg0".wantedBy = lib.mkForce [ ]; - coredump.enable = false; settings.Manager = { DefaultTimeoutStartSec = "30s"; diff --git a/fuji/wireguard.nix b/fuji/wireguard.nix new file mode 100644 index 0000000..cf43365 --- /dev/null +++ b/fuji/wireguard.nix @@ -0,0 +1,149 @@ +{ config +, pkgs +, lib +, ... +}: +{ + sops.secrets = { + "wg_privkey" = { + sopsFile = ./secrets/wg_privkey.yaml; + }; + + "wg_preshared/nixy" = { + sopsFile = ../common/secrets/wg_preshared.yaml; + }; + + "wg_privkey_proton" = { + sopsFile = ./secrets/wg_privkey_proton.yaml; + }; + + "wg_endpoint_proton" = { + sopsFile = ./secrets/wg_privkey_proton.yaml; + }; + }; + + # Personal mesh: dials into the magpie hub (10.100.0.0/24) + networking.wireguard.interfaces = { + wg0 = { + ips = [ "10.100.0.6/24" ]; + privateKeyFile = config.sops.secrets."wg_privkey".path; + peers = [ + { + publicKey = builtins.readFile ../magpie/wg_pubkey; + presharedKeyFile = config.sops.secrets."wg_preshared/nixy".path; + allowedIPs = [ "10.100.0.0/24" ]; + endpoint = "5.75.229.224:51820"; + persistentKeepalive = 25; + } + ]; + }; + }; + + systemd = { + services = { + # ProtonVPN split tunnel: proton_wg lives inside the `wg` network + # namespace; anything that should egress over Proton is launched + # with `ip netns exec wg ...`. + "netns@" = { + description = "%I network namespace"; + before = [ "network.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.iproute2}/bin/ip netns add %I"; + ExecStop = "${pkgs.iproute2}/bin/ip netns del %I"; + }; + }; + + "wg_proton" = { + description = "wg network interface"; + bindsTo = [ "netns@wg.service" ]; + requires = [ "network-online.target" ]; + wants = [ "dnscrypt-proxy_proton.service" ]; + after = [ "netns@wg.service" ]; + before = [ "dnscrypt-proxy_proton.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = pkgs.writers.writeBash "wg-up" '' + set -e + ENDPOINT_IP=$(${pkgs.coreutils-full}/bin/cat "${config.sops.secrets."wg_endpoint_proton".path}") + ${pkgs.iproute2}/bin/ip link add proton_wg type wireguard + ${pkgs.iproute2}/bin/ip link set proton_wg netns wg + ${pkgs.iproute2}/bin/ip -n wg address add 10.2.0.2/32 dev proton_wg + ${pkgs.iproute2}/bin/ip netns exec wg \ + ${pkgs.wireguard-tools}/bin/wg set "proton_wg" private-key "${ + config.sops.secrets."wg_privkey_proton".path + }" + ${pkgs.iproute2}/bin/ip netns exec wg \ + ${pkgs.wireguard-tools}/bin/wg set "proton_wg" peer "${lib.fileContents ../common/wg_pubkey_proton}" \ + endpoint "$ENDPOINT_IP:51820" \ + persistent-keepalive "25" \ + allowed-ips "0.0.0.0/0" + ${pkgs.iproute2}/bin/ip -n wg link set lo up + ${pkgs.iproute2}/bin/ip -n wg link set proton_wg up + ${pkgs.iproute2}/bin/ip -n wg route add default dev proton_wg + ''; + ExecStop = pkgs.writers.writeBash "wg-down" '' + ${pkgs.iproute2}/bin/ip -n wg route del default dev proton_wg + ${pkgs.iproute2}/bin/ip -n wg link del proton_wg + ''; + }; + }; + + "dnscrypt-proxy_proton" = { + description = "DNSCrypt-proxy client proton"; + wants = [ + "network-online.target" + "nss-lookup.target" + ]; + before = [ "nss-lookup.target" ]; + after = [ "wg_proton.service" ]; + partOf = [ "wg_proton.service" ]; + serviceConfig = { + AmbientCapabilities = "CAP_NET_BIND_SERVICE"; + CacheDirectory = "dnscrypt-proxy"; + DynamicUser = true; + ExecStart = "${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy -config ${config.services.dnscrypt-proxy.configFile}"; + LockPersonality = true; + LogsDirectory = "dnscrypt-proxy"; + MemoryDenyWriteExecute = true; + NetworkNamespacePath = "/var/run/netns/wg"; + NonBlocking = true; + NoNewPrivileges = true; + PrivateDevices = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + Restart = "always"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RuntimeDirectory = "dnscrypt-proxy"; + StateDirectory = "dnscrypt-proxy"; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "@chown" + "~@aio" + "~@keyring" + "~@memlock" + "~@setuid" + "~@timer" + ]; + }; + }; + }; + + # Don't bring wg0 up at boot + targets."wireguard-wg0".wantedBy = lib.mkForce [ ]; + }; +}