ansibleguy.infra_nftables

NFTables logo

Ansible Role - NFTables

This role sets up the NFTables firewall on Linux servers.

Buy me a coffee

Molecule Test Status YamlLint Test Status PyLint Test Status Ansible-Lint Test Status Ansible Galaxy

Molecule Logs: Short, Full

Tested on:

  • Debian 11
  • Debian 12

Installation

# Install latest version
ansible-galaxy role install git+https://github.com/ansibleguy/infra_nftables

# From Ansible Galaxy
ansible-galaxy install ansibleguy.infra_nftables

# Or install to a custom path
ansible-galaxy install ansibleguy.infra_nftables --roles-path ./roles

Documentation

Troubleshooting


Usage

Want a simple Ansible GUI? Check out my Ansible WebUI

Configuration

Set up the configuration as needed:

nftables:
  # Enable features supported by the kernel
  #   sets: true
  #   nat: true
  #   deb11_backport: false  # use Debian 11 backports for newer version on Debian 10
  #   bash_completion: false

  _defaults:  # defaults for all tables and chains
    table:
      type: 'inet'
    
    chain:
      policy: 'drop'
      type: 'filter'
      priority: 0
      log:
        drop: true

    rules:
      _all: []  # rules for all chains of all tables
      incoming: []  # rules for the 'incoming' chain of all tables

  tables:
    example:
      _defaults:
        rules:
          _all: []  # rules for all chains of this table

      vars:
        dns_servers: ['1.1.1.1', '1.1.0.0', '8.8.8.8', '8.8.4.4']
        private_ranges: ['192.168.0.0/16', '172.16.0.0/12', '10.0.0.0/8']

      sets:
        blacklist:
          flags: ['dynamic', 'timeout']
          settings:
            timeout: '3m'

      counters:
        invalid_packages:
          comment: 'Invalid'

      chains:
        incoming:
          hook: 'input'
          rules:
            - sequence: 1
              raw: 'ct state invalid counter name invalid_packages log prefix "DROP invalid states" drop'
            - seq: 2
              raw: 'ct state {established, related} counter accept comment "Allow open sessions"'
            - s: 3
              raw: 'iifname "lo" accept comment "Allow loopback traffic"'
            - {proto: 'icmp', type: 'echo-request', limit: 'rate 10/second', comment: 'Allow icmp-ping'}
            - {proto: 'icmpv6', type: 'echo-request', limit: 'rate 10/second', comment: 'Allow icmp-ping'}
            - {proto: 'icmp', code: 30, limit: 'rate 10/second', comment: 'Allow icmp-traceroute'}
            - {proto: 'icmpv6', limit: 'rate 10/second', comment: 'Allow necessary icmpv6-types for ipv6 to work',
               type: ['nd-neighbor-solicit', 'nd-router-advert', 'nd-neighbor-advert']}
            - {proto: 'udp', port: 46251, counter: 'invalid_packages'}

        outgoing:
          hook: 'output'
          rules:
            - {dest: '$dns_servers', proto: 'udp', port: 53}
            - {dest: '$dns_servers', proto: 'tcp', port: [53, 853]}
            - {proto: ['tcp', 'udp'], port: [80, 443]}
            - {proto: ['icmp', 'icmpv6'], comment: 'Allow outbound icmp'}

        route:
          hook: 'forward'

        translate:
          hook: 'postrouting'
          type: 'nat'
          policy: 'accept'
          rules:
            - {'src': '$private_ranges', oif: 'eno2', masquerade: true}  # dynamic outbound nat
            - {'src': '$private_ranges', oif: 'eno3', snat: '192.168.0.1'}  # static outbound nat

To combine group and host rules, do it like this:

- name: NFTables
  become: true
  hosts: all
  vars:
    nftables:
      tables:
        example:
          chains: "{{ fw_rules_all |
          combine(fw_rules_group|default({}), recursive=true, list_merge='append') |
          combine(fw_rules_host|default({}), recursive=true, list_merge='append') }}"

  pre_tasks:
    - debug:
        var: nftables

  roles:
    - ansibleguy.infra_nftables

Execution

Run the playbook:

ansible-playbook -K -D -i inventory/hosts.yml playbook.yml

Useful tags:

  • config_table => only provision actual rulesets
  • config
  • purge

For debugging errors, set the debug variable at runtime:

ansible-playbook -K -D -i inventory/hosts.yml playbook.yml -e debug=yes

Features

  • Package Installation

    • Minimal Ansible dependencies
    • NFTables
  • Configuration

    • Define

      • variables globally
      • variables, sets, counters, and limits at the table level
      • variables at the chain level
    • Configuration validation before writing it

    • Default Configuration:

      • Enabled features (must be supported by kernel)
        • Sets
        • NAT
      • No default rules added
      • Tables:
        • table-type = inet
      • Chains:
        • chain-type = filter
        • chain-policy = drop
        • priority = 0
        • add counter = yes
        • log implicit drops = yes
      • Sets:
        • set-type = ipv4_addr
        • add counter = yes
      • Rules:
        • policy = accept (set to 'none' to remove it)
        • logging drops = yes
    • Default Options:

      • Deleting unmanaged config files in '/etc/nftables.d/'
    • Default Opt-Outs:

      • Installing NFTables from Debian 11 backports on Debian 10 (for newer version)
      • Adding bash-completion script for 'nft' command

Information

  • Note: You can enable or disable most functions of the role.

    For a full list of options, check the default configuration in the main defaults file!

  • Warning: Not all settings/variables will be checked for validity. Bad configuration may break the role!

  • Info: You can add DNS Resolution and IP Blocklist features to NFTables using the ansibleguy.addons_nftables role!

  • Warning: Some core functionalities (NAT/Sets) might not be supported by all Distribution kernels.

    See: Troubleshooting Guide - 'Unsupported Operation'

  • Info: Read the Hook documentation for guidance on configuring hooks and priorities!

  • Info: Rules can be given in dictionary format as shown in examples.

    Below are the available fields and aliases:

    Function Keys Note
    Rule sequence s, id, seq, sequence The sequence ID (integer) to sort the rules inside a chain. Defaults to 1000 if none is provided. Duplicate sequence IDs will cause the role to fail.
    Input interface if, iif, iifname -
    Output interface of, oif, oifname -
    Protocol proto, pr, protocol -
    Protocol sub-type t, type -
    Protocol sub-code co, code -
    Destination Address/Network d, dest, target, destination, 'ip daddr', d6, dest6, target6, 'ip6 daddr' -
    Destination Port dp, port, dport, dest_port -
    Source Address/Network s, src, source, 'ip saddr', s6, src6, source6, 'ip6 saddr' -
    Source Port sp, sport, sport, src_port -
    Logging / Log message l, log, 'log prefix' If set to 'True' and a comment is provided, it will be used as a message. Otherwise, no message will be used
    Traffic counter count, counter If set to 'True', a rule-specific counter will be used. Otherwise, it will use the provided counter
    Traffic Limit lim, limit A limit for the rule, see: Anonymous Limits and Pre-defined Limits
    Rule action a, action Defaults to 'accept' if no action is provided.
    Source NAT masquerading m, masque, masquerade If NAT masquerading should be used
    Source NAT snat, src_nat, source_nat, outbound_nat, 'snat to' -
    Destination NAT dnat, dest_nat, destination_nat, 'dnat to' -
    Redirect redir, redirect, 'redirect to' Redirects packets to the local machine
    Rule comment c, cmt, comment -
    User user, uid Match traffic from specific users
    Group group, gid Match traffic from specific groups
    Firewall-Mark mark -
    Priority prio, priority -
    Packet length len, length -
    Timestamp time, timestamp Match the timestamp of packet reception
    Weekday day Match the day of the week (0 = Sunday to 6 = Saturday)
    Time hour Match 24-hour format "HH:MM:SS", seconds are optional

    You can only set one of Action, Source-NAT, Masquerading, or Destination-NAT for each rule!

  • Info: For special/complex rules that cannot be configured with the rule dictionary, use the 'raw' key to add any custom rule directly.

  • Info: You can define variables, sets, counters and limits at the table level.

    • Variables are key-value pairs:
      var-name: var-value
      var2-name: ['value1', 'value2']
      
    • Sets have the following structure:
      set-name:
        flags: [list-of-flags]  # optional
        settings:
          setting: value  # optional
      
    • Counters are structured like this:
      counter-name:
        comment: text  # optional
      
    • Limits are structured like this:
      limit-name:
        rate: 'over 1024 bytes/second burst 512 bytes'
        comment: text  # optional
      
  • Warning: For 'count-only' rules, set 'action' explicitly to 'none'; otherwise, the default 'accept' will be added!

  • Info: If any unsupported field is provided to the rule translation, it will result in an error since it could yield unexpected results!

  • Info: Docker may require IPTables as a package dependency.

    See: Use-Case Docker Host

Informazioni sul progetto

Ansible Role to provision NFTables firewall on linux servers

Installa
ansible-galaxy install ansibleguy.infra_nftables
Licenza
other
Download
4.4k
Proprietario
[email protected] | GPG: https://badges.ansibleguy.net/public.gpg