#!/usr/sbin/nft -f # {{ ansible_managed }} flush ruleset table inet filter { # Named sets set trusted4 { type ipv4_addr flags interval elements = { {% for ip in trusted_ranges %} {% if ip.v == 'ipv4' %} {{ ip.cidr }}, # {{ ip.comment | default('') }} {% endif %} {% endfor %} } } set trusted6 { type ipv6_addr flags interval elements = { {% for ip in trusted_ranges %} {% if ip.v == 'ipv6' %} {{ ip.cidr }}, # {{ ip.comment | default('') }} {% endif %} {% endfor %} } } # Firewall chains chain input { type filter hook input priority 0; policy {{ nft_policy_input }}; # Established connections ct state established,related accept ct state invalid counter drop comment "drop invalid packets" # Limit icmp echo/reply ip protocol icmp icmp type echo-request limit rate over 10/second burst 50 packets log prefix "high icmp-echo rate: " drop # icmp6 from trusted ranges ip6 nexthdr icmpv6 icmpv6 type echo-request accept # icmpv6 from the rest of the world ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 10/second burst 50 packets log prefix "high icmp6-echo rate: " drop # Loopback traffic iifname lo accept # icmp ip protocol icmp icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } accept # icmp6 ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, echo-reply, echo-request, nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert, packet-too-big, parameter-problem, time-exceeded } accept # Open ssh only for trusted machines ip saddr @trusted4 tcp dport { ssh } accept ip6 saddr @trusted6 tcp dport { ssh } accept # Rules based on group-vars {% for custom in nft_group_rules %} {% if custom.comment is defined %} # {{ custom.comment|default('') }} {% endif %} ip saddr { {{ custom.from | join(', ') }} } {{ custom.proto | default('tcp') }} dport { {{ custom.port }} } {{ custom.policy | default('accept') }} {% endfor %} {% for rule in group_nft_input %} # Group input rules {{ rule }} {% endfor %} {% for rule in host_nft_input %} # Host input rules {{ rule }} {% endfor %} } chain forward { type filter hook forward priority 0; policy {{ nft_policy_forward }}; ct state established,related accept {% for rule in group_nft_forward %} # Group forward rules {{ rule }} {% endfor %} {% for rule in host_nft_forward %} # Host forward rules {{ rule }} {% endfor %} counter comment "count dropped incoming packets" } chain output { type filter hook output priority 0; policy {{ nft_policy_output }}; # Established connections ct state established,related accept ct state invalid counter drop comment "drop invalid packets" # icmp ip protocol icmp icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } accept # icmp6 ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, echo-reply, echo-request, nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert, packet-too-big, parameter-problem, time-exceeded } accept {% for rule in group_nft_output %} # Group output rules {{ rule }} {% endfor %} {% for rule in host_nft_output %} # Host output rules {{ rule }} {% endfor %} counter comment "count dropped outgoing packets" } } table ip nat { chain prerouting { type nat hook prerouting priority 100 policy {{ nft_policy_prerouting }}; {% for rule in group_nft_prerouting %} # Group prerouting rules {{ rule }} {% endfor %} {% for rule in host_nft_prerouting %} # Host prerouting rules {{ rule }} {% endfor %} } chain postrouting { type nat hook postrouting priority 100 policy {{ nft_policy_postrouting }}; {% for rule in group_nft_postrouting %} # Group postrouting rules {{ rule }} {% endfor %} {% for rule in host_nft_postrouting %} # Host postrouting rules {{ rule }} {% endfor %} } }