nftables Configuration Templates

The following templates can be used to secure servers with nftables.

Note: The below firewall will not have any updates made. Additional nftables templates which are actively used/developed are available in the wiki. Additional firewall templates and information (using eBPF, XDP, iptables) is also available in the wiki here.

Basic Usage

To load the firewall rules:

# Check the syntax of /etc/nftables.conf
nftables -f /etc/nftables.conf -c

# Apply the firewall rules if no errors
nftables -f /etc/nftables.conf

Counters are used for traffic that is dropped; to get the counter statistics:

# Get all counters
nft list counters

# Show specific counter
nft list counter inet filter input_icmpv4_ping

To list all rules:

# List all rules for all tables
# This will also list any counters and IP's in sets
nft list ruleset

Sets

These firewalls make use of sets to restrict groups of IP’s from services/all traffic.

The input_timeout_ipv4 and input_timeout_ipv6 sets are used to restrict all inbound IPv4 or IPv6 traffic from IP’s or networks. IP’s/networks added to these sets will timeout after 24 hours (by default). To add entries the add element command can be used:

# Block all inbound IPv4 traffic from these IP's/networks:
# 192.0.2.1, 192.0.2.250 and 192.0.2.240/29
nft add element inet filter input_timeout_ipv4 '{ 192.0.2.1, 192.0.2.250 }'

# Block all inbound IPv6 traffic from these IP's networks:
# 2001:0db8::4, 2001:0db8:ffff::/48
nft add element inet filter input_timeout_ipv6 '{ 2001:0db8::4, 2001:0db8:ffff::/48 }'

Templates

Multiple templates are available below for different restrictions.

Relaxed Template

This template will permit HTTP, HTTPS and SSH traffic inbound (for both IPv4 and IPv6) from anywhere. Unmatched inbound traffic will be dropped. There are no outbound rules configured; all outbound traffic is permitted.

#!/usr/sbin/nft -f

flush ruleset

table inet filter {

    # IPv4 IP's listed in this set will have all inbound IPv4 traffic dropped for 24 hours
    # To add IP's to the set:
    #   nft add element inet filter input_timeout_ipv4 '{ 192.0.2.1, 192.0.2.250 }'
    set input_timeout_ipv4 {
        type ipv4_addr
        flags timeout, interval
        timeout 1d
    }

    # IPv6 IP's listed in this set will have all inbound IPv6 traffic dropped for 24 hours
    # To add IP's to the set:
    #   nft add element inet filter input_timeout_ipv6 '{ 2001:0db8::4 }'
    set input_timeout_ipv6 {
        type ipv6_addr
        flags timeout, interval
        timeout 1d
    }

    # Create the counters for below rules
    counter input_timeout_ipv4 {}
    counter input_timeout_ipv6 {}
    counter input_tcp_no_syn {}
    counter input_tcp_scan_1 {}
    counter input_tcp_scan_2 {}
    counter input_tcp_scan_3 {}
    counter input_tcp_scan_4 {}
    counter input_invalid_state {}
    counter input_icmpv6_required {}
    counter input_icmpv6_ping {}
    counter input_icmpv6_dropped {}
    counter input_icmpv4_required {}
    counter input_icmpv4_ping {}
    counter input_icmpv4_dropped {}
    counter input_traceroute {}
    counter input_policy {}

    chain forward {
        type filter hook forward priority 0; policy drop
    }

    chain input {
        type filter hook input priority 0; policy drop

        # Drop traffic early
        ip saddr @input_timeout_ipv4 counter name input_timeout_ipv4 drop comment "Early drop IPv4 traffic from the prefixes listed in input_timeout_ipv4"
        ip6 saddr @input_timeout_ipv6 counter name input_timeout_ipv6 drop comment "Early drop IPv6 traffic from the prefixes listed in input_timeout_ipv6"

        # Permit all established connections
        ct state established,related accept comment "Permit established/related connections"

        # Permit all loopback
        iif lo accept comment "Permit all traffic via loopback interface"

        # Drop TCP traffic with invalid flags
        tcp flags != syn ct state new log prefix "New TCP without SYN: " counter name input_tcp_no_syn drop comment "Drop new connections that do not have the SYN TCP flag set"
        tcp flags & (fin|syn) == (fin|syn) log prefix "Port scan 1: " counter name input_tcp_scan_1 drop comment "Drop common port scan traffic"
        tcp flags & (syn|rst) == (syn|rst) log prefix "Port scan 2: " counter name input_tcp_scan_2 drop comment "Drop common port scan traffic"
        tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) log prefix "Port scan 3:" counter name input_tcp_scan_3 drop comment "Drop common port scan traffic"
        tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) log prefix "Port scan 4:" name input_tcp_scan_4 counter drop comment "Drop common port scan traffic"

        # Drop invalid connection state traffic
        ct state invalid log flags all prefix "Invalid conntrack state: " counter name input_invalid_state drop comment "Drop traffic with invalid connection state"

        # Allow SSH, HTTP, HTTPS
        tcp dport { ssh, http, https } ct state new accept comment "Permit inbound TCP traffic to services hosted on this server"

        # Permit and rate limit required ICMPv6 types
        ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, ind-neighbor-advert, ind-neighbor-solicit,
            mld-listener-query, mld-listener-reduction, mld-listener-report,
            mld2-listener-report, nd-neighbor-advert, nd-neighbor-solicit,
            nd-router-advert, nd-router-solicit, packet-too-big,
            parameter-problem, time-exceeded } counter name input_icmpv6_required accept comment "Permit required ICMPv6 types without rate limit"
        ip6 nexthdr icmpv6 icmpv6 type { echo-reply, echo-request } limit rate 250/second counter name input_icmpv6_ping accept comment "Rate limit IPv4 echo (ping)"
        ip6 nexthdr icmpv6 log flags all prefix "Prohibited ICMPv6: " counter name input_icmpv6_dropped drop comment "Log and drop all other ICMPv6 types"

        # Permit and rate limit required ICMPv4 types
        ip protocol icmp icmp type { destination-unreachable, source-quench, time-exceeded, parameter-problem } counter name input_icmpv6_required accept comment "Permit required ICMPv4 types without rate limit"
        ip protocol icmp icmp type { echo-reply, echo-request } limit rate 250/second counter  name input_icmpv4_ping accept comment "Rate limit IPv4 echo (ping)"
        ip protocol icmp log flags all prefix "Prohibited ICMPv4: " counter name input_icmpv4_dropped drop comment "Log and drop all other ICMPv4 types"

        # Permit and rate limit traceroute
        udp dport 33434-33524 limit rate 50/second counter name input_traceroute accept comment "Rate limit traceroute"

        # Drop unmatched traffic
        counter name input_policy log prefix "Default policy: "
    }

    chain output {
        type filter hook output priority 0; policy accept
    }

}

Strict Template

This template will allow inbound HTTP, HTTPS and SSH – similar to the above relaxed template. How ever, this template will also restrict outbound traffic.

Outbound traffic will be limited to any HTTP/HTTPS destinations, any NTP destinations and DNS traffic to the Cloudflare and Google public resolvers.

#!/usr/sbin/nft -f

flush ruleset

table inet filter {

    # Set default policy for forward traffic to drop
    chain forward {
        type filter hook forward priority 0; policy drop
    }

    # Create the counters for input rules
    counter input_timeout_ipv4 {}
    counter input_timeout_ipv6 {}
    counter input_tcp_no_syn {}
    counter input_tcp_scan_1 {}
    counter input_tcp_scan_2 {}
    counter input_tcp_scan_3 {}
    counter input_tcp_scan_4 {}
    counter input_invalid_state {}
    counter input_icmpv6_required {}
    counter input_icmpv6_ping {}
    counter input_icmpv6_dropped {}
    counter input_icmpv4_required {}
    counter input_icmpv4_ping {}
    counter input_icmpv4_dropped {}
    counter input_traceroute {}
    counter input_policy_default {}

    # IPv4 IP's listed in this set will have all inbound IPv4 traffic dropped for 24 hours
    # To add IP's to the set:
    #   nft add element inet filter input_timeout_ipv4 '{ 192.0.2.1, 192.0.2.250 }'
    set input_timeout_ipv4 {
        type ipv4_addr
        flags timeout, interval
        timeout 1d
    }

    # IPv6 IP's listed in this set will have all inbound IPv6 traffic dropped for 24 hours
    # To add IP's to the set:
    #   nft add element inet filter input_timeout_ipv6 '{ 2001:0DB8::4 }'
    set input_timeout_ipv6 {
        type ipv6_addr
        flags timeout, interval
        timeout 1d
    }

    # Add input (inbound) rules
    chain input {
        type filter hook input priority 0; policy drop

        # Drop traffic early
        ip saddr @input_timeout_ipv4 counter name input_timeout_ipv4 drop comment "Early drop IPv4 traffic from the prefixes listed in input_timeout_ipv4"
        ip6 saddr @input_timeout_ipv6 counter name input_timeout_ipv6 drop comment "Early drop IPv6 traffic from the prefixes listed in input_timeout_ipv6"

        # Permit all established connections
        ct state established,related accept comment "Permit established/related connections"

        # Permit all loopback
        iif lo accept comment "Permit all traffic via loopback interface"

        # Drop TCP traffic with invalid flags
        tcp flags != syn ct state new log prefix "IN - New !SYN: " counter name input_tcp_no_syn drop comment "Drop new connections that do not have the SYN TCP flag set"
        tcp flags & (fin|syn) == (fin|syn) log prefix "IN - Scan 1: " counter name input_tcp_scan_1 drop comment "Drop common port scan traffic"
        tcp flags & (syn|rst) == (syn|rst) log prefix "IN - Scan 2: " counter name input_tcp_scan_2 drop comment "Drop common port scan traffic"
        tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) log prefix "IN - Scan 3:" counter name input_tcp_scan_3 drop comment "Drop common port scan traffic"
        tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) log prefix "IN - Scan 4:" counter name input_tcp_scan_4 drop comment "Drop common port scan traffic"

        # Drop invalid connection state traffic
        ct state invalid log flags all prefix "IN - Invalid: " counter name input_invalid_state drop comment "Drop traffic with invalid connection state"

        # Allow HTTP and HTTPS
        tcp dport { http, https } ct state new accept comment "Permit inbound HTTP and HTTPS"

        # Allow SSH
        tcp dport ssh ct state new accept comment "Permit inbound SSH"

        # Permit and rate limit required ICMPv6 types
        ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, ind-neighbor-advert, ind-neighbor-solicit,
            mld-listener-query, mld-listener-reduction, mld-listener-report,
            mld2-listener-report, nd-neighbor-advert, nd-neighbor-solicit,
            nd-router-advert, nd-router-solicit, packet-too-big,
            parameter-problem, time-exceeded } counter name input_icmpv6_required accept comment "Permit required ICMPv6 types without rate limit"
        ip6 nexthdr icmpv6 icmpv6 type { echo-reply, echo-request } limit rate 250/second counter name input_icmpv6_ping accept comment "Rate limit IPv4 echo (ping)"
        ip6 nexthdr icmpv6 log flags all prefix "IN - Prohibited ICMPv6: " counter name input_icmpv6_dropped drop comment "Log and drop all other ICMPv6 types"

        # Permit and rate limit required ICMPv4 types
        ip protocol icmp icmp type { destination-unreachable, source-quench, time-exceeded, parameter-problem } counter name input_icmpv6_required accept comment "Permit required ICMPv4 types without rate limit"
        ip protocol icmp icmp type { echo-reply, echo-request } limit rate 250/second counter name input_icmpv4_ping accept comment "Rate limit IPv4 echo (ping)"
        ip protocol icmp log flags all prefix "IN - Prohibited ICMPv4: " counter name input_icmpv4_dropped drop comment "Log and drop all other ICMPv4 types"

        # Permit and rate limit traceroute
        udp dport 33434-33524 limit rate 50/second counter name input_traceroute accept comment "Rate limit traceroute"

        # Log and count any unmatched traffic
        counter name input_policy_default log prefix "IN - Default: "
    }

    # Create the counters for output rules
    counter output_timeout_ipv4 {}
    counter output_timeout_ipv6 {}
    counter output_invalid_state {}
    counter output_icmpv6_required {}
    counter output_icmpv6_ping {}
    counter output_icmpv6_dropped {}
    counter output_icmpv4_required {}
    counter output_icmpv4_ping {}
    counter output_icmpv4_dropped {}
    counter output_traceroute {}
    counter output_policy_default {}

    # IPv4 IP's listed in this set will have all outbound IPv4 traffic dropped for 24 hours
    # To add IP's to the set:
    #   nft add element inet filter output_timeout_ipv4 '{ 192.0.2.1, 192.0.2.250 }'
    set output_timeout_ipv4 {
        type ipv4_addr
        flags timeout, interval
        timeout 1d
    }

    # IPv6 IP's listed in this set will have all outbound IPv6 traffic dropped for 24 hours
    # To add IP's to the set:
    #   nft add element inet filter output_timeout_ipv6 '{ 2001:0DB8::4 }'
    set output_timeout_ipv6 {
        type ipv6_addr
        flags timeout, interval
        timeout 1d
    }

    # List of IPv4 DNS servers that outbound queries are sent to
    set output_dns_ipv4 {
        type ipv4_addr
        elements = {
            1.1.1.1,
            1.0.0.1,
            8.8.8.8,
            8.8.4.4
        }
    }

    # List of IPv4 DNS servers that outbound queries are sent to
    set output_dns_ipv6 {
        type ipv6_addr
        elements = {
            2606:4700:4700::1111,
            2606:4700:4700::1001,
            2001:4860:4860::8888,
            2001:4860:4860::8844
        }
    }

    # Add output (outbound) rules
    chain output {
        type filter hook output priority 0; policy drop

        # Drop traffic early
        ip saddr @output_timeout_ipv4 counter name output_timeout_ipv4 drop comment "Early drop IPv4 traffic to the prefixes listed in output_timeout_ipv4"
        ip6 saddr @output_timeout_ipv6 counter name output_timeout_ipv6 drop comment "Early drop IPv6 traffic to the prefixes listed in output_timeout_ipv6"

        # Permit all established connections
        ct state established,related accept comment "Permit established/related connections"

        # Permit all loopback
        oif lo accept comment "Permit all traffic via loopback interface"

        # Drop invalid connection state traffic
        ct state invalid log flags all prefix "OUT - Invalid: " counter name output_invalid_state drop comment "Drop traffic with invalid connection state"

        # Allow HTTP and HTTPS
        tcp dport { http, https } ct state new accept comment "Permit outbound HTTP and HTTPS"

        # Allow IPv4 DNS queries to DNS servers
        ip daddr @output_dns_ipv4 udp dport domain accept comment "Permit outbound IPv4 UDP DNS"
        ip daddr @output_dns_ipv4 tcp dport domain accept comment "Permit outbound IPv4 TCP DNS"
        ip6 daddr @output_dns_ipv6 udp dport domain accept comment "Permit outbound IPv6 UDP DNS"
        ip6 daddr @output_dns_ipv6 tcp dport domain accept comment "Permit outbound IPv6 TCP DNS"

        # Allow outbound SMTP submission
        tcp dport 587 ct state new accept comment "Permit outbound SMTP submission traffic"

        # Allow outbound NTP
        udp dport ntp accept comment "Permit outbound NTP"

        # Permit and rate limit required ICMPv6 types
        ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-solicit, destination-unreachable, packet-too-big,
            time-exceeded, nd-router-advert, mld-listener-query, parameter-problem } counter name output_icmpv6_required accept comment "Permit required ICMPv6 types without rate limit"
        ip6 nexthdr icmpv6 icmpv6 type { echo-reply, echo-request } limit rate 250/second counter name output_icmpv6_ping accept comment "Rate limit IPv4 echo (ping)"
        ip6 nexthdr icmpv6 log flags all prefix "OUT - Prohibited ICMPv6: " counter name output_icmpv6_dropped drop comment "Log and drop all other ICMPv6 types"

        # Permit and rate limit required ICMPv4 types
        ip protocol icmp icmp type { destination-unreachable, source-quench, time-exceeded, parameter-problem } counter name output_icmpv6_required accept comment "Permit required ICMPv4 types without rate limit"
        ip protocol icmp icmp type { echo-reply, echo-request } limit rate 250/second counter  name output_icmpv4_ping accept comment "Rate limit IPv4 echo (ping)"
        ip protocol icmp log flags all prefix "OUT - Prohibited ICMPv4: " counter name output_icmpv4_dropped drop comment "Log and drop all other ICMPv4 types"

        # Permit and rate limit traceroute
        udp dport 33434-33524 limit rate 50/second counter name output_traceroute accept comment "Rate limit traceroute"

        # Log and count any unmatched traffic
        counter name output_policy_default log prefix "OUT - Default: "
    }

}

Leave a Reply

Your email address will not be published. Required fields are marked *