diff --git a/README.md b/README.md index 7adbd1f..9e43308 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ 1. [Overview](#overview) 2. [Role Variables](#role-variables) * [OS Specific Variables](#os-specific-variables) + * [Rules Dictionaries](#rules-dictionaries) 3. [Example Playbook](#example-playbook) 4. [Configuration](#configuration) 5. [Development](#development) @@ -19,6 +20,9 @@ A role to manage Nftables rules and packages. * **nft_pkg_state** : State of new `nftables` package(s) [default : `installed`]. * **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_global_default_rules** : Set default rules for `global` chain. Other chains will jump to `global` before apply their specific rules. +* **nft_global_group_rules** : You can add `global` rules or override those defined by **nft_global_default_rules** for a group. +* **nft_global_host_rules:** : Hosts can also add or override `global` rules. * **nft_service_manage** : If `nftables` service should be managed with this role [default : `true`]. * **nft_service_name** : `nftables` service name [default : `nftables`]. @@ -28,6 +32,72 @@ Please see default value by Operating System file in [vars][vars directory] dire * **nft_pkg_list** : The list of package(s) to provide `nftables`. +### 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_*_group_rules** : Can add rules and override those defined by **nft_*_default_rules**. You can define it in `group_vars/webservers`. + * **nft_*_host_rules** : Can add rules and override those define by **nft_*_default_rules** and **nft_*_group_rules**. You can define it in `host_vars/www.local.domain`. + +`defaults/main.yml`: + +``` yml +# rules +nft_global_default_rules: + 000 state management: + - ct state established,related accept + - ct state invalid drop +nft_global_group_rules: {} +nft_global_host_rules: {} +``` + +Those default will generate the following configuration : +``` +#!/usr/sbin/nft -f +# Ansible managed + + +# clean +flush ruleset + +table inet firewall { + chain global { + # 000 state management + ct state established,related accept + ct state invalid drop + } + chain input { + type filter hook input priority 0; + jump global + } + chain output { + type filter hook output priority 0; + jump global + } +} +``` + +And you get the same result by displaying the ruleset on the host : `$ nft list ruleset` : + +``` +table inet firewall { + chain global { + ct state established,related accept + ct state invalid drop + } + + chain input { + type filter hook input priority 0; policy accept; + jump global + } + + chain output { + type filter hook output priority 0; policy accept; + jump global + } +} +``` + ## Example Playbook * Manage Nftables with defaults vars : diff --git a/defaults/main.yml b/defaults/main.yml index 985ac3a..3b74875 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -9,6 +9,14 @@ nft_pkg_state: 'installed' nft_main_conf_path: '/etc/nftables.conf' nft_main_conf_content: 'etc/nftables.conf.j2' +# rules +nft_global_default_rules: + 000 state management: + - ct state established,related accept + - ct state invalid drop +nft_global_group_rules: {} +nft_global_host_rules: {} + # service nft_service_manage: true nft_service_name: 'nftables' diff --git a/templates/etc/nftables.conf.j2 b/templates/etc/nftables.conf.j2 index 1eafe07..9e7c23b 100755 --- a/templates/etc/nftables.conf.j2 +++ b/templates/etc/nftables.conf.j2 @@ -1,14 +1,31 @@ #!/usr/sbin/nft -f # {{ ansible_managed }} +{% set globalmerged = nft_global_default_rules.copy() %} +{% set _ = globalmerged.update(nft_global_group_rules) %} +{% set _ = globalmerged.update(nft_global_host_rules) %} + # clean flush ruleset table inet firewall { + chain global { +{% for group, rules in globalmerged|dictsort %} + # {{ group }} +{% if not rules %} + # (none) +{% endif %} +{% for rule in rules %} + {{ rule }} +{% endfor %} +{% endfor %} + } chain input { type filter hook input priority 0; + jump global } chain output { type filter hook output priority 0; + jump global } }