diff --git a/machines/shinobu/secrets.yaml b/machines/shinobu/secrets.yaml index 9e1245a..0219aa6 100644 --- a/machines/shinobu/secrets.yaml +++ b/machines/shinobu/secrets.yaml @@ -1,3 +1,4 @@ +wg-he-private-key: ENC[AES256_GCM,data:bT1G2nZHJO9j04I4j3QZYn7BxGX4XHxzgXDr3iFTnu/kirik6+0Eh/AUp+4=,iv:SeowjlP64t8lPn+WXqrOtZJWA3geTSO9ST9JNuPQwu0=,tag:ctLXe7BP0Ob/ADD4q7yOmg==,type:str] wg-home-private-key: ENC[AES256_GCM,data:gm4INfmp226u4wp+LuKgf5m2nTFFw4S24w4PRPcW/A7CU713c9NtQ+kPDKg=,iv:JAir9z5/Db6+Oroq+0vXPZLZLA2gjY2Be6hRAmgV5AE=,tag:fxL9nK3v5xERfcoBbCUsXg==,type:str] wg-upstream-private-key: ENC[AES256_GCM,data:CO50H7QsLQ2x0QQXnB7c0leG8NdV66gWrdWBWOR9z4ukSN7qj/qqe83t82k=,iv:2as2HfTfRje3TEap8QpPfzz4saNDgjo6Ty1DTF23JVE=,tag:ZYe+59wrpX7mV1HcDllMdg==,type:str] hostapd-config: ENC[AES256_GCM,data:a0ESrrsquLq6VRJM588C5A+FmVxJwJSzwRuv2o//LL5OybcDS8jkVUajosXEs0qmQ6Xfc1gFDcevCYUwJ24eZ+ynKLWwoNx8RXXwbpllO7FkI68vcauUij1CtUgVb8aHheKfrFuyW7WU1wE3NTtOt2gij1+nM3iKS3vFXtX2n9L2fuy2b3EhOUBiakxAeQmyVmclSVBDYt12i4h4tW7GpPr8AjoIiZgz0Hyx5zA5f/JTPzz/P200eM0tCttNPbMNPBGztJfw7raRIX+v6xw7QNPMgf03TOae17mt6uggTNKJfEPeanzcEMA3xR6xoFUqJL6Hvowyl4MrSFc+E5Rvft+qhp8m6tAqQln9Z3MzaDtxSBWnWdvWEcyeK1aDBQ57/aIwo8kVs47Iblqbi5+jM/n4DoeQtqTM1kS7sZ3XDQ26suW5KCw+VIeqEEqdu6g5ZXMO2SipSOzP5jPjX+5ubX3SXcyoAIo41Efa6YGdWtl3,iv:oLk5tatZEY5AI/PlTBJHShGCKiyvve9rPhGARAtMMj4=,tag:Bkan2Hff8L8ZcC67r+fWjg==,type:str] @@ -7,8 +8,8 @@ sops: azure_kv: [] hc_vault: [] age: [] - lastmodified: "2023-08-08T09:43:37Z" - mac: ENC[AES256_GCM,data:lxoKzGyPwdfeI5Dlmgx9K9SBhfRIaokvum+dJWABUoGtIMtrhp4K4ZRF1Rjja8oTi4w3b+s9aUBpxt8TLu9vJZFsUkhY2gqW5bX3Ub/3xMAR9YSG3LtijRSMuKkdVlAkdjB6Guz9aHNVBG3fTZ+SfTlyOQdImW6bK4tydbGHKgY=,iv:6kVR4zZfHnqhcOT3N2tClGST8h7FLjIseXDu2xS2DEY=,tag:rd/f7cHSoxLT3O7HluVWLA==,type:str] + lastmodified: "2024-08-26T18:50:19Z" + mac: ENC[AES256_GCM,data:k26ZEKuFtS0GLMqFIbY0QiVfHvmpxt3JgLvZIhEHcC3wQ80OhRNeyKocZhua1T5iSfhfvlckXYZl6tTZkCEh4fj3NmYMtQ9vwpoexdYWwx5ylPT3rpByfBbO+foHgQ3JXk6Kyt2R9ULjghMU3/lEcsG4AuGU1XMomsTzrdigXY8=,iv:ls3nIFIwTM//tSvee/aHj6Qv2nn/gZMKgGF+aQWNxeg=,tag:l58uHLpvPfIkbUn9gl+lzg==,type:str] pgp: - created_at: "2024-01-22T00:20:19Z" enc: |- @@ -79,4 +80,4 @@ sops: -----END PGP MESSAGE----- fp: 28677f2e3584b39f528a779caf445ebb39c882b7 unencrypted_suffix: _unencrypted - version: 3.7.3 + version: 3.8.1 diff --git a/machines/shinobu/services/router/common.nix b/machines/shinobu/services/router/common.nix index d85cfa3..f2a214d 100644 --- a/machines/shinobu/services/router/common.nix +++ b/machines/shinobu/services/router/common.nix @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2023 Simon Bruder +# SPDX-FileCopyrightText: 2023-2024 Simon Bruder # # SPDX-License-Identifier: AGPL-3.0-or-later @@ -35,22 +35,22 @@ in vlan = { lan = { id = 10; - subnet = mkSubnet "10.80.1.0/24" "fd00:80:1::/64"; + subnet = mkSubnet "10.80.1.0/24" "2001:470:73b9:1::/64"; domain = "lan.shinonome-lab.de"; }; management = { id = 20; - subnet = mkSubnet "10.80.2.0/24" "fd00:80:2::/64"; + subnet = mkSubnet "10.80.2.0/24" "2001:470:73b9:2::/64"; domain = "management.shinonome-lab.de"; }; guest = { id = 30; - subnet = mkSubnet "10.80.3.0/24" "fd00:80:3::/64"; + subnet = mkSubnet "10.80.3.0/24" "2001:470:73b9:3::/64"; domain = "guest.shinonome-lab.de"; }; iot = { id = 40; - subnet = mkSubnet "10.80.4.0/24" "fd00:80:4::/64"; + subnet = mkSubnet "10.80.4.0/24" "2001:470:73b9:4::/64"; domain = "iot.shinonome-lab.de"; }; }; diff --git a/machines/shinobu/services/router/default.nix b/machines/shinobu/services/router/default.nix index a66af45..8710a6a 100644 --- a/machines/shinobu/services/router/default.nix +++ b/machines/shinobu/services/router/default.nix @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2023 Simon Bruder +# SPDX-FileCopyrightText: 2023-2024 Simon Bruder # # SPDX-License-Identifier: AGPL-3.0-or-later @@ -36,6 +36,8 @@ in ./tc.nix ]; + sbruder.wireguard.he.enable = true; + boot.kernel.sysctl = { "net.ipv4.conf.all.forwarding" = true; "net.ipv6.conf.all.forwarding" = true; @@ -106,6 +108,7 @@ in # Only use RA DHCPv6Client = false; UseDNS = "no"; + UseGateway = false; # should not be used by default for routing (wg-he takes precendence) }; }; physical-lan = { @@ -128,6 +131,13 @@ in name = "enp4s0"; bridge = [ "br-lan" ]; }; + # extended from common config + wg-he = { + address = lib.singleton "2001:470:73b9::1"; + routes = lib.singleton { + routeConfig.Gateway = "::"; # on link + }; + }; } ]; }; diff --git a/machines/shinobu/services/router/dnsmasq.nix b/machines/shinobu/services/router/dnsmasq.nix index 7bfb7b6..7b3e432 100644 --- a/machines/shinobu/services/router/dnsmasq.nix +++ b/machines/shinobu/services/router/dnsmasq.nix @@ -54,6 +54,12 @@ in server = [ "127.0.0.1#5053" ]; + + # Authoritative zones for external reachability (only AAAA records) + auth-server = "shinobu.shinonome-lab.de,2001:470:73b9::1"; + auth-zone = map + (vlan: "${vlan.domain},${vlan.subnet.v6.cidr}") + (lib.attrValues cfg.vlan); }; }; systemd.services.dnsmasq.after = [ "systemd-networkd.service" ]; diff --git a/machines/shinobu/services/router/rules.nft b/machines/shinobu/services/router/rules.nft index 169425f..05cdaed 100644 --- a/machines/shinobu/services/router/rules.nft +++ b/machines/shinobu/services/router/rules.nft @@ -4,34 +4,51 @@ define NAT_LAN_IFACES = { "br-lan", "br-guest" } define PHYSICAL_WAN = "enp1s0" +# only includes interfaces that use NAT define NAT_WAN_IFACES = { $PHYSICAL_WAN } +# also includes interfaces that do not use NAT +define WAN_IFACES = { $NAT_WAN_IFACES, "wg-he" } table inet filter { chain forward { type filter hook forward priority filter; policy drop + # Use MSS clamping to avoid too large packets not going through the tunnel. + tcp flags syn / syn,rst tcp option maxseg size set rt mtu + # plastic router, might be vulnerable (FIXME v6 is still reachable) iifname "br-guest" ip daddr "192.168.0.1" drop # allow traffic between selected VLANs and wan - iifname $NAT_LAN_IFACES oifname $NAT_WAN_IFACES counter accept - iifname $NAT_WAN_IFACES oifname $NAT_LAN_IFACES ct state established,related counter accept + iifname $NAT_LAN_IFACES oifname $WAN_IFACES counter accept + iifname $WAN_IFACES oifname $NAT_LAN_IFACES ct state established,related counter accept + + # allow lan clients to be publicly reachable + iifname "wg-he" oifname "br-lan" counter accept # traffic from lan to all other vlans is allowed iifname "br-lan" oifname $VLAN_BRIDGES counter accept; iifname $VLAN_BRIDGES oifname "br-lan" ct state established,related counter accept - iifname $NAT_WAN_IFACES oifname "br-iot" ct state established,related counter accept + iifname $WAN_IFACES oifname "br-iot" ct state established,related counter accept } } -table inet nat { +table ip nat { chain postrouting { type nat hook postrouting priority filter; policy accept oifname $NAT_WAN_IFACES masquerade } } +table ip6 public-access { + chain input { + type filter hook input priority filter; policy accept + + iifname "wg-he" oifname "br-lan" counter accept + } +} + # Only allow select connections from and to (physical) wan, # overriding NixOS firewall in some cases. table inet restrict-wan { diff --git a/machines/yuzuru/configuration.nix b/machines/yuzuru/configuration.nix index e873c1c..d46c940 100644 --- a/machines/yuzuru/configuration.nix +++ b/machines/yuzuru/configuration.nix @@ -16,7 +16,10 @@ sbruder = { nginx.hardening.enable = true; full = false; - wireguard.home.enable = true; + wireguard = { + he.enable = true; + home.enable = true; + }; infovhost.enable = true; }; diff --git a/machines/yuzuru/secrets.yaml b/machines/yuzuru/secrets.yaml index ff423c9..bb10668 100644 --- a/machines/yuzuru/secrets.yaml +++ b/machines/yuzuru/secrets.yaml @@ -1,3 +1,4 @@ +wg-he-private-key: ENC[AES256_GCM,data:aTH+AUBgG2D1CUF0zp1OzTUBu5Td2J2fsq3EpYEUuPGQFA+EbAYS+4AEipg=,iv:vNkqtoixZ+I+C5L4Vbck3EhCYGKzzIvwHIjiNs5PPIQ=,tag:6SMQ9oqKd7FdLvQNt2SAYA==,type:str] wg-home-private-key: ENC[AES256_GCM,data:0ylkx9p62CBGqVg+T52eHbMwbLcZM/v3tg/wJukDq76heN1TtQqbbqgVZKc=,iv:/aUkqKhihnBWQFLIRjS7kHigBCBXX7L4KY5q+cO9Q00=,tag:jQSMVElMfIyrG5hs7HuxUQ==,type:str] li7y-environment: ENC[AES256_GCM,data:cm4+672JelbYsBm0rwrF/I9gS72XfAlj335v0+EfXmPSD1LCBJ3clR7jZC7SVH5D9ZSaSlrY8J/+7hgDmzsiR2kypNBvfMvN825AF5QFehnYeHhxUktU+uig7RzpRUeWSPM0r8j6lmpGNc7vd3S+L3TWn2ZfCJ8Kc28Ad2M9yFiZ7PPqB6qqLnsx2peQuafDhefuohLPOYA=,iv:84yL6l7zqeb7l3w3ARskJoQEvI1+HxoCCKrLhB0kx7E=,tag:GCetAOW7pvyjKEM26A9ZbA==,type:str] sops: @@ -6,8 +7,8 @@ sops: azure_kv: [] hc_vault: [] age: [] - lastmodified: "2024-07-14T17:32:43Z" - mac: ENC[AES256_GCM,data:7D9xHNpdhI6CgX94PAoJJIJqVZ403ZL7dXbdnod2do4M+Qf0yRrRDxi6hPipf0BX0vsSq1npdiXcnwP50PZHal8LW7IJRjfefW5WnO+BLD42sIxt5mikdNfZhpyg3dHB7j+8m1lE1+veK/Ho06V32sckibhBG4AFBfMZ/k1VIns=,iv:NS9CaSyEUdmJEKFejiaugtZ5Nf8norhoaCaOwPZsxow=,tag:Y2Nu92iYO0PSqtXMLc3D7g==,type:str] + lastmodified: "2024-08-26T17:49:34Z" + mac: ENC[AES256_GCM,data:tnjZq65XULfFeEa7fDwTbOFTgjyvZ+UHW+T7Hqny3kzUb5bgaX6D3Xj2Ij0CrTxgyEzRLpkBG/TpEDdY1//NaruGl6CDYmYHEb5yHAzDRzpbPoZhteGfyuiRKGblK3EvMWpj2x4ZTnO7Y13fGpOzA5o38maAZL3eYPUb2yueD58=,iv:70dlzD6/uteJZZMo2T5R+H7QvZH60AWDrwc8iljIEb4=,tag:ADWZObS6Aq/iwRLPLlqPjg==,type:str] pgp: - created_at: "2024-01-22T00:20:20Z" enc: |- diff --git a/modules/wireguard/default.nix b/modules/wireguard/default.nix index c06f856..d464ab5 100644 --- a/modules/wireguard/default.nix +++ b/modules/wireguard/default.nix @@ -1,9 +1,10 @@ -# SPDX-FileCopyrightText: 2020-2023 Simon Bruder +# SPDX-FileCopyrightText: 2020-2024 Simon Bruder # # SPDX-License-Identifier: AGPL-3.0-or-later { imports = [ + ./he.nix ./home.nix ./support.nix ]; diff --git a/modules/wireguard/he.nix b/modules/wireguard/he.nix new file mode 100644 index 0000000..008c9c9 --- /dev/null +++ b/modules/wireguard/he.nix @@ -0,0 +1,120 @@ +# SPDX-FileCopyrightText: 2020-2024 Simon Bruder +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +{ lib, config, ... }: +let + serverHostName = "yuzuru"; + serverPort = 51820; + peers = { + yuzuru = { + subnets = [ ]; + publicKey = "mWm92aZybisoLtd11g4XqwUZvQGVxMfPW9/za3/1/0Y="; + }; + shinobu = { + subnets = [ "2001:470:73b9::/56" ]; + publicKey = "c8lnzMWFeTzQmXwNV0DlD2ROJqBcDL0F9WN5u4lVeFQ="; + }; + }; + + cfg = config.sbruder.wireguard.he; + enableServer = config.networking.hostName == serverHostName; +in +{ + options.sbruder.wireguard.he.enable = lib.mkEnableOption "WireGuard tunnel wg-he"; + + config = lib.mkIf cfg.enable { + sops.secrets.wg-he-private-key = { + owner = config.users.users.systemd-network.name; + sopsFile = ./../../machines + "/${config.networking.hostName}/secrets.yaml"; + }; + + systemd.network = { + enable = true; + netdevs = { + wg-he = { + netdevConfig = { + Kind = "wireguard"; + Name = "wg-he"; + }; + wireguardConfig = { + PrivateKeyFile = config.sops.secrets.wg-he-private-key.path; + } // (lib.optionalAttrs enableServer { + ListenPort = serverPort; + }); + wireguardPeers = + if enableServer + then + map + ({ publicKey, subnets }: { + wireguardPeerConfig = { + PublicKey = publicKey; + AllowedIPs = subnets; + }; + }) + (lib.attrValues + (lib.filterAttrs + (n: v: n != config.networking.hostName) + peers)) + else + lib.singleton { + wireguardPeerConfig = { + PublicKey = peers."${serverHostName}".publicKey; + AllowedIPs = "::/0"; + Endpoint = "85.215.73.203:${toString serverPort}"; + PersistentKeepalive = 25; + }; + }; + }; + } // (lib.optionalAttrs enableServer { + he = { + netdevConfig = { + Name = "he"; + Kind = "sit"; + MTUBytes = "1480"; + }; + tunnelConfig = { + Remote = "216.66.80.30"; # tserv1.fra1.he.net + Local = "85.215.73.203"; + TTL = 255; + }; + }; + }); + networks = { + wg-he = { + name = "wg-he"; + networkConfig = lib.optionalAttrs enableServer { + IPForward = "ipv6"; + }; + routes = lib.singleton { + routeConfig.Destination = "2001:470:73b9::/48"; + }; + }; + } // (lib.optionalAttrs enableServer { + he = { + name = "he"; + address = lib.singleton "2001:470:1f0a:5db::2/64"; + gateway = lib.singleton "2001:470:1f0a:5db::1"; + routingPolicyRules = lib.singleton { + routingPolicyRuleConfig = { + From = "2001:470:73b9::/48"; + Table = "0x73b9"; + }; + }; + routes = lib.singleton { + routeConfig = { + Gateway = "2001:470:1f0a:5db::1"; + Table = "0x73b9"; + }; + }; + }; + # FIXME interface name is hardcoded + eth0 = { + networkConfig.Tunnel = "he"; + }; + }); + }; + + networking.firewall.allowedUDPPorts = lib.optional enableServer serverPort; + }; +}