From a16a153e768e2b4472f4a7c9f9bd8afc89c8fe82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Yule=20B=C3=A4dorf?= Date: Tue, 13 Feb 2024 00:27:30 +0100 Subject: [PATCH] wireguard: fix routing w/ tunneled wireguard --- hosts/droppie/networking.nix | 12 +-- hosts/frikandel/wireguard.nix | 20 ++-- hosts/stroopwafel/networking.nix | 10 +- modules/wireguard/default.nix | 2 +- modules/wireguard/private.nix | 11 +- modules/wireguard/public.nix | 83 --------------- modules/wireguard/tunnel.nix | 96 ++++++++++++++++++ secrets/secrets.nix | 4 +- secrets/wg-public-stroopwafel.age | Bin 1227 -> 0 bytes ...blic-droppie.age => wg-tunnel-droppie.age} | 0 secrets/wg-tunnel-stroopwafel.age | 24 +++++ 11 files changed, 152 insertions(+), 110 deletions(-) delete mode 100644 modules/wireguard/public.nix create mode 100644 modules/wireguard/tunnel.nix delete mode 100644 secrets/wg-public-stroopwafel.age rename secrets/{wg-public-droppie.age => wg-tunnel-droppie.age} (100%) create mode 100644 secrets/wg-tunnel-stroopwafel.age diff --git a/hosts/droppie/networking.nix b/hosts/droppie/networking.nix index 5ece084..e1b74d3 100644 --- a/hosts/droppie/networking.nix +++ b/hosts/droppie/networking.nix @@ -25,18 +25,16 @@ "fd00:b12f:acab:1312:acab:3::/96" ]; privateKeyFile = config.age.secrets.wg-private-key.path; - useDNS = false; }; - age.secrets.wg-public-key.file = "${flake.self}/secrets/wg-public-droppie.age"; + age.secrets.wg-tunnel-key.file = "${flake.self}/secrets/wg-tunnel-droppie.age"; - pub-solar.wireguard.public = { + pub-solar.wireguard.tunnel = { ownIPs = [ - "10.70.16.244/32" - "fc00:bbbb:bbbb:bb01::7:10f3/128" + "10.69.139.214/32" + "fc00:bbbb:bbbb:bb01::6:8bd5/128" ]; - privateKeyFile = config.age.secrets.wg-public-key.path; - useDNS = true; + privateKeyFile = config.age.secrets.wg-tunnel-key.path; peer = { publicKey = "m9w2Fr0rcN6R1a9HYrGnUTU176rTZIq2pcsovPd9sms="; endpoint = "[2a02:6ea0:d406:1::a18f]:3019"; diff --git a/hosts/frikandel/wireguard.nix b/hosts/frikandel/wireguard.nix index 78c0f8b..7e90fa6 100644 --- a/hosts/frikandel/wireguard.nix +++ b/hosts/frikandel/wireguard.nix @@ -20,6 +20,7 @@ }; networking.firewall.allowedUDPPorts = [ 51899 ]; + networking.firewall.extraForwardRules = [ "iifname { != wg-private } reject" "iifname wg-private accept" @@ -62,7 +63,8 @@ "10.13.12.2/32" "fd00:b12f:acab:1312:acab:2::/96" ]; - persistentKeepalive = 25; + persistentKeepalive = 30; + dynamicEndpointRefreshSeconds = 30; } { # droppie publicKey = "qsnBMoj9Z16D8PJ5ummRtIfT5AiMpoF3SoOCo4sbyiw="; @@ -70,8 +72,8 @@ "10.13.12.3/32" "fd00:b12f:acab:1312:acab:3::/96" ]; - - persistentKeepalive = 25; + persistentKeepalive = 30; + dynamicEndpointRefreshSeconds = 30; } { # chocolatebar publicKey = "nk8EtGE/QsnSEm1lhLS3/w83nOBD2OGYhODIf92G91A="; @@ -79,8 +81,8 @@ "10.13.12.5/32" "fd00:b12f:acab:1312:acab:5::/96" ]; - - persistentKeepalive = 25; + persistentKeepalive = 30; + dynamicEndpointRefreshSeconds = 30; } { # biolimo publicKey = "4ymN7wwBuhF+h+5fFN0TqXmVyOe1AsWiTqRL0jJ3CDc="; @@ -88,8 +90,8 @@ "10.13.12.6/32" "fd00:b12f:acab:1312:acab:6::/96" ]; - - persistentKeepalive = 25; + persistentKeepalive = 30; + dynamicEndpointRefreshSeconds = 30; } { # stroopwafel publicKey = "5iNRg13utOJ30pX2Z8SjwPNUFwfH2zonlbeYW2mKFkU="; @@ -97,8 +99,8 @@ "10.13.12.8/32" "fd00:b12f:acab:1312:acab:8::/96" ]; - - persistentKeepalive = 25; + persistentKeepalive = 30; + dynamicEndpointRefreshSeconds = 30; } ]; }; diff --git a/hosts/stroopwafel/networking.nix b/hosts/stroopwafel/networking.nix index e77512d..2931f3c 100644 --- a/hosts/stroopwafel/networking.nix +++ b/hosts/stroopwafel/networking.nix @@ -18,14 +18,14 @@ privateKeyFile = config.age.secrets.wg-private-key.path; }; - age.secrets.wg-public-key.file = "${flake.self}/secrets/wg-public-stroopwafel.age"; + age.secrets.wg-tunnel-key.file = "${flake.self}/secrets/wg-tunnel-stroopwafel.age"; - pub-solar.wireguard.public = { + pub-solar.wireguard.tunnel = { ownIPs = [ - "10.68.3.133/32" - "fc00:bbbb:bbbb:bb01::5:384/128" + "10.65.141.174/32" + "fc00:bbbb:bbbb:bb01::2:8dad/128" ]; - privateKeyFile = config.age.secrets.wg-public-key.path; + privateKeyFile = config.age.secrets.wg-tunnel-key.path; peer = { publicKey = "5FZW+fNA2iVBSY99HFl+KjGc9AFVNE+UFAedLNhu8lc="; endpoint = "146.70.134.2:3565"; diff --git a/modules/wireguard/default.nix b/modules/wireguard/default.nix index d81502d..9fe3d48 100644 --- a/modules/wireguard/default.nix +++ b/modules/wireguard/default.nix @@ -6,6 +6,6 @@ }: { imports = [ ./private.nix - ./public.nix + ./tunnel.nix ]; } diff --git a/modules/wireguard/private.nix b/modules/wireguard/private.nix index 82cd8e1..f71d645 100644 --- a/modules/wireguard/private.nix +++ b/modules/wireguard/private.nix @@ -75,9 +75,13 @@ in { + (if cfg.fullTunnel then '' defaultRoute=$(${pkgs.iproute2}/bin/ip r | ${pkgs.gnugrep}/bin/grep "default via" | head -n 1 | ${pkgs.gawk}/bin/awk '{ print $3 " " $4 " " $5 }') ipv4=$(${pkgs.dnsutils}/bin/dig +short A vpn.b12f.io) - ${pkgs.iproute2}/bin/ip route add $ipv4 via $defaultRoute + ${pkgs.iproute2}/bin/ip route add $ipv4 metric 256 via $defaultRoute ipv6=$(${pkgs.dnsutils}/bin/dig +short AAAA vpn.b12f.io) - ${pkgs.iproute2}/bin/ip route add $ipv6 via $defaultRoute + ${pkgs.iproute2}/bin/ip route add $ipv6 metric 256 via $defaultRoute + ip -4 route delete default dev wg-private || true + ip -4 route replace default dev wg-private metric 512 + ip -6 route delete default dev wg-private || true + ip -6 route replace default dev wg-private metric 512 '' else ""); postShutdown = lib.mkIf cfg.useDNS '' resolvconf -d wg-private -f @@ -94,7 +98,8 @@ in { "::/0" ] else []); endpoint = "vpn.b12f.io:51899"; - persistentKeepalive = 25; + persistentKeepalive = 30; + dynamicEndpointRefreshSeconds = 30; } ]; }; diff --git a/modules/wireguard/public.nix b/modules/wireguard/public.nix deleted file mode 100644 index 8b8fd01..0000000 --- a/modules/wireguard/public.nix +++ /dev/null @@ -1,83 +0,0 @@ -{ - lib, - config, - pkgs, - ... -}: -with lib; let - psCfg = config.pub-solar; - cfg = config.pub-solar.wireguard.public; -in { - options.pub-solar.wireguard.public = { - ownIPs = mkOption { - description = "Internal ips in wireguard used for cluster control-plane communication."; - type = types.listOf types.str; - default = []; - }; - - privateKeyFile = mkOption { - description = "Location of private key file"; - type = types.path; - }; - - peer = { - publicKey = mkOption { - description = "Public key of the peer"; - type = types.str; - }; - endpoint = mkOption { - description = "Peer endpoint address"; - type = types.str; - }; - }; - - useDNS = mkOption { - description = "Whether to use the DNS of the interface as default"; - default = true; - type = types.bool; - }; - }; - - config = mkIf (length cfg.ownIPs != 0){ - networking.firewall.allowedUDPPorts = [51820]; - - systemd.services.wireguard-wg-public = mkIf (length config.pub-solar.wireguard.private.ownIPs != 0) { - after = [ "wireguard-wg-private.service" ]; - }; - - networking.wireguard.interfaces = { - wg-public = { - listenPort = 51820; - ips = cfg.ownIPs; - privateKeyFile = cfg.privateKeyFile; - postSetup = let - splitEndpoint = (strings.splitString ":" cfg.peer.endpoint); - joinIPV6 = p: ip: p + (if (stringLength ip > 0) then ":" else "") + ip; - isIPV4 = length splitEndpoint < 3; - endpointIP = (if isIPV4 - then elemAt splitEndpoint 0 - else lists.fold joinIPV6 "" ((lists.take ((length splitEndpoint) - 1)) splitEndpoint) - ); - in mkIf cfg.useDNS '' - printf "nameserver 10.64.0.1" | resolvconf -a wg-public -m 0 -x - defaultRoute=$(${pkgs.iproute2}/bin/ip r | ${pkgs.gnugrep}/bin/grep "default via" | head -n 1 | ${pkgs.gawk}/bin/awk '{ print $3 " " $4 " " $5 }') - ${pkgs.iproute2}/bin/ip ${if isIPV4 then "" else "-6"} route add ${endpointIP}${if isIPV4 then "" else "/128"} via $defaultRoute - ''; - postShutdown = mkIf cfg.useDNS '' - resolvconf -d wg-public -f - ''; - peers = [ - { - publicKey = cfg.peer.publicKey; - allowedIPs = [ - "0.0.0.0/0" - "::/0" - ]; - endpoint = cfg.peer.endpoint; - persistentKeepalive = 25; - } - ]; - }; - }; - }; -} diff --git a/modules/wireguard/tunnel.nix b/modules/wireguard/tunnel.nix new file mode 100644 index 0000000..747f668 --- /dev/null +++ b/modules/wireguard/tunnel.nix @@ -0,0 +1,96 @@ +{ + lib, + config, + pkgs, + ... +}: +with lib; let + psCfg = config.pub-solar; + cfg = config.pub-solar.wireguard.tunnel; +in { + options.pub-solar.wireguard.tunnel = { + ownIPs = mkOption { + description = "Internal ips in wireguard used for cluster control-plane communication."; + type = types.listOf types.str; + default = []; + }; + + privateKeyFile = mkOption { + description = "Location of private key file"; + type = types.path; + }; + + peer = { + publicKey = mkOption { + description = "Public key of the peer"; + type = types.str; + }; + endpoint = mkOption { + description = "Peer endpoint address"; + type = types.str; + }; + }; + + useDNS = mkOption { + description = "Whether to use the DNS of the interface as default"; + default = false; + type = types.bool; + }; + }; + + config = mkIf (length cfg.ownIPs != 0){ + networking.firewall.allowedUDPPorts = [51820]; + + systemd.services.wireguard-wg-tunnel = mkIf (length config.pub-solar.wireguard.private.ownIPs != 0) { + after = [ "wireguard-wg-private.service" ]; + }; + + networking.wireguard.interfaces = let + splitEndpoint = (strings.splitString ":" cfg.peer.endpoint); + joinIPV6 = p: ip: p + (if (stringLength ip > 0) then ":" else "") + ip; + isIPV4 = length splitEndpoint < 3; + ipFlag = if isIPV4 then "-4" else "-6"; + endpointIP = (if isIPV4 + then elemAt splitEndpoint 0 + else lists.fold joinIPV6 "" ((lists.take ((length splitEndpoint) - 1)) splitEndpoint) + ); + endpointIPStripped = strings.removePrefix "[" (strings.removeSuffix "]" endpointIP); + in { + wg-tunnel = { + listenPort = 51820; + ips = cfg.ownIPs; + privateKeyFile = cfg.privateKeyFile; + postSetup = '' + defaultRoute=$(${pkgs.iproute2}/bin/ip ${ipFlag} r | ${pkgs.gnugrep}/bin/grep "default via" | head -n 1 | ${pkgs.gawk}/bin/awk '{ print $3 " " $4 " " $5 }') + ${pkgs.iproute2}/bin/ip ${ipFlag} route add "${endpointIPStripped}${if isIPV4 then "/32" else "/128"}" metric 256 via $defaultRoute + ip -4 route delete default dev wg-tunnel || true + ip -4 route add default dev wg-tunnel metric 512 + ip -6 route delete default dev wg-tunnel || true + ip -6 route add default dev wg-tunnel metric 512 + '' + (if cfg.useDNS + then ''printf "nameserver 10.64.0.1" | resolvconf -a wg-tunnel -m 0 -x'' + else ""); + postShutdown = '' + addedRoute=$(${pkgs.iproute2}/bin/ip ${ipFlag} r | ${pkgs.gnugrep}/bin/grep "${endpointIPStripped}" | head -n 1 | ${pkgs.gawk}/bin/awk '{ print $1 " " $2 " " $3 " " $4 " " $5 }') + if [ -n "$addedRoute" ]; then + ${pkgs.iproute2}/bin/ip ${ipFlag} route delete $addedRoute + fi + '' + (if cfg.useDNS + then ''resolvconf -d wg-tunnel -f'' + else ""); + peers = [ + { + publicKey = cfg.peer.publicKey; + allowedIPs = [ + "0.0.0.0/0" + "::/0" + ]; + endpoint = cfg.peer.endpoint; + persistentKeepalive = 30; + dynamicEndpointRefreshSeconds = 30; + } + ]; + }; + }; + }; +} diff --git a/secrets/secrets.nix b/secrets/secrets.nix index f4c9af1..5d316ea 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -80,8 +80,8 @@ in { "wg-private-droppie.age".publicKeys = droppieKeys ++ baseKeys; "wg-private-frikandel-server.age".publicKeys = frikandelKeys ++ baseKeys; - "wg-public-stroopwafel.age".publicKeys = stroopwafelKeys ++ baseKeys; - "wg-public-droppie.age".publicKeys = droppieKeys ++ baseKeys; + "wg-tunnel-stroopwafel.age".publicKeys = stroopwafelKeys ++ baseKeys; + "wg-tunnel-droppie.age".publicKeys = droppieKeys ++ baseKeys; "invoiceplane-db-password.age".publicKeys = pieKeys ++ baseKeys; "invoiceplane-db-secrets.env.age".publicKeys = pieKeys ++ baseKeys; diff --git a/secrets/wg-public-stroopwafel.age b/secrets/wg-public-stroopwafel.age deleted file mode 100644 index d3a28f80feb2f67508d32af1d77107e94834216e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1227 zcmY+?JL~IY0Dy6EP>JB;a@-0>5D7JJ-ZV+OsLi#PT$;3L(zuv3$(uIU=H4I(XLT1G z9CQ*CJRd+5oZJ+2b8-^DgYx&B!NE`PgNMgM;WW(8)xB&kMgC4vA)+I(>ARD+H=Ps{%II&GZ)b`?GD%^B%~gI%jjO zHs?iuxtk*wI|fw`{MtOR>Do^hMsZ$Gi3<6Y)eW;AhATUX_#iru*inAwJSJlAi%}tlw7^MZXGX8c z>!~eH3Y*kx!3I2S?R_+kI(^I>t%v#|01#`}S=zyBGcFo7%=-f{y;}6)XwU0DHc|t~ zqEG4hkts$}p=07S9=edYhbOB%qTASGt;8-H?#@Z%Y7Dn@%%1L4Gczt@bhRiw6J?w# zgN5WSXU9#{SA`P9JMo+W$=d4svfX20b1l|Xs#|0s%bEG$NemJLXqdl{q4vt zYV9np2^XGnZZruLM+ip@eO0l05$Hg`(|jjTTTn|1N*cs#u3*7rtp-Y3t%%MVs56Xd zW}a+%WiRyfT%|S;Oc{2WO%zxD!GE{HR{s`Py0bWD`^h}m|D7<(c{;fmd5txVA# zSB{My4lG@fF|Vp30n$U%v;u|fyXBF_|E$g&ciJTp6~hJI*N3DVGIiq@eZ#1mWIud(TLIzjS+8LMjLpCsKMb3!N!$g6d!rADo0 zv$h?qNEy=A(XucCJ^t{!H-2Y7dh+#Klxe;9^vOTJJ{n*C>9bEie)yvK`{8@;btLS^ um%jbxRqmCyfBOad;QgP!Y+rnV|Le!eQv!Yd$5#)3{*d*LyiZ;$gMR_Fw3ZkE diff --git a/secrets/wg-public-droppie.age b/secrets/wg-tunnel-droppie.age similarity index 100% rename from secrets/wg-public-droppie.age rename to secrets/wg-tunnel-droppie.age diff --git a/secrets/wg-tunnel-stroopwafel.age b/secrets/wg-tunnel-stroopwafel.age new file mode 100644 index 0000000..81c1af8 --- /dev/null +++ b/secrets/wg-tunnel-stroopwafel.age @@ -0,0 +1,24 @@ +age-encryption.org/v1 +-> ssh-ed25519 b0WFDg SR5wr78Fr0kObzfzfr1UwFukdELVPZ5hht71Fa5fFxs +3QndmGk9sbYth4QskAV1L8aVqK3JvIQo7wmo6tMsvMg +-> ssh-rsa kFDS0A +T6+WM2QvqQVErNTl8Fww+zCU6jA8gtZwFjZzeTlKxUMkAizae5X7ahsii9yRB6Sq +d1eHjzSqfO87lTDyX/QTL88Gf07wpGYKMuphQheA+mFUQwUlGauhCXFcPH+hs1t/ +NRQLwqPnDp0tIL3toBbYMMyUSR170IEM76c0Q5aU6JCYN+lhFAJS7z3jN/uAOzlG +KUnDtf/KV35jpIIW9rkkReOLHvFAkgtw2il6FVUq1OPN8Kkyl/HWOIAslC+ct/Ui +459Cv0m3Keaa1lBOTa9UnrJrIevNZE7V3N0XZMvoYLPgNZisUvblyrJABQRAKA8g +ivGn3l8DifN9UJwpW1SP/fej4ZqPZrrBUld4eerxoKyxLBqlrGiCBA3aYXsH6szS +ke7K0G2/q+wUsGd7zaXuwSoozbcRb9hbz2BlVVeyPJwlkt9HmLDMCFLbN+l4/72j +9tUrkmloKliyRPEOWmL+cVzzMZR7qZMPUmhW+N6Pb74KsfItfwoauJff2oNefC6u +ngJbErZLBplpBYDYMlPXPXWj0D1ZJXQj99fu1kPuKY0O7ji2COewR2yCcuox7Ecd +Zg8NyID97l6Gqy2MXOJU+QT7o9b6d0wm43X0nuSfbMnkjBsyYs+s4vzeRwC63J3K +9xG+0qk9DPTaIvsxwjNL1022/SPXJWFtTI1PMVrnJP4 +-> piv-p256 zqq/iw AhBisE2Fe0vaKERI8QXX4PkYrl15sVVB4Gvhb+ztzYd3 +fyrDkCPy3uDC0V3QIxZ+pcEgYCaBTaRnQpyMykHOMrY +-> piv-p256 vRzPNw A3cCq7Gh+pCEKMb4fuAAeYGKOCroXeoIaz0uV9PVpAY9 +sLd2F+4tMlRcslGQIXMkTDkfc6IQZZoywI3Cf/nFuEk +-> \b*z-grease +GMVOh1rMrdQqWp9U263dPc3h1ngcEsrE/ZUmtgD7urq6KsqnQaS0WJqtsZ5VzbWS + +--- A+ftgvNAqu9R+3wZSILocxfuTN782u1YzEvjIE1Lp9I +NiBOYhP:;{XJԎ7ѡH6!_MSֹGI?º/ \ No newline at end of file