diff --git a/CHANGELOG.md b/CHANGELOG.md
index cea79a0..cbc1727 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,16 @@
## v1.X.Y
-### Fix
+### Added
+* New examples usecases (mostly for playbooks) in README.md.
+
+### Removed
+* Remove everything related to **in_udp_accept** (see conversation in PR #13).
+ Cause it was empty by default and the role currently doesn't manage it very
+ well. Take a look to new examples in README.md to find your preferred solution
+ (re-adding it, new simple/multi-ports filter rule,…).
+
+### Fixed
* Ansible-lint: Fix line longer than 160 chars.
-* Remove everything related to in_udp_accept (see conversation in PR #13).
- Cause it was empty by default and the role currently doesn't manage it well.
## v1.7.0
diff --git a/README.md b/README.md
index 45c7d3d..534bac4 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,24 @@
# Nftables
1. [Overview](#overview)
-2. [Role Variables](#role-variables)
+1. [Role Variables](#role-variables)
* [OS Specific Variables](#os-specific-variables)
* [Rules Dictionaries](#rules-dictionaries)
-3. [Example Playbook](#example-playbook)
-4. [Known Issue](#known-issue)
-5. [Configuration](#configuration)
-6. [Development](#development)
-7. [License](#license)
-8. [Author Information](#author-information)
+1. [Examples](#examples)
+ * [With playbooks](#with-playbooks)
+ * [With group_vars and host_vars](#with-group_vars-and-host_vars)
+1. [Configuration](#configuration)
+1. [Development](#development)
+1. [License](#license)
+1. [Author Information](#author-information)
## Overview
A role to manage Nftables rules and packages.
-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… ^^
+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… (I'm pretty sure, i now did complexify it :D) ^^
## Role Variables
@@ -241,17 +244,189 @@ table inet filter {
}
```
-## Example Playbook
+## Examples
-* Manage Nftables with defaults vars :
+### With playbooks
+
+
+ Manage Nftables with defaults vars (click to expand)
+
``` yml
- hosts: serverXYZ
roles:
- role: ipr-cnrs.nftables
```
+
-* Override some of the default defined sets:
+
+ Add a new simple filter rule for incoming traffic (eg. 1 port for UDP/torrent) (click to expand)
+
+``` yml
+- 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)
+
+``` yml
+- 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.
+``` yml
+- 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.
+1. Add a new rule for incoming traffic and use the previous defined variable.
+1. Result of `nft list ruleset` on the remote host will be :
+ ``` bash
+ 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.
+``` yml
+- 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).
+1. Add a new rule for incoming traffic and use the previous defined set.
+1. On the remote host, if you try to add a port to this set : `nft add element inet filter in_udp_accept \{ 6999 \}`
+1. Result of `nft list ruleset` on the remote host will now be :
+ ``` bash
+ 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)
+
+``` yml
+- 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`).
+1. Drop any ICMP request that doesn't come from 192.168.0.0 network.
+1. 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)
``` yml
- hosts: serverXYZ
@@ -261,15 +436,76 @@ table inet filter {
desc: Custom SSH port and torrent
name: in_tcp_accept
value: '{ 2201, 6881 }'
- input udp accepted:
- desc: torrent
- name: in_udp_accept
- value: '{ 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.
+1. Set a new value (eg. `'{ 2201, 6881 }'`).
+1. 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.
+
-* Use default rules with allow incoming ICMP and count dropped input packets :
+
+ 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 :
+``` yml
+- 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`.
+ 1. manage already `established` state.
+ 1. 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)
+
+``` yml
+- 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`).
+1. 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.
+1. 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` :
@@ -280,62 +516,61 @@ nft_input_group_rules:
999 count policy packet:
- counter
```
+
-* Use merged group rules from multiple ansible groups:
+
+ Use merged group rules from multiple ansible groups (click to expand)
-``` yml
-- hosts: serverXYZ
- vars:
- nft_merged_groups: true
- nft_merged_groups_dir: vars/
- roles:
- - role: ipr-cnrs.nftables
-```
-
-And put the rules inside the "vars" folder named after your ansible groups of the server:
-
-`vars/first_group` :
-
-``` yaml
-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` :
-
-``` yaml
-nft_input_group_rules:
- 021 LAN:
- - iif eth0 accept
-```
-
-These rulesets from the two groups will be merged if the host has the two groups as ansible roles.
-
-## Known Issue
-
-* The 10 minutes delay at the first run is finally fixed by allowing the host to reset SSH connection (flags `rst, psh | ack`) (see #1).
+1. Enable to merge group's variables :
+ ``` yml
+ - hosts: serverXYZ
+ vars:
+ nft_merged_groups: true
+ nft_merged_groups_dir: vars/
+ roles:
+ - role: ipr-cnrs.nftables
+ ```
+1. Put extra rules inside the "vars" folder named after your ansible groups for serverXYZ :
+ * `vars/first_group` :
+ ``` yaml
+ 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` :
+ ``` yaml
+ nft_input_group_rules:
+ 021 LAN:
+ - iif eth0 accept
+ ```
+1. 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 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.
* (re)Start `nftables` service at first run.
-* Reload `nftables` service at next runs to avoid to let the host without firewall rules due to invalid syntax.
+* Reload `nftables` service at next runs to avoid to let the host without firewall
+ rules due to invalid syntax.
## 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…
+This source code comes from our [Gitea 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] :)
+Thanks to this [hook][gogs to github hook], Github automatically got updates from our [Gitea instance][nftables source] :)
## License
@@ -344,7 +579,7 @@ Thanks to this [hook][gogs to github hook], Github automatically got updates fro
## Author Information
Jérémy Gardais
-* Source : [on IPR's Gogs][nftables source]
+* Source : [on IPR's Gitea][nftables source]
* [IPR][ipr website] (Institut de Physique de Rennes)
[gogs to github hook]: https://stackoverflow.com/a/21998477