Coder Social home page Coder Social logo

nftables's Introduction

Nftables

  1. Overview
  2. Role Variables
  3. Examples
  4. Configuration
  5. Development
  6. License
  7. Author Information

Overview

A role to manage Nftables rules and packages.

Highly inspired by Mike Gleason firewall role (3 levels of rules definition and template), thanks ! I hope i haven't complexify his philosophy… (I'm pretty sure, i now did complexify it :D) ^^

Role Variables

  • nft_enabled : Enable or disable support for Nftables [default : true].
  • nft_pkg_state : State of new nftables package(s) [default : present].
  • nft_old_pkg_list : The list of useless packages to remove (such as Iptables,…) [default : iptables].
  • nft_old_pkg_state : State of old package(s) [default : absent].
  • nft_old_pkg_manage : If old package(s) should be managed with this role [default : true].
  • nft_conf_dir_path : Directory to store the differents Nftables configuration files [default : /etc/nftables.d].
  • nft_main_conf_path : Main configuration file loaded by systemd unit [default : /etc/nftables.conf].
  • nft_main_conf_content : Template used to generate the previous main configuration file [default : etc/nftables.conf.j2].
  • nft_input_conf_path : Input configuration file include in main configuration file [default : {{ nft_conf_dir_path }}/filter-input.nft].
  • nft_input_conf_content : Template used to generate the previous input configuration file [default : etc/nftables.d/filter-input.nft.j2].
  • nft_output_conf_path : Output configuration file include in main configuration file [default : {{ nft_conf_dir_path }}/filter-output.nft].
  • nft_output_conf_content : Template used to generate the previous output configuration file [default : etc/nftables.d/filter-output.nft.j2].
  • nft_forward_conf_path : forward configuration file include in main configuration file [default : {{ nft_conf_dir_path }}/filter-forward.nft].
  • nft_forward_conf_content : Template used to generate the previous forward configuration file [default : etc/nftables.d/filter-forward.nft.j2].
  • nft_define_conf_path : Vars definition file include in main configuration file [default : {{ nft_conf_dir_path }}/defines.nft].
  • nft_define_conf_content : Template used to generate the previous vars definition file [default : etc/nftables.d/defines.nft.j2].
  • nft_sets_conf_path : Sets and maps definition file include in main configuration file [default : {{ nft_conf_dir_path }}/sets.nft].
  • nft_sets_conf_content : Template used to generate the previous sets and maps definition file [default : etc/nftables.d/sets.nft.j2].
  • nft_global_default_rules : Set default rules for global chain. Other chains will jump to global before apply their specific rules.
  • nft_global_rules : You can add global rules or override those defined by nft_global_default_rules for all hosts.
  • nft_global_group_rules : You can add global rules or override those defined by nft_global_default_rules and nft_global_rules for a group.
  • nft_global_host_rules : Hosts can also add or override all previours rules.
  • nft__custom_content : Custom content (tables, include,…) to add in Nftables configuration [default : ''].
  • nft_input_default_rules : Set default rules for input chain.
  • nft_input_rules : You can add input rules or override those defined by nft_input_default_rules for all hosts.
  • nft_input_group_rules : You can add input rules or override those defined by nft_input_default_rules and nft_input_rules for a group.
  • nft_input_host_rules: : Hosts can also add or override all previous input rules.
  • nft_output_default_rules : Set default rules for output chain.
  • nft_output_rules : You can add output rules or override those defined by nft_output_default_rules for all hosts.
  • nft_output_group_rules : You can add output rules or override those defined by nft_output_default_rules and nft_output_rules for a group.
  • nft_output_host_rules : Hosts can also add or override all previous output rules.
  • nft_forward_default_rules : Set default rules for forward chain.
  • nft_forward_rules : You can add forward rules or override those defined by nft_forward_default_rules for all hosts.
  • nft_forward_group_rules : You can add forward rules or override those defined by nft_forward_default_rules and nft_forward_rules for a group.
  • nft_forward_host_rules : Hosts can also add or override all previous forward rules.
  • nft__forward_table_manage : If the forward table should be managed [default : False].
  • nft__nat_table_manage : If the nat table should be managed [default : False].
  • nft__nat_default_prerouting_rules : Set default rules for prerouting chain of nat table.
  • nft__nat_prerouting_rules : Set rules for prerouting chain of nat table for all hosts in the Ansible inventory.
  • nft__nat_group_prerouting_rules : Set rules for prerouting chain of nat table for hosts in specific Ansible inventory group.
  • nft__nat_host_prerouting_rules : Set rules for prerouting chain of nat table for specific hosts the Ansible inventory.
  • nft__nat_prerouting_conf_path : Prerouting configuration file include in the main configuration [default : {{ nft_conf_dir_path }}/nat-prerouting.nft].
  • nft__nat_prerouting_conf_content : Template used to generate the previous prerouting configuration file [default : etc/nftables.d/nat-prerouting.nft.j2].
  • nft__nat_default_postrouting_rules : Set default rules for postrouting chain of nat table.
  • nft__nat_postrouting_rules : Set rules for postrouting chain of nat table for all hosts in the Ansible inventory.
  • nft__nat_group_postrouting_rules : Set rules for postrouting chain of nat table for hosts in specific Ansible inventory group.
  • nft__nat_host_postrouting_rules : Set rules for postrouting chain of nat table for specific hosts the Ansible inventory.
  • nft__nat_postrouting_conf_path : postrouting configuration file include in the main configuration [default : {{ nft_conf_dir_path }}/nat-postrouting.nft].
  • nft__nat_postrouting_conf_content : Template used to generate the previous postrouting configuration file [default : etc/nftables.d/nat-postrouting.nft.j2].
  • nft_define_default : Set default vars available in all rules.
  • nft_define : You can add vars or override those defined by nft_define_default for all hosts.
  • nft_define_group : You can add vars or override those defined by nft_define_default and nft_define for a group.
  • nft_define_host : You can add or override all previous vars.
  • nft_service_manage : If nftables service should be managed with this role [default : true].
  • nft_service_name : nftables service name [default : nftables].
  • nft_service_enabled : Set nftables service available at startup [default : true].
  • nft__service_protect : If systemd unit should protect system and home [default : true].
  • nft_merged_groups : If variables from the hosts Ansible groups should be merged [default : false].
  • nft_merged_groups_dir : The dictionary where the nftables group rules, named like the Ansible groups, are located in [default : vars/].
  • nft_debug : Toggle more verbose output on/off. [default: 'false'].

OS Specific Variables

Please see default value by Operating System file in [vars][vars directory] directory.

  • nft_pkg_list : The list of package(s) to provide nftables.
  • nft__bin_location : Path to nftables executable. [default : /usr/sbin/nft]

Rule Templates

The nft_templates dictionary contains a library of useful rules, intended to be standardized and ready to use in your firewall. For example {{ nft_templates.allow_mdns }} will expand to the following rules, covering mDNS for both IPv4 and IPv6:

  - meta l4proto udp ip6 daddr ff02::fb    udp dport mdns counter accept comment "mDNS IPv6 service discovery"
  - meta l4proto udp ip  daddr 224.0.0.251 udp dport mdns counter accept comment "mDNS IPv4 service discovery"

Intended usage in custom rule sets:

nft_host_input_rules:
  ...
  010 allow mdns: "{{ nft_templates.allow_mdns }}"

Among others, the nft_templates dictionary contains rules implementing full recommendations for forwarding and input traffic firewalls as defined in RFC 4890, RFC 7126 and RFC 9288. For details and examples see defaults/main.yml.

Rules Dictionaries

Each type of rules dictionaries will be merged and rules will be applied in the alphabetical order of the keys (the reason to use 000 to 999 as prefix). So :

  • nft_*_default_rules : Define default rules for all nodes. You can define it in group_vars/all.
  • nft_*_rules : Can add rules and override those defined by nft_*_default_rules. You can define it in group_vars/all.
  • nft_*_group_rules : Can add rules and override those defined by nft_*_default_rules and nft_*_rules. You can define it in group_vars/webservers.
    • If 'nft_merged_groups' is set to true, multiple group rules from the ansible groups will also be merged together.
  • nft_*_host_rules : Can add rules and override those define by nft_*_default_rules, nft_*_group_rules and nft_*_rules. You can define it in host_vars/www.local.domain.

defaults/main.yml:

# rules
nft_global_default_rules:
  005 state management:
    - ct state established,related accept
    - ct state invalid drop
nft_global_rules: {}
nft_merged_groups: false
nft_merged_groups_dir: vars/
nft_global_group_rules: {}
nft_global_host_rules: {}

nft_input_default_rules:
  000 policy:
    - type filter hook input priority 0; policy drop;
  005 global:
    - jump global
  010 drop unwanted:
    - ip daddr @blackhole counter drop
  015 localhost:
    - iif lo accept
  210 input tcp accepted:
    - tcp dport @in_tcp_accept ct state new accept
nft_input_rules: {}
nft_input_group_rules: {}
nft_input_host_rules: {}

nft_output_default_rules:
  000 policy:
    - type filter hook output priority 0; policy drop;
  005 global:
    - jump global
  015 localhost:
    - oif lo accept
  050 icmp:
    - ip protocol icmp accept
    - ip6 nexthdr icmpv6 counter accept
  200 output udp accepted:
    - udp dport @out_udp_accept ct state new accept
  210 output tcp accepted:
    - tcp dport @out_tcp_accept ct state new accept
nft_output_rules: {}
nft_output_group_rules: {}
nft_output_host_rules: {}

# define nft vars
nft_define_default:
  broadcast and multicast:
    desc: 'broadcast and multicast'
    name: badcast_addr
    value: '{ 255.255.255.255, 224.0.0.1, 224.0.0.251 }'
  input tcp accepted:
    name: in_tcp_accept
    value: '{ ssh }'
  output tcp accepted:
    name: out_tcp_accept
    value: '{ http, https, hkp }'
  output udp accepted:
    name: out_udp_accept
    value: '{ bootps, domain, ntp }'
nft_define: {}
nft_define_group: {}
nft_define_host: {}

# sets and maps
nft_set_default:
  blackhole:
    - type ipv4_addr;
    - elements = $badcast_addr
  in_tcp_accept:
    - type inet_service; flags interval;
    - elements = $in_tcp_accept
  out_tcp_accept:
    - type inet_service; flags interval;
    - elements = $out_tcp_accept
  out_udp_accept:
    - type inet_service; flags interval;
    - elements = $out_udp_accept
nft_set: {}
nft_set_group: {}
nft_set_host: {}

Those default will generate the following configuration :

#!/usr/sbin/nft -f
# Ansible managed

# clean
flush ruleset

include "/etc/nftables.d/defines.nft"

table inet filter {
	chain global {
		# 000 state management
		ct state established,related accept
		ct state invalid drop
	}
	include "/etc/nftables.d/sets.nft"
	include "/etc/nftables.d/filter-input.nft"
	include "/etc/nftables.d/filter-output.nft"
}

And you can get all rules and definitons by displaying the ruleset on the host : $ nft list ruleset :

table inet filter {
	set blackhole {
		type ipv4_addr
		elements = { 255.255.255.255, 224.0.0.1, 224.0.0.251}
	}

	set out_tcp_accept {
		type inet_service
		flags interval
		elements = { http, https, hkp}
	}

	set out_udp_accept {
		type inet_service
		flags interval
		elements = { domain, bootps, ntp}
	}

	chain global {
		ct state established,related accept
		ct state invalid drop
	}

	chain input {
		type filter hook input priority 0; policy drop;
		jump global
		ip daddr @blackhole counter packets 0 bytes 0 drop
		iif "lo" accept
		tcp dport @in_tcp_accept ct state new accept
	}

	chain output {
		type filter hook output priority 0; policy drop;
		jump global
		oif "lo" accept
		ip protocol icmp accept
		udp dport @out_udp_accept ct state new accept
		tcp dport @out_tcp_accept ct state new accept
	}
}

Examples

With playbooks

Manage Nftables with defaults vars (click to expand)
- hosts: serverXYZ
  roles:
    - role: ipr-cnrs.nftables
Add a new simple filter rule for incoming traffic (eg. 1 port for UDP/torrent) (click to expand)
- hosts: serverXYZ
  vars:
      nft_input_rules:
        400 input torrent accepted:
          - udp dport 6881 ct state new accept
  roles:
    - role: ipr-cnrs.nftables
  • nft_input_group_rules or nft_input_host_rules variables can also be used.
  • The weight (400) allow to order all merged rules (from nft_input_*rules dictionaries).
  • The text following the weight (input torrent accepted) is a small description that will be added as a comment in nft_input_conf_path file on the remote host.
Add a new multi-ports filter rule for incoming traffic (eg. TCP/http, https, http-alt,…) (click to expand)
- hosts: serverXYZ
  vars:
      nft_input_rules:
        400 input http accepted:
          - tcp dport { 80, 443, 8080-8082 } ct state new accept
  roles:
    - role: ipr-cnrs.nftables
  • nft_input_group_rules or nft_input_host_rules variables can also be used.
  • The weight (400) allow to order all merged rules (from nft_input_*rules dictionaries).
  • The text following the weight (input http accepted) is a small description that will be added as a comment in nft_input_conf_path file on the remote host.
  • In this case, brackets are useful and define a anonymous set. For a single element (port, IP address,…), brackets are overkill and the singleton definition is enought.
Add a new rule with a variable (click to expand)

Nftables variables can be useful if you define somes generic rules for all hosts with such variables (called with $) and override variable's value for some groups or hosts.

- hosts: serverXYZ
  vars:
    - nft_define_group:
        input http accepted:
          desc: HTTP and HTTPS
          name: in_http_accept
          value: '{ 80, 443 }'
      nft_input_group_rules:
        400 input http accepted:
          - tcp dport $in_http_accept ct state new accept
  roles:
    - role: ipr-cnrs.nftables
  1. Add a new variable with define for HTTP ports.
  2. Add a new rule for incoming traffic and use the previous defined variable.
  3. Result of nft list ruleset on the remote host will be :
    table inet filter {
            …
    
            chain input {
                    …
                    tcp dport { http, https } ct state new accept
                    …
            }
            …
    }
    • No mention of $in_http_accept variable.
  • nft_define or nft_define_host variables can also be used.
  • nft_input_rules or nft_input_host_rules variables can also be used.
  • The weight (400) allow to order all merged rules (from nft_input_*rules dictionaries).
  • The text following the weight (input http accepted) is a small description that will be added as a comment in nft_input_conf_path file on the remote host.
Add a new rule with a named set (click to expand)

Quite similar to Nftables variables, named set can be useful if you define somes generic rules and sets (eg. for all hosts) and override only the set in some case (eg. for a group or some hosts).

In addition to variables, it is possible to add content to named sets on the fly from the host without completely rewrite the rule.

- hosts: serverXYZ
  vars:
      nft_set_group:
        in_udp_accept:
          - type inet_service; flags interval;
          - elements = { 6881-6887, 6889 }
      nft_input_group_rules:
        200 input udp accepted:
          - udp dport @in_udp_accept ct state new accept
  roles:
    - role: ipr-cnrs.nftables
  1. Add a new named set with nft_set_group dictionary (eg. for torrent ports).
  2. Add a new rule for incoming traffic and use the previous defined set.
  3. On the remote host, if you try to add a port to this set : nft add element inet filter in_udp_accept \{ 6999 \}
  4. Result of nft list ruleset on the remote host will now be :
    table inet filter {
            …
            set in_udp_accept {
                    type inet_service
                    flags interval
                    elements = { 6881-6887, 6889, 6999 }
            }
            chain input {
                    …
                    udp dport @in_udp_accept ct state new accept
                    …
            }
            …
    }
  • nft_set or nft_set_host variables can also be used.
  • nft_input_rules or nft_input_host_rules variables can also be used.
  • The weight (200) allow to order all merged rules (from nft_input_*rules dictionaries).
  • The text following the weight (input upd accepted) is a small description that will be added as a comment in nft_input_conf_path file on the remote host.
Override a default rule with 2 new rules (click to expand)
- hosts: serverXYZ
  vars:
      nft_input_host_rules:
        050 icmp:
          - ip protocol icmp  ip saddr != 192.168.0.0/24  counter  drop
          - ip protocol icmp  icmp type echo-request  ip length <= 84  counter  limit rate 10/minute  accept
  roles:
    - role: ipr-cnrs.nftables
  1. Get rule description from defaults/main.yml file (eg. 050 icmp).
  2. Drop any ICMP request that doesn't come from 192.168.0.0 network.
  3. Ensure the request is less or equal to 84 bytes and set up a limit to 10 requests per minute.
  • nft_input_rules or nft_input_group_rules variables can also be used.
  • The weight (050) allow to order all merged rules (from nft_input_*rules dictionaries).
  • The text following the weight (icmp) is a small description that will be added as a comment in nft_input_conf_path file on the remote host.
Override some of the default defined sets (click to expand)
- hosts: serverXYZ
  vars:
    - nft_define:
      input tcp accepted:
        desc: Custom SSH port and torrent
        name: in_tcp_accept
        value: '{ 2201, 6881 }'
  roles:
    - role: ipr-cnrs.nftables
  1. Get item name (eg. input tcp accepted) and variable name (eg. in_tcp_accept) from defaults/main.yml file.
  2. Set a new value (eg. '{ 2201, 6881 }').
  3. You can add a desc attribute that will be set as a comment in nft_input_conf_path file on the remote host.
  • nft_define_group or nft_define_host variables can also be used.
Override all default rules (eg. for outgoing traffic) (click to expand)

If the default rules are too permissive, if you already override most of them,… In some case, i guess, it can be interesting to redefine the default variable :

- hosts: serverXYZ
  vars:
      nft_output_default_rules:
        000 policy:
          - type filter hook output priority 0; policy drop;
        005 state management:
          - ct state established,related accept
          - ct state invalid drop
        015 localhost:
          - oif lo accept
        050 my rule for XXX hosts and services:
          - tcp dport 2000  ip saddr { xxx.xxx.xxx.xxx, yyy.yyy.yyy.yyy }  ct state new  accept
        250 reset-ssh:  # allow the host to reset SSH connections to avoid 10 min delay from Ansible controller
          - tcp sport ssh tcp flags { rst, psh | ack } counter accept
  roles:
    - role: ipr-cnrs.nftables
  • At least, don't forget to :
    1. set a default policy.
    2. manage already established state.
    3. accept rst, psh | ack flags for ssh to avoid a 10 minutes delay at the first run of this Nftables role (see #1).
  • Then add your own rules with the wanted weight to order all merged rules (from nft_output_*rules dictionaries) and descriptions.
Remove a default rule (click to expand)
- hosts: serverXYZ
  vars:
      nft_output_host_rules:
        210 output tcp accepted:
          -
  roles:
    - role: ipr-cnrs.nftables
  1. Get rule description from defaults/main.yml file (210 output tcp accepted).
  2. The default policy for outgoing traffic (drop) will now be applied to ports defined in out_tcp_accept variable. Be sure of what you are doing.
  3. The rule will no longer be present in nft list ruleset result, just a comment will remain (210 output tcp accepted) in nft_output_conf_path file on the remote host.
  • nft_output_rules or nft_output_group_rules variables can also be used.
  • The weight (210) allow to order all merged rules (from nft_output_*rules dictionaries).

With group_vars and host_vars

Use default rules and allow, for first_group, incoming ICMP and count both ICMP and default policy (drop) packets (click to expand)

group_vars/first_group :

nft_input_group_rules:
  020 icmp:
    - ip protocol icmp icmp type echo-request ip length <= 84 counter limit rate 1/minute accept
  999 count policy packet:
    - counter
Use merged group rules from multiple ansible groups (click to expand)
  1. Enable to merge group's variables :
    - hosts: serverXYZ
      vars:
        nft_merged_groups: true
        nft_merged_groups_dir: vars/
      roles:
        - role: ipr-cnrs.nftables
  2. Put extra rules inside the "vars" folder named after your ansible groups for serverXYZ :
    • vars/first_group :
      nft_input_group_rules:
        020 icmp:
          - ip protocol icmp icmp type echo-request ip length <= 84 counter limit rate 1/minute accept
        999 count policy packet:
          - counter
    • vars/second_group :
      nft_input_group_rules:
        021 LAN:
          - iif eth0 accept
  3. These rulesets, from the two groups, will be merged if the host is a member of these groups.

Configuration

This role will :

  • Install nftables on the system.
  • Enable nftables service by default at startup.
  • Generate a default configuration file which include all following files and loaded by systemd unit.
  • Generate input and output rules files include called by the main configuration file.
  • Generate vars in a file and sets and maps in another file.
  • Ensure nftables is started and enabled on boot
  • (re)Start nftables service at first run or when systemd units are modified
  • Reload nftables service at next runs to avoid to let the host without firewall rules due to invalid syntax.

Fail2ban integration

Before Debian Bullseye, systemd unit for Fail2ban doesn't come with a decent integration with Nftables. This role will create override file for fail2ban unit, unless nft_fail2ban_service_override is set to false. Default is to add it even if it's not (yet) available on the host. This ensures :

  • The fail2ban unit is started after the nftables unit.
  • The fail2ban unit is restarted when nftables unit restarts.

Development

This source code comes from our Gitea instance and the Github repo exist just to be able to send the role to Ansible Galaxy…

But feel free to send issue/PR here :)

Thanks to this hook, Github automatically got updates from our Gitea instance :)

License

WTFPL

Author Information

Jérémy Gardais

  • IPR (Institut de Physique de Rennes)

nftables's People

Contributors

aardbol avatar dennisse avatar gardouille avatar ipr-cnrs avatar julienvdg avatar kravietz avatar nikosch86 avatar p-rintz avatar rdbisme avatar rissson avatar stejoo avatar vtimofeenko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nftables's Issues

Location of nftables.service unit file

Hi :)

The location of the nftables.service file is specified as /lib/systemd/system/nftables.service. But directly managing this file at path /lib/systemd/system/nftables.service goes against systemd guidelines, as specified in systemd.unit (5), referring in particular to section UNIT FILE LOAD PATH.

To quote a nice table from that section (hope the formatting stays intact):

       Table 1.  Load path when running in system mode (--system).
       ┌──────────────────────────────┬────────────────────────────────────────────────────┐
       │Path                          │ Description                                        │
       ├──────────────────────────────┼────────────────────────────────────────────────────┤
       │/etc/systemd/system.control   │ Persistent and transient configuration created     │
       ├──────────────────────────────┤ using the dbus API                                 │
       │/run/systemd/system.control   │                                                    │
       ├──────────────────────────────┼────────────────────────────────────────────────────┤
       │/run/systemd/transient        │ Dynamic configuration for transient units          │
       ├──────────────────────────────┼────────────────────────────────────────────────────┤
       │/run/systemd/generator.early  │ Generated units with high priority (see early-dir  │
       │                              │ in systemd.generator(7))                           │
       ├──────────────────────────────┼────────────────────────────────────────────────────┤
       │/etc/systemd/system           │ System units created by the administrator          │
       ├──────────────────────────────┼────────────────────────────────────────────────────┤
       │/run/systemd/system           │ Runtime units                                      │
       ├──────────────────────────────┼────────────────────────────────────────────────────┤
       │/run/systemd/generator        │ Generated units with medium priority (see          │
       │                              │ normal-dir in systemd.generator(7))                │
       ├──────────────────────────────┼────────────────────────────────────────────────────┤
       │/usr/local/lib/systemd/system │ System units installed by the administrator        │
       ├──────────────────────────────┼────────────────────────────────────────────────────┤
       │/usr/lib/systemd/system       │ System units installed by the distribution package │
       │                              │ manager                                            │
       ├──────────────────────────────┼────────────────────────────────────────────────────┤
       │/run/systemd/generator.late   │ Generated units with low priority (see late-dir in │
       │                              │ systemd.generator(7))                              │
       └──────────────────────────────┴────────────────────────────────────────────────────┘

Systemd checks these paths in reverse order; meaning directories higher up in this table take precedence.

The {/usr,}/lib/systemd/system directory is for system units installed by the distribution package manager. Files in this location should not be touched by administrators. To fully override this packaged unit file, as the system administrator (using Ansible), would be to drop "our" custom version of nftables.service in directory /etc/systemd/system. Not touching the one in /lib/systemd/system.

This should easy to resolve. I will have a go at it and test my suggested change, after which I will try to submit a PR here.

Async does not support check_mode

I'm getting errors when using check_mode.

From https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_async.html

As of Ansible 2.3, async does not support check mode and will fail the task when run in check mode. See Validating tasks: check mode and diff mode on how to skip a task in check mode.

Checking for ansible_check_mode will prevent getting an error when running in check mode.

I made a PR (#57) in january, but I haven't gotten any response there.

nft_merged_groups and "Error: not found"

Hi, shouldn't the first task have a when wrapping it, so that it doesn't run if nft_merged_groups is False?

I have a clean install, and I'm getting this:

failed: [test -> localhost] (item=lxd) => changed=false
  ansible_loop_var: groupname
  groupname: lxd
  module_stderr: |-
    Error: not found
  module_stdout: ''
  msg: |-
    MODULE FAILURE
    See stdout/stderr for the exact error
  rc: 1

Ubuntu 16.04 not compatible

Ubuntu 16.04 is not compatible since it uses and old version of nftables which doesn't support the default's config syntax. Running the role will result in:

{"changed": false, "msg": "Unable to start service nftables: Job for nftables.service failed because the control process exited with error code. See \"systemctl status nftables.service\" and \"journalctl -xe\" for details.\n"}

In the journal logs:

/etc/nftables.d/filter-output.nft:19:20-20: Error: syntax error

Ubuntu 18.04 hosts work fine.

feature req: ipv6 nat support

This module is incredibly handy, and I'm using the nat table management features. however, it seems like it only sets up a table for ip(v4), and nothing for v6. I know nat generally isn't super useful on ipv6, but I believe I still need it for using keepalived/ipvsadm on my firewalls connected to backend hosts, so I'd really love to have optional support for it in this module.

On Archlinux, iptables can't be removed

error: failed to prepare transaction (could not satisfy dependencies)
:: removing iptables breaks dependency 'iptables' required by fail2ban
:: removing iptables breaks dependency 'iptables' required by iproute2
:: removing iptables breaks dependency 'iptables' required by systemd

Maybe installing iptables-nft instead would solve the problem?

Issue new tag

@kravietz you have been hard at work merging stuff. Thank you ❤️ !

Would it be possible to tag/release a new version of the role to mark this occassion? 👍

Bridge support?

Hello, I'd like to manage a bridge with this. Is it possible?

Example:

$ nft list ruleset
table inet filter {
        chain input {
                type filter hook input priority 0; policy accept;
        }

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

        chain output {
                type filter hook output priority 0; policy accept;
        }
}
table bridge filter {
        chain INPUT {
                type filter hook input priority -200; policy accept;
                iifname "enp*" ether type ip ip daddr 255.255.255.255 udp sport 68 udp dport 67  counter packets 0 bytes 0 drop
        }

        chain FORWARD {
                type filter hook forward priority -200; policy accept;
                ether type ip ip daddr 255.255.255.255 udp sport 68 udp dport 67  counter packets 0 bytes 0 drop
        }

        chain OUTPUT {
                type filter hook output priority -200; policy accept;
        }
}

Should we manage `nftables.service` at all? Task "Install nftables Debian systemd service unit"

Hi,

Thanks for your role! I have recently started using it in testing with the intention of putting it to use on several Red Hat based machines. If I happen to come across any issues I'll let you know and will try to resolve them and share a possible fix with out via PR.

I noticed task "Install nftables Debian systemd service unit" is being run. Modifying the original /lib/systemd/system/nftables.service file put in place by the nftables package. This happens on both EL8 (AlmaLinux 8) and the exact same should happen on Debian (11) by looking at the code, or simply: this always happens when nft_enabled and nft_service_manage are true (which is the default).

The unit file carried by this role seems to match the nftables.service file provided by Debian. Or at least it seems to closely resemble the one I compared it to (from nftables_0.9.8-3.1_amd64.deb (Debian 11)). On RHEL8 the file looks a little different (compared to nftables-0.9.3-25.el8.x86_64 (RHEL8)).
One distinct change seems to be in the ExecReload behaviour there:

-ExecReload=/sbin/nft 'flush ruleset; include "/etc/sysconfig/nftables.conf";'
+ExecReload=/usr/sbin/nft -f /etc/nftables.conf

The EL8 package is slightly older. But my Fedora 35 variant als has the ExecReload with the flush ruleset in there. So that seems a distro-specific design choice? Maybe better to keep it for RedHat based machines, to not stray from the distro too much.

Another change of importance:

 [Install]
-WantedBy=multi-user.target
+WantedBy=sysinit.target

Hmm... that does modify it's behaviour in the grand scheme of bootup (7) a bit compared to what's set by the package on Red Hat. Not somebody that is cause of concern, but a change that does influence it's position in the bootup order.
I noticed task "Ensure to remove nftables systemd service from old target" also ensures the nftables.service is removed from the multi-user.target.wants. Seems quite intentional, but I haven't figured out the motivation for it.
I am interested to learn why this is done? Perhaps the "why" could be added as comment to the task to make it more clear at the same time.

I would probably be in favor of checking if a nftables.service exists prior to adding a custom one. Or have such a task perform based on the distribution and it's version, for example in case Debian 10 does not supply such a file there would be need to add it ourselves. Where instead Debian 11 and EL8 do supply a nftables.service and we could skip adding our own.

To sum up my questions:

  • Is there a need to modify/manage this file at all when it's supplied by the package?
  • In case of "yes, we should". Perhaps I could add a Red Hat specific one, or perhaps set a conditional on this particular task to be skipped for systems that perhaps don't need this?
  • Why remove /etc/systemd/system/multi-user.target.wants/nftables.service ?

Curious about what your, and possible others, thoughts are about this one.
Hope to hear from you and learn about those choices. 😃

Reload invalid ruleset leads to no firewall rules

If an invalid syntax is added to the rulebase, a changed rulebase stops/starts the service. So
stop flushes the rulebase and start fails. A reload will not load the rulebase if there any errors.

A handler with state reloaded, which runs when changes to the rules are made, instead of state restarted would not result in a host without firewall rules.

Mistakenly pushed branch

@gardouille I've just pushed a whole branch that was subject to an open PR into master by mistake (I was using another computer where this repository was set as origin rather than my fork). The obvious remedy would be to create a revert back to c4da513d08a24df4ae042b85a10d9d3f7a27ca8a which was the latest PR merged, but if you're OK with these changes we can leave them in as if it was a merged PR?

Following update, rules no longer load

After updating to the latest (v2.0.1) of this nftables role, my rules no longer load. I get really bizarre errors from the actual nft software when I attempt to update my firewalls. I am not doing anything fancy, I just have a list of allowed IPs. I am letting this Ansible role generate all of my nft configs. I have included an example of the bizarre sorts of errors I am getting. nft now refuses to load any of these rule files.

The "conflicting intervals" appear to be 400 columns down a line that never gets printed, but the example ^^^ and ~~~ do get printed ... after 400 or so spaces. What is going on here? The statements all seem legal to me. Ansible did not report that any of these files were changing. All I did was add IPs to a set.

nft-example.txt

I got this error after getting very similar errors from the filter-input.nft and filter-output.nft files, and then I commented them out, to see what I could get to load. Turns out, no included files would load at all.

When I try to include the files manually, nft complains a lot about the syntax, so there's not a good way for me to test each sub-block by hand.

I can provide additional output if desired. I feel like there must be something simple I'm missing, but the changelog did not warn of any things I need to change in order for my old code to continue to work. In the meantime I will see if there is a way for me to revert my submodule copy of this repo to an earlier, working version.

Deprecated option

[DEPRECATION WARNING]: Invoking "apt" only once while using a loop via 
squash_actions is deprecated. Instead of using a loop to supply multiple items 
and specifying `name: "{{ item }}"`, please use `name: ['{{ nft_old_pkg_list | 
to_nice_json }}']` and remove the loop. This feature will be removed in version
 2.11. Deprecation warnings can be disabled by setting 
deprecation_warnings=False in ansible.cfg.

Allow Merged Group Variables

Hi there,

I have the following use case that I would like to fulfil with this Ansible role.
Imagine the following setup:
Server A has two (or more) Ansible groups.
Group "webserver" and Group "email_server".

Webserver has the following rules (just nft_input_group_rules as example):

nft_input_group_rules:
  297 local:
    - iif mgmt accept
  298 storage:
    - iif storage accept
  299 cluster:
    - iif cluster accept

Email_server has the following:

nft_input_group_rules:
  310 allowemail:
    - ip saddr @allowemail ct state new accept

If I set the variables inside the group_vars as you mentioned in the readme, the group vars of group "email_server" would be overwritten by those of group "webserver" and only the firewall rules for the webservers would be applied to server A.

Instead I would like both variables of the groups to be applied, so that the server gets the firewall rules for both the "webserver" and "email_server" group.

        # 297 local
        iif mgmt accept
        # 298 storage
        iif storage accept
        # 299 cluster
        iif cluster accept
        # 310 allowemail
        ip saddr @allowemail ct state new accept

Is this something you would be interested in as a pull request?
I have written the necessary changes already on my end, though I would need to make it more modularized and test it more to actually open up a pull request.

Currently the default behaviour would stay the same as it is now.
There would be two new variables that are optional to be set if one would like to use this.

"merged_groups": true/false (false being the default)
"merged_groups_dir": directory with the nftables variables inside text files named after the ansible groups. (ie. "webserver" or "email_server")

Thanks.

update_cache: true breaks nftables installation on Gentoo

I am writing molecule tests to test the role on Gentoo and found that the role throws an error when installing the package:

fatal: [Gentoo]: FAILED! => {"attempts": 3, "changed": false, 
"msg": 
"Unsupported parameters for (ansible.legacy.portage) module: update_cache. 
Supported parameters include: sync, deep, keepgoing, depclean, update, newuse, oneshot, usepkg, onlydeps, jobs, quietfail, package (name), loadavg, noreplace, getbinpkgonly, state, verbose, nodeps, usepkgonly, changed_use, quietbuild, quiet, getbinpkg."}

Looks like 8fad9d7 added

update_cache: true

to installation task.

According to the doc, the values supported by the ansible.builtin.package are:

  • name
  • state
  • use

Was this change made in the context of the molecule tests? If so, would it be possible to move the package cache into preparation playbooks making them distro-specific?

Recent versions seem to demand recent kernel/nftables for NAT

I've starting getting errors like this in my servers:

info.daemon     2023-05-16T18:49:20.422304+02:00        example:nft[12885]:        In file included from /etc/nftables.conf:34:9-6
2:
info.daemon     2023-05-16T18:49:20.422392+02:00        example:nft[12885]:        /etc/nftables.ansible.d/nat-postrouting.nft:11:
60-69: Error: NAT is only supported for IPv4/IPv6
notice.daemon   2023-05-16T18:49:20.422537+02:00        example:systemd[1]:        nftables.service: Main process exited, code=exi
ted, status=1/FAILURE
warning.daemon  2023-05-16T18:49:20.422618+02:00        example:systemd[1]:        nftables.service: Failed with result 'exit-code
'.

The nat-postrouting files has autogenerated entries that refer to some group, as in

iifname "brlan*" ip daddr != @my_intranets_v4 masquerade;

After looking online for the NAT is only supported for IPv4/IPv6 message I found some references to nftable not allowing ip syntax for certain things in old versions. If I upgrade my buster server's kernel and nftables command to buster-backports, the ansible role works again. (That would be kernel 4.19 to 5.10, and nftables from 0.9.0 to 0.9.6).

n.b.: buster is on active LTS until 2024.

DNS names in rules / dumping with -n

I request dumping the rules after a successful load with -n to resolve names in rules/sets.
These rules can be restored on reboot before networking comes up.
Currently it is not possible to use names in rules, as they won't load on reboot.

The alternatives

  • not using names in rules
  • maintaining /etc/hosts for early resolve before network comes up so nftables can use it

are considered worse.

The role stalls when handling the nftables service on rhel 8

Ansible never gives back control when the role reaches this step:

RUNNING HANDLER [local.nftables : Reload nftables service]

It does reload the service though. This appears to happen with RHEL 8 hosts, but not with Debian 11. To reproduce, perform the following step on the target before running the role:

systemctl disable --now nftables
rm /etc/nftables.d/defines.nft

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.