add mgmt nft

This commit is contained in:
asyncnomi 2025-07-21 21:09:45 +02:00
parent a4fd96a197
commit 1ff6293bec
4 changed files with 106 additions and 4 deletions

View file

@ -3,5 +3,7 @@
# Import dependencies # Import dependencies
imports = [ imports = [
./bastion/wireguard.nix ./bastion/wireguard.nix
./bastion/forward.nix
./bastion/nftables.nix
]; ];
} }

View file

@ -0,0 +1,86 @@
{ ... }:
{
networking = {
nat.enable = false;
firewall.enable = false;
nftables = {
enable = true;
checkRuleset = true;
flushRuleset = true;
tables = {
filter = {
family = "inet";
content = ''
chain preroute {
type filter hook prerouting priority -150; policy accept;
}
chain input {
type filter hook input priority 0; policy drop;
# Authorized already setup connection
ct state related,established accept
# Reject sus stuff
ct state invalid counter drop
tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop
# Loopback
iif lo accept
# ICMP
icmp type { echo-request } limit rate 4/second accept
icmpv6 type { echo-request } limit rate 4/second accept
ip protocol icmp accept
icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
# SSH
tcp dport 22 accept
# Mesh
udp dport 51820 accept
# Mgmt
udp dport 51920 accept
# Log anything else
ip protocol tcp counter log prefix "tcp.in.dropped: "
ip protocol udp counter log prefix "udp.in.dropped: "
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state related,established accept
ct state invalid counter drop
iifname mgmt oifname mesh accept
}
chain output {
type filter hook output priority 0; policy accept;
}
chain postroute {
type filter hook postrouting priority 50; policy accept;
}
'';
};
# We'll not nat the outgoing wg packet
# Instead custom routing is done on all
# other node to sent it back correclty
# That allow for custom ACL for the mgmt
# ip addresses
nat = {
family = "inet";
content = ''
chain prerouting {
type nat hook prerouting priority -100; policy accept;
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
}
'';
};
};
};
};
}

View file

@ -21,8 +21,8 @@ let
name = "${peerConfig.name}"; name = "${peerConfig.name}";
publicKey = peerConfig.publicKey; publicKey = peerConfig.publicKey;
allowedIPs = [ allowedIPs = [
"172.19..${toString (myZone + 128)}${toString peerConfig.id}/32" "172.19..${toString (myZone + 127)}${toString peerConfig.id}/32"
"fc00:f::${toString (myZone + 128)}:${toString peerConfig.id}/128" "fc00:f::${toString (myZone + 127)}:${toString peerConfig.id}/128"
]; ];
persistentKeepalive = 25; persistentKeepalive = 25;
}) users-wg; }) users-wg;
@ -30,8 +30,8 @@ let
interface = { interface = {
"mgmt" = { "mgmt" = {
ips = [ ips = [
"172.19.${toString (myZone + 128)}.254/24" "172.19.${toString (myZone + 127)}.254/24"
"fc00:f::${toString (myZone + 128)}:254/96" "fc00:f::${toString (myZone + 127)}:254/96"
]; ];
privateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}".path; privateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}".path;
listenPort = 51920; listenPort = 51920;

View file

@ -15,6 +15,20 @@ let
# And routes, the gateway is assumed to be in subnet, otherwise GatewayOnLink is required # And routes, the gateway is assumed to be in subnet, otherwise GatewayOnLink is required
route4 = if supportsIPv4 myNode then [{ Gateway = myNode.gIp4; }] else []; route4 = if supportsIPv4 myNode then [{ Gateway = myNode.gIp4; }] else [];
route6 = if supportsIPv6 myNode then [{ Gateway = myNode.gIp6; }] else []; route6 = if supportsIPv6 myNode then [{ Gateway = myNode.gIp6; }] else [];
# Return route for mgmt traffic
rtwg4 = if myNode.id == 1 then [] else
map (node: {
Gateway = "172.19.${toString node.zone}.1";
Destination = "172.19.${toString (node.zone + 127)}.0/24";
}) (lib.attrValues (lib.filterAttrs (name: node: node.id == 1) nodes));
rtwg6 = if myNode.id == 1 then [] else
map (node: {
Gateway = "fc00::${toString node.zone}:1";
Destination = "fc00:f::${toString (node.zone + 127)}:0/96";
}) (lib.attrValues (lib.filterAttrs (name: node: node.id == 1) nodes));
in in
{ {
networking.hostName = config.hostName; networking.hostName = config.hostName;