network/roles/firewall/templates/nftables.nft.j2
Timotej Lazar 78e02134e7 firewall: do track wireguard connections not meant for us
Oops. Connection tracking is disabled for our wireguard connections
because of source address mangling. We still need to track outside
connections to allow inbound reply packets through the firewall.
2025-07-19 12:02:07 +02:00

187 lines
5.8 KiB
Django/Jinja

#!/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 . 3389, # RDP
tcp . 5000-5100,
tcp . 5985,
tcp . 5986,
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 %}
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"
ip protocol icmp icmp type {
echo-request, echo-reply, destination-unreachable,
parameter-problem, time-exceeded,
} accept \
comment "Accept ICMPv4"
ip6 nexthdr icmpv6 icmpv6 type {
echo-request, echo-reply, destination-unreachable,
packet-too-big, parameter-problem, time-exceeded,
} accept \
comment "Accept ICMPv6"
include "/etc/nftables.d/forward.nft*"
}
chain output {
type filter hook output priority 0; policy accept
}
}
table inet wireguard {
chain input {
type filter hook prerouting priority raw; policy accept
ip daddr {{ wg_ip | ipaddr('address') }} udp dport 51820 notrack \
comment "Disable connection tracking for wireguard"
}
chain output {
type route hook output priority raw; policy accept
meta mark 51820 meta nfproto ipv4 ip saddr set {{ wg_ip | ipaddr('address') }} notrack \
comment "Disable connection tracking and set anycast source IP for wireguard"
}
}
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"
}
}