2017-08-07 12:09:13 +02:00
# Nftables
1. [Overview ](#overview )
2. [Role Variables ](#role-variables )
* [OS Specific Variables ](#os-specific-variables )
2017-08-07 17:07:35 +02:00
* [Rules Dictionaries ](#rules-dictionaries )
2017-08-07 12:09:13 +02:00
3. [Example Playbook ](#example-playbook )
2017-08-23 15:02:27 +02:00
4. [Known Issue ](#known-issue )
5. [Configuration ](#configuration )
6. [Development ](#development )
7. [License ](#license )
8. [Author Information ](#author-information )
2017-08-07 12:09:13 +02:00
## Overview
A role to manage Nftables rules and packages.
2017-08-08 12:11:58 +02:00
Highly inspired by [Mike Gleason firewall role][mikegleasonjr firewall github] (3 levels of rules definition and template), thanks ! I hope i haven't complexify his philosophy… ^^
2017-08-07 17:16:09 +02:00
2017-08-07 12:09:13 +02:00
## Role Variables
* **nft_pkg_manage** : If `nftables` package(s) should be managed with this role [default : `true` ].
* **nft_pkg_state** : State of new `nftables` package(s) [default : `installed` ].
2017-08-18 09:25:28 +02:00
* **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` ].
2017-08-18 09:18:43 +02:00
* **nft_conf_dir_path** : Directory to store the differents Nftables configuration files [default : `/etc/nftables.d` ].
2017-08-07 13:48:54 +02:00
* **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` ].
2017-08-18 09:18:43 +02:00
* **nft_input_conf_path** : Input configuration file include in main configuration file [default : `{{ nft_conf_dir_path }}filter-input.nft` ].
2017-08-09 11:18:49 +02:00
* **nft_input_conf_content** : Template used to generate the previous input configuration file [default : `etc/nftables.d/filter-input.nft.j2` ].
2017-08-18 09:18:43 +02:00
* **nft_output_conf_path** : Output configuration file include in main configuration file [default : `{{ nft_conf_dir_path }}filter-output.nft` ].
2017-08-09 11:18:49 +02:00
* **nft_output_conf_content** : Template used to generate the previous output configuration file [default : `etc/nftables.d/filter-output.nft.j2` ].
2017-08-18 09:18:43 +02:00
* **nft_define_conf_path** : Vars definition file include in main configuration file [default : `{{ nft_conf_dir_path }}defines.nft` ].
2017-08-08 14:32:59 +02:00
* **nft_define_conf_content** : Template used to generate the previous vars definition file [default : `etc/nftables.d/defines.nft.j2` ].
2017-08-18 09:18:43 +02:00
* **nft_sets_conf_path** : Sets and maps definition file include in main configuration file [default : `{{ nft_conf_dir_path }}sets.nft` ].
2017-08-09 11:18:49 +02:00
* **nft_sets_conf_content** : Template used to generate the previous sets and maps definition file [default : `etc/nftables.d/sets.nft.j2` ].
2017-08-07 17:07:35 +02:00
* **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.
2017-08-07 17:41:03 +02:00
* **nft_input_default_rules** : Set default rules for `input` chain.
* **nft_input_group_rules** : You can add `input` rules or override those defined by **nft_input_default_rules** for a group.
* **nft_input_host_rules:** : Hosts can also add or override `input` rules.
2017-08-08 15:35:05 +02:00
* **nft_output_default_rules** : Set default rules for `output` chain.
* **nft_output_group_rules** : You can add `output` rules or override those defined by **nft_output_default_rules** for a group.
* **nft_output_host_rules:** : Hosts can also add or override `output` rules.
2017-08-08 12:11:58 +02:00
* **nft_define_default** : Set default vars available in all rules.
* **nft_define_group** : You can add vars or override those defined by **nft_define_default** for groups.
* **nft_define_host** : You can add or override existant vars.
2017-08-07 14:14:14 +02:00
* **nft_service_manage** : If `nftables` service should be managed with this role [default : `true` ].
* **nft_service_name** : `nftables` service name [default : `nftables` ].
2017-08-09 14:27:07 +02:00
* **nft_service_enabled** : Set `nftables` service available at startup [default : `true` ].
2017-08-07 12:09:13 +02:00
### 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` .
2017-08-07 17:07:35 +02:00
### 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:
2017-08-09 14:56:20 +02:00
005 state management:
2017-08-07 17:07:35 +02:00
- ct state established,related accept
- ct state invalid drop
nft_global_group_rules: {}
nft_global_host_rules: {}
2017-08-07 17:41:03 +02:00
nft_input_default_rules:
000 policy:
- type filter hook input priority 0; policy drop;
2017-08-08 14:32:59 +02:00
005 global:
2017-08-07 17:41:03 +02:00
- jump global
2017-08-08 14:37:54 +02:00
010 drop unwanted:
- ip daddr @blackhole counter drop
2017-08-09 11:05:00 +02:00
015 localhost:
- iif lo accept
2017-08-09 17:14:26 +02:00
200 input udp accepted:
- udp dport @input_udp_accept ct state new accept
210 input tcp accepted:
- tcp dport @input_tcp_accept ct state new accept
2017-08-07 17:41:03 +02:00
nft_input_group_rules: {}
nft_input_host_rules: {}
2017-08-08 14:32:59 +02:00
2017-08-08 15:35:05 +02:00
nft_output_default_rules:
000 policy:
2017-08-09 10:34:29 +02:00
- type filter hook output priority 0; policy drop;
2017-08-08 15:35:05 +02:00
005 global:
- jump global
2017-08-09 11:05:00 +02:00
015 localhost:
- oif lo accept
2017-08-09 16:04:54 +02:00
050 icmp:
- ip protocol icmp accept
2017-08-09 14:56:20 +02:00
200 output udp accepted:
- udp dport @output_udp_accept ct state new accept
210 output tcp accepted:
- tcp dport @output_tcp_accept ct state new accept
2017-08-08 15:35:05 +02:00
nft_output_group_rules: {}
nft_output_host_rules: {}
2017-08-08 14:32:59 +02:00
# 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 }'
2017-08-09 17:14:26 +02:00
input tcp accepted:
name: input_tcp_accept
value: '{ ssh }'
input udp accepted:
name: input_udp_accept
value: 'none'
2017-08-09 14:56:20 +02:00
output tcp accepted:
name: output_tcp_accept
2017-08-11 13:46:50 +02:00
value: '{ http, https, hkp }'
2017-08-09 17:14:26 +02:00
output udp accepted:
name: output_udp_accept
value: '{ bootps, domain, ntp }'
2017-08-08 14:32:59 +02:00
nft_define_group: {}
nft_define_host: {}
2017-08-09 14:56:20 +02:00
# sets and maps
2017-08-08 14:32:59 +02:00
nft_set_default:
blackhole:
- type ipv4_addr;
- elements = $badcast_addr
2017-08-09 17:14:26 +02:00
input_tcp_accept:
- type inet_service; flags interval;
- elements = $input_tcp_accept
input_udp_accept:
2017-08-09 14:56:20 +02:00
- type inet_service; flags interval;
output_tcp_accept:
- type inet_service; flags interval;
- elements = $output_tcp_accept
2017-08-09 17:14:26 +02:00
output_udp_accept:
- type inet_service; flags interval;
- elements = $output_udp_accept
2017-08-08 14:32:59 +02:00
nft_set_group: {}
nft_set_host: {}
2017-08-07 17:07:35 +02:00
```
Those default will generate the following configuration :
```
#!/usr/sbin/nft -f
# Ansible managed
# clean
flush ruleset
2017-08-08 14:32:59 +02:00
include "/etc/nftables.d/defines.nft"
2017-08-09 15:01:35 +02:00
table inet firewall {
2017-08-07 17:07:35 +02:00
chain global {
# 000 state management
ct state established,related accept
ct state invalid drop
}
2017-08-09 11:18:49 +02:00
include "/etc/nftables.d/sets.nft"
include "/etc/nftables.d/filter-input.nft"
include "/etc/nftables.d/filter-output.nft"
2017-08-07 17:07:35 +02:00
}
```
2017-08-09 14:56:20 +02:00
And you can get all rules and definitons by displaying the ruleset on the host : `$ nft list ruleset` :
2017-08-07 17:07:35 +02:00
```
2017-08-09 15:01:35 +02:00
table inet firewall {
2017-08-08 14:32:59 +02:00
set blackhole {
type ipv4_addr
2017-08-09 14:56:20 +02:00
elements = { 255.255.255.255, 224.0.0.1, 224.0.0.251}
}
set output_tcp_accept {
type inet_service
flags interval
2017-08-11 13:46:50 +02:00
elements = { http, https, hkp}
2017-08-09 14:56:20 +02:00
}
set output_udp_accept {
type inet_service
flags interval
elements = { domain, bootps, ntp}
2017-08-08 14:32:59 +02:00
}
2017-08-07 17:07:35 +02:00
chain global {
ct state established,related accept
ct state invalid drop
}
chain input {
2017-08-07 17:41:03 +02:00
type filter hook input priority 0; policy drop;
2017-08-07 17:07:35 +02:00
jump global
2017-08-09 14:56:20 +02:00
ip daddr @blackhole counter packets 0 bytes 0 drop
2017-08-09 11:05:00 +02:00
iif "lo" accept
2017-08-09 17:14:26 +02:00
udp dport @input_udp_accept ct state new accept
tcp dport @input_tcp_accept ct state new accept
2017-08-07 17:07:35 +02:00
}
chain output {
2017-08-09 10:34:29 +02:00
type filter hook output priority 0; policy drop;
2017-08-07 17:07:35 +02:00
jump global
2017-08-09 11:05:00 +02:00
oif "lo" accept
2017-08-09 16:04:54 +02:00
ip protocol icmp accept
2017-08-09 14:56:20 +02:00
udp dport @output_udp_accept ct state new accept
tcp dport @output_tcp_accept ct state new accept
2017-08-07 17:07:35 +02:00
}
}
```
2017-08-07 12:09:13 +02:00
## Example Playbook
* Manage Nftables with defaults vars :
``` yml
- hosts: serverXYZ
roles:
- role: ipr-cnrs.nftables
```
2017-08-09 16:04:54 +02:00
* Use default rules with allow incoming ICMP and count dropped input packets :
2017-08-07 17:59:21 +02:00
`group_vars/first_group` :
``` yaml
nft_input_group_rules:
2017-08-09 16:04:54 +02:00
020 icmp:
- ip protocol icmp icmp type echo-request ip length < = 84 counter limit rate 1/minute accept
2017-08-07 17:59:21 +02:00
999 count policy packet:
- counter
```
2017-08-23 15:02:27 +02:00
## Known Issue
* The first run of a playbook may be long (~8 minutes) just after the (re)start of `nftables` service.
* Probably due to Ansible/OpenSSH Specific default Settings, the outgoing connections for Ansible/SSH will be blocked :
```
trace id d7c3a8dc inet firewall output packet: oif "ens18" ip saddr REMOTE_HOST ip daddr MY_HOST ip dscp 0x02 ip ecn not-ect ip ttl 64 ip id 56799 ip length 420 tcp sport ssh tcp dport 53922 tcp flags == 0x18 tcp window 1452
```
* This only happen at the first run on new clean host. The next runs will works without any delay.
2017-08-07 12:09:13 +02:00
## Configuration
This role will :
* Install `nftables` on the system.
2017-08-09 14:27:07 +02:00
* Enable `nftables` service by default at startup.
2017-08-08 14:32:59 +02:00
* Generate a default configuration file which include all following files and loaded by systemd unit.
2017-08-08 15:35:05 +02:00
* Generate input and output rules files include called by the main configuration file.
2017-08-08 14:32:59 +02:00
* Generate vars in a file and sets and maps in another file.
2017-08-07 14:14:14 +02:00
* Restart `nftables` service.
2017-08-07 12:09:13 +02:00
## Development
This source code comes from our [Gogs instance][nftables source] and the [Github repo][nftables github] exist just to be able to send the role to Ansible Galaxy…
But feel free to send issue/PR here :)
Thanks to this [hook][gogs to github hook], Github automatically got updates from our [Gogs instance][nftables source] :)
## License
[WTFPL][wtfpl website]
## Author Information
Jérémy Gardais
* Source : [on IPR's Gogs][nftables source]
* [IPR][ipr website] (Institut de Physique de Rennes)
[gogs to github hook]: https://stackoverflow.com/a/21998477
[nftables source]: https://git.ipr.univ-rennes1.fr/cellinfo/ansible.nftables
[nftables github]: https://github.com/ipr-cnrs/nftables
[wtfpl website]: http://www.wtfpl.net/about/
[ipr website]: https://ipr.univ-rennes1.fr/
2017-08-07 17:16:09 +02:00
[mikegleasonjr firewall github]: https://github.com/mikegleasonjr/ansible-role-firewall