#!/usr/sbin/nft -f {% set ifaces_fabric = interfaces | selectattr('name', 'match', '^lan') | map(attribute='name') %} flush ruleset table inet filter { include "/etc/nftables.d/interfaces.nft" include "/etc/nftables.d/networks.nft" include "/etc/nftables.d/sets.nft*" set link { type iface_index elements = { {{ ifaces_fabric | product(['2', '4']) | map('join', '.') | join(', ') }} } } # convenience port set definitions set ad-ports { # https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/config-firewall-for-ad-domains-and-trusts type inet_proto . inet_service flags interval elements = { tcp . 53, tcp . 88, tcp . 135, tcp . 139, tcp . 389, tcp . 445, tcp . 464, tcp . 636, tcp . 3268-3269, tcp . 5000-5100, tcp . 9389, tcp . 22222-22224, tcp . 49152-65535, udp . 53, udp . 88, udp . 135, udp . 137, # netbios, maybe can do without udp . 138, # netbios, maybe can do without udp . 389, udp . 464, udp . 3269 } } set ldap-ports { type inet_proto . inet_service flags interval elements = { tcp . 88, tcp . 389, tcp . 636, tcp . 3268, tcp . 3269, udp . 88, udp . 389 } } chain input { type filter hook input priority 0; policy drop ct state vmap { established : accept, related : accept, invalid : drop } \ comment "Accept established streams and drop invalid connections" iif lo accept \ comment "Accept any localhost traffic" iif mgmt tcp dport ssh accept \ comment "Accept SSH from management VRF" # allow SSH connections from firewall master’s IPs {% for iface in hostvars[master].interfaces %} {% for address in iface.ip_addresses | selectattr('family.value', '==', 4) %} tcp dport ssh {{ 'ip' if address.family.value == 4 else 'ip6' }} saddr {{ address.address | ipaddr('address') }} accept {% for nat_address in address.nat_outside %} tcp dport ssh ip saddr {{ nat_address.address | ipaddr('address') }} accept {% endfor %} {% endfor %} {% endfor %} iif @link tcp dport bgp ip6 saddr fe80::/10 accept \ comment "Accept link-local BGP on fabric links" iif @link udp dport 3784 ip6 saddr fe80::/10 accept \ comment "Accept link-local BFD on fabric links" udp dport 51820 accept \ comment "Accept WireGuard from anywhere" iif {{ iface_sync }} ip6 saddr fe80::/10 udp dport 3780 accept \ comment "Accept connection tracking sync data" tcp dport auth reject with icmpx type port-unreachable \ comment "Reject AUTH to make it fail fast" # ICMPv4 ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, parameter-problem, time-exceeded, } accept \ comment "Accept ICMP" # ICMPv6 ip6 nexthdr icmpv6 icmpv6 type { echo-request, echo-reply, destination-unreachable, packet-too-big, parameter-problem, time-exceeded, } accept \ comment "Accept basic IPv6 functionality" ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-solicit, nd-router-advert, } ip6 hoplimit 255 accept \ comment "Allow IPv6 neighbor discovery" } chain forward { type filter hook forward priority filter; policy drop ct state { established, related } accept \ comment "Forward all established and related traffic" ct status dnat accept \ comment "Forward DNAT traffic for servers and suchlike" include "/etc/nftables.d/forward.nft*" } chain output { type filter hook output priority 0; policy accept } } table ip nat { include "/etc/nftables.d/interfaces.nft" include "/etc/nftables.d/networks.nft" include "/etc/nftables.d/sets.nft*" include "/etc/nftables.d/netmap.nft*" # Ensure these maps exist even if empty. map netmap-in { type ipv4_addr : interval ipv4_addr; flags interval; } map netmap-out { type ipv4_addr : interval ipv4_addr; flags interval; } chain postrouting { type nat hook postrouting priority srcnat iif @inside oif @outside snat ip prefix to ip saddr map @netmap-out \ comment "Static source NAT for 1:1 mapped addresses" include "/etc/nftables.d/nat.nft*" } chain prerouting { type nat hook prerouting priority dstnat dnat ip prefix to ip daddr map @netmap-in \ comment "Static destination NAT for 1:1 mapped addresses" } }