From deab5b335ee19e235d48e58dffeaac61fa24a1c4 Mon Sep 17 00:00:00 2001 From: oddlama Date: Fri, 21 Apr 2023 01:27:43 +0200 Subject: [PATCH] feat: add zoned nftables firewall --- hosts/common/core/default.nix | 14 ++++ hosts/common/core/net.nix | 57 ++++++++++++- hosts/common/core/resolved.nix | 11 +-- hosts/ward/meta.nix | 4 +- hosts/ward/net.nix | 127 +++++++++++++++++++++++++++-- hosts/ward/secrets/secrets.nix.age | Bin 480 -> 503 bytes hosts/zackbiene/net.nix | 34 +++++++- modules/wireguard.nix | 1 + nix/generate-node.nix | 2 +- nix/lib.nix | 2 + 10 files changed, 229 insertions(+), 23 deletions(-) diff --git a/hosts/common/core/default.nix b/hosts/common/core/default.nix index 4ed8ff7..f5b2e2e 100644 --- a/hosts/common/core/default.nix +++ b/hosts/common/core/default.nix @@ -19,6 +19,20 @@ ../../../modules/wireguard.nix ]; + # IP address math library + # https://gist.github.com/duairc/5c9bb3c922e5d501a1edb9e7b3b845ba + # Plus some extensions by us + lib = let + libWithNet = (import "${inputs.lib-net}/net.nix" {inherit lib;}).lib; + in + lib.recursiveUpdate libWithNet { + net.cidr = rec { + hostCidr = n: x: "${libWithNet.net.cidr.host n x}/${libWithNet.net.cidr.length x}"; + ip = x: lib.head (lib.splitString "/" x); + canonicalize = x: libWithNet.net.cidr.make (libWithNet.net.cidr.length x) (ip x); + }; + }; + # Setup secret rekeying parameters rekey = { inherit diff --git a/hosts/common/core/net.nix b/hosts/common/core/net.nix index 40bc9b7..b42f47c 100644 --- a/hosts/common/core/net.nix +++ b/hosts/common/core/net.nix @@ -1,4 +1,5 @@ { + config, lib, pkgs, nodeName, @@ -8,6 +9,7 @@ inherit (lib) concatStringsSep + head mapAttrsToList mkDefault mkForce @@ -17,10 +19,59 @@ in { hostName = mkDefault nodeName; useDHCP = mkForce false; useNetworkd = true; - wireguard.enable = true; dhcpcd.enable = false; - nftables.enable = true; - firewall.enable = true; + + nftables = { + firewall.enable = true; + stopRuleset = mkDefault '' + table inet filter { + chain input { + type filter hook input priority filter; policy drop; + ct state invalid drop + ct state {established, related} accept + + iifname lo accept + meta l4proto ipv6-icmp accept + meta l4proto icmp accept + tcp dport ${toString (head config.services.openssh.ports)} accept + } + chain forward { + type filter hook forward priority filter; policy drop; + } + chain output { + type filter hook output priority filter; policy accept; + } + } + ''; + }; + + nftables.firewall = { + zones = lib.mkForce { + local.localZone = true; + }; + + rules = lib.mkForce { + icmp = { + early = true; + after = ["ct"]; + from = "all"; + to = ["local"]; + extraLines = [ + "ip6 nexthdr icmpv6 icmpv6 type { echo-request, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept" + "ip protocol icmp icmp type { echo-request, router-advertisement } accept" + #"ip6 saddr fe80::/10 ip6 daddr fe80::/10 udp dport 546 accept" + ]; + }; + + ssh = { + early = true; + after = ["ct"]; + from = "all"; + to = ["local"]; + allowedTCPPorts = config.services.openssh.ports; + }; + }; + }; }; # Rename known network interfaces diff --git a/hosts/common/core/resolved.nix b/hosts/common/core/resolved.nix index 9e75dcb..0e610e1 100644 --- a/hosts/common/core/resolved.nix +++ b/hosts/common/core/resolved.nix @@ -1,10 +1,7 @@ {lib, ...}: { - networking = { - firewall = { - allowedTCPPorts = [5355]; - allowedUDPPorts = [5353 5355]; - }; - networkmanager.dns = "systemd-resolved"; + networking.firewall = { + allowedTCPPorts = [5355]; + allowedUDPPorts = [5353 5355]; }; services.resolved = { @@ -16,7 +13,7 @@ "8.8.8.8" "2001:4860:4860::8844" ]; - llmnr = "true"; + llmnr = "true"; # Microsoft's version of mDNS extraConfig = '' Domains=~. MulticastDNS=true diff --git a/hosts/ward/meta.nix b/hosts/ward/meta.nix index 4aeb0af..35f371c 100644 --- a/hosts/ward/meta.nix +++ b/hosts/ward/meta.nix @@ -3,7 +3,7 @@ system = "x86_64-linux"; microVmHost = true; physicalConnections = { - "10-lan1" = "LAN 1"; - "10-lan2" = "LAN 2"; + "10-lan" = "LAN"; + "10-wan" = "WAN"; }; } diff --git a/hosts/ward/net.nix b/hosts/ward/net.nix index 23298e1..9150760 100644 --- a/hosts/ward/net.nix +++ b/hosts/ward/net.nix @@ -1,27 +1,140 @@ { + config, lib, nodeSecrets, ... -}: { - networking.hostId = "49ce3b71"; +}: let + inherit (config.lib.net) cidr; + + net.lan.ipv4cidr = "192.168.100.1/24"; + net.lan.ipv6cidr = "fd01::1/64"; +in { + networking.hostId = nodeSecrets.networking.hostId; systemd.network.networks = { - "10-lan1" = { - DHCP = "yes"; - matchConfig.MACAddress = nodeSecrets.networking.interfaces.lan1.mac; + "10-lan" = { + address = [net.lan.ipv4cidr net.lan.ipv6cidr]; + matchConfig.MACAddress = nodeSecrets.networking.interfaces.lan.mac; networkConfig.IPv6PrivacyExtensions = "kernel"; dhcpV4Config.RouteMetric = 10; dhcpV6Config.RouteMetric = 10; }; - "10-lan2" = { + "10-wan" = { DHCP = "yes"; - matchConfig.MACAddress = nodeSecrets.networking.interfaces.lan2.mac; + #address = [ + # "192.168.178.2/24" + # "fd00::1/64" + #]; + #gateway = [ + #]; + matchConfig.MACAddress = nodeSecrets.networking.interfaces.wan.mac; networkConfig.IPv6PrivacyExtensions = "kernel"; dhcpV4Config.RouteMetric = 20; dhcpV6Config.RouteMetric = 20; }; }; + networking.nftables.firewall = { + zones = lib.mkForce { + lan = { + interfaces = ["lan"]; + ipv4Addresses = [(cidr.canonicalize net.lan.ipv4cidr)]; + ipv6Addresses = [(cidr.canonicalize net.lan.ipv6cidr)]; + }; + wan = { + interfaces = ["wan"]; + # TODO ipv4Addresses = [ net.wan.netv4 ]; + # TODO ipv6Addresses = [ net.wan.netv6 ]; + ipv4Addresses = ["192.168.1.0/22"]; + ipv6Addresses = ["fd00::/64"]; + }; + }; + + rules = lib.mkForce { + masquerade-wan = { + from = ["lan"]; + to = ["wan"]; + masquerade = true; + }; + + outbound = { + from = ["lan"]; + to = ["lan" "wan"]; + late = true; # Only accept after any rejects have been processed + verdict = "accept"; + }; + + wan-to-local = { + from = ["wan"]; + to = ["local"]; + }; + + lan-to-local = { + from = ["lan"]; + to = ["local"]; + + inherit + (config.networking.firewall) + allowedTCPPorts + allowedUDPPorts + ; + }; + }; + }; + + services.kea = { + dhcp4 = { + enable = true; + settings = { + lease-database = { + name = "/var/lib/kea/dhcp4.leases"; + persist = true; + type = "memfile"; + }; + valid-lifetime = 4000; + renew-timer = 1000; + rebind-timer = 2000; + interfaces-config = { + interfaces = ["lan"]; + service-sockets-max-retries = -1; + }; + option-data = [ + { + name = "domain-name-servers"; + data = "1.1.1.1, 8.8.8.8"; + } + ]; + subnet4 = [ + { + interface = "lan"; + subnet = cidr.canonicalize net.lan.ipv4cidr; + pools = [ + {pool = "192.168.100.20 - 192.168.100.250";} + ]; + option-data = [ + { + name = "routers"; + data = cidr.ip net.lan.ipv4cidr; + } + ]; + #reservations = [ + # { + # duid = "aa:bb:cc:dd:ee:ff"; + # ip-address = cidr.ip net.lan.ipv4cidr; + # } + #]; + } + ]; + }; + }; + #dhcp6 = { + # enable = true; + #}; + }; + systemd.services.kea-dhcp4-server.after = [ + "sys-subsystem-net-devices-lan.device" + ]; + #extra.wireguard.vms = { # server = { # enable = true; diff --git a/hosts/ward/secrets/secrets.nix.age b/hosts/ward/secrets/secrets.nix.age index 9ef1da0e5a405f83970637c8fdfbae128d195fa6..7990cb5b8f6d669cabccf436aa36e285b2af10c5 100644 GIT binary patch delta 481 zcmV<70UrL~1NQ@vAb)pvFj6s1XID2`LP>N>RbgUCS~X!sGEaAKL}YPMa#C(Dd2LH< zHdRq*NeX8xNpxjxWOY?lZ!~%@G)6Z>P;o1HHhFbIGGsArML1_!Q&weqG;MNcFbXX` zAaH4REpRe5HXwL$Q)M_&AVF_dWKu^^F9LUM3PYimR?N?K-k zQFu;aLUuJTY)T4xGEZkmD`IkHdTvW*IX5y@VNp*-a6xTraC$IyaCI|5MpbQ4V^(iB zOhpPUJ|ICYXL4m>b7df2S}6)QRa8}ZRdF*&HgHxnR#|#dXiYO_a5HXLXi*9+EiE8f zH!)dLc3MeSSbsKXP)tcPM>b1#H&<9=YC>#RM_4dON>O!4bU{aLF?uixuW2?J;r_m4 z^Lnsfga?0*NbgqX2+s9RMTUi-Nb0`7zym)&tfXScy;mD%|8@cTrl3Lw8_d8)A=2Z_&qD3V!SZp1q zszVJ5sZe@>F99}!K%hKN8Sf~fLSj1X9!tCW1TC0-8IB_ XlY_9tuUA*`OJ@vlPiQw^#s^_a;@r5t delta 458 zcmV;*0X6>j1KyR&F#*a|$g! zAaH4REpRe5HXwL$Q)M_&AVGI?ZFO%+OKC%LZbx!iMtW~=aDP)VZ+0|xNO?k1VsK+G zH!(#{dPqk|LUsyeSu{pyV^~#8HDXe7GB<2PSuZboWLY;&acXgMOKfvdOioTvYE)8M zG%yM+J|J#8EoX9NVRL05d>~y4T2fI8EiEk|dQx|2L2^kiOLH+!S2t^7OLtF5bW2KR zaCA|5Mm1PvO@DGhZc9%vMM`;h3Ydz>jz{>cUX{J!*{5)0(d=n-+XnbWC%Y)R(`uQZ z236Kba1UV|ziEsfXu~7JXAP(kdw(osq1uWHL0ol??my6WeJa`L4=4>7N5P)#3PKIj zgzV-DSEM?z8A7Adskio@zkRPx9upgt-1CN_n?_c#oI{`n_!?5Tg}>nqq=dhMXMuwo z22J0M8??uMwmWoNVZDJ*K&GM