Support merged firewall rules for multiple groups per host.

- Multiple groups for a single server will now lead to all firewall
    rules being merged instead of overwritten.
This commit is contained in:
Philipp Rintz 2020-11-10 21:17:11 +01:00
parent 6e1c48ee99
commit 290a86e906
9 changed files with 86 additions and 31 deletions

View File

@ -74,6 +74,17 @@ nft_global_default_rules:
# in the Ansible inventory. # in the Ansible inventory.
nft_global_rules: {} nft_global_rules: {}
# ]]] # ]]]
# .. envvar:: merged_groups [[[
#
# Enable or disable the ability to merge multiple firewall group variables
merged_groups: false
# ]]]
# .. envvar:: merged_groups_dir [[[
#
# The directory to read the group firewall rules from.
# Relative to the playbook directory.
merged_groups_dir: vars/
# ]]]
# .. envvar:: nft_global_group_rules [[[ # .. envvar:: nft_global_group_rules [[[
# #
# List of global rules (applied on all tables) to configure for hosts in # List of global rules (applied on all tables) to configure for hosts in

View File

@ -2,16 +2,33 @@
# .. vim: foldmarker=[[[,]]]:foldmethod=marker # .. vim: foldmarker=[[[,]]]:foldmethod=marker
# #
# tasks file for nftables # tasks file for nftables
- name: Import nftables-variables if merged_groups is set
when: merged_groups
set_fact:
"{{ groupname }}": "{{ lookup('file',merged_groups_dir ~ groupname) | from_yaml }}"
loop: "{{ group_names }}"
loop_control:
loop_var: groupname
- name: Combine Rules when merged_groups is set
when: merged_groups
set_fact:
nft_combined_rules: "{{ nft_combined_rules | default({}) | combine ( hostvars[inventory_hostname][groupname], recursive=True ) }}"
loop: "{{ group_names }}"
loop_control:
loop_var: groupname
- name: Load specific OS vars for nftables - name: Load specific OS vars for nftables
include_vars: "{{ item }}" include_vars: "{{ osname }}"
with_first_found: with_first_found:
- "{{ ansible_distribution|lower }}-{{ ansible_distribution_version }}.yml" - "{{ ansible_distribution|lower }}-{{ ansible_distribution_version }}.yml"
- "{{ ansible_distribution|lower }}.yml" - "{{ ansible_distribution|lower }}.yml"
- "{{ ansible_os_family|lower }}.yml" - "{{ ansible_os_family|lower }}.yml"
loop_control:
loop_var: osname
# Manage packages [[[1 # Manage packages [[[1
- name: Ensure Nftables packages are in there desired state - name: Ensure Nftables packages are in their desired state
package: package:
name: '{{ nft_pkg_list | list }}' name: '{{ nft_pkg_list | list }}'
state: '{{ nft_pkg_state }}' state: '{{ nft_pkg_state }}'
@ -19,7 +36,7 @@
until: pkg_install_result is success until: pkg_install_result is success
when: nft_enabled|bool when: nft_enabled|bool
- name: Ensure old Iptables packages are in there desired state - name: Ensure old Iptables packages are in their desired state
apt: apt:
name: '{{ nft_old_pkg_list | list }}' name: '{{ nft_old_pkg_list | list }}'
state: '{{ nft_old_pkg_state }}' state: '{{ nft_old_pkg_state }}'

View File

@ -1,8 +1,12 @@
#jinja2: lstrip_blocks: "True", trim_blocks: "True"
#!/usr/sbin/nft -f #!/usr/sbin/nft -f
# {{ ansible_managed }} # {{ ansible_managed }}
{% set globalmerged = nft_global_default_rules.copy() %} {% set globalmerged = nft_global_default_rules.copy() %}
{% set _ = globalmerged.update(nft_global_rules) %} {% set _ = globalmerged.update(nft_global_rules) %}
{% set _ = globalmerged.update(nft_global_group_rules) %} {% set _ = globalmerged.update(nft_global_group_rules) %}
{% if merged_groups and hostvars[inventory_hostname]['nft_combined_rules'].nft_global_group_rules is defined%}
{% set _ = globalmerged.update(hostvars[inventory_hostname]['nft_combined_rules'].nft_global_group_rules) %}
{% endif %}
{% set _ = globalmerged.update(nft_global_host_rules) %} {% set _ = globalmerged.update(nft_global_host_rules) %}
# clean # clean
@ -14,12 +18,12 @@ table inet filter {
chain global { chain global {
{% for group, rules in globalmerged|dictsort %} {% for group, rules in globalmerged|dictsort %}
# {{ group }} # {{ group }}
{% if not rules %} {% if not rules %}
# (none) # (none)
{% endif %} {% endif %}
{% for rule in rules %} {% for rule in rules %}
{{ rule }} {{ rule }}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
} }
include "{{ nft_set_conf_path }}" include "{{ nft_set_conf_path }}"

View File

@ -1,16 +1,19 @@
#jinja2: lstrip_blocks: "True", trim_blocks: "True"
# {{ ansible_managed }} # {{ ansible_managed }}
{% set definemerged = nft_define_default.copy() %} {% set definemerged = nft_define_default.copy() %}
{% set _ = definemerged.update(nft_define) %} {% set _ = definemerged.update(nft_define) %}
{% set _ = definemerged.update(nft_define_group) %} {% set _ = definemerged.update(nft_define_group) %}
{% if merged_groups and hostvars[inventory_hostname]['nft_combined_rules'].nft_define_group is defined%}
{% set _ = definemerged.update(hostvars[inventory_hostname]['nft_combined_rules'].nft_define_group) %}
{% endif %}
{% set _ = definemerged.update(nft_define_host) %} {% set _ = definemerged.update(nft_define_host) %}
{% for definition in definemerged.values() %} {% for definition in definemerged.values() %}
{% if definition.desc is defined %} {% if definition.desc is defined %}
# {{ definition.desc }} # {{ definition.desc }}
{% else %} {% else %}
# {{ definition.name }} # {{ definition.name }}
{% endif %} {% endif %}
define {{ definition.name }} = {{ definition.value }} define {{ definition.name }} = {{ definition.value }}
{% endfor %} {% endfor %}

View File

@ -1,17 +1,21 @@
#jinja2: lstrip_blocks: "True", trim_blocks: "True"
# {{ ansible_managed }} # {{ ansible_managed }}
{% set inputmerged = nft_input_default_rules.copy() %} {% set inputmerged = nft_input_default_rules.copy() %}
{% set _ = inputmerged.update(nft_input_rules) %} {% set _ = inputmerged.update(nft_input_rules) %}
{% set _ = inputmerged.update(nft_input_group_rules) %} {% set _ = inputmerged.update(nft_input_group_rules) %}
{% if merged_groups and hostvars[inventory_hostname]['nft_combined_rules'].nft_input_group_rules is defined %}
{% set _ = inputmerged.update(hostvars[inventory_hostname]['nft_combined_rules'].nft_input_group_rules) %}
{% endif %}
{% set _ = inputmerged.update(nft_input_host_rules) %} {% set _ = inputmerged.update(nft_input_host_rules) %}
chain input { chain input {
{% for group, rules in inputmerged|dictsort %} {% for group, rules in inputmerged|dictsort %}
# {{ group }} # {{ group }}
{% if not rules %} {% if not rules %}
# (none) # (none)
{% endif %} {% endif %}
{% for rule in rules %} {% for rule in rules %}
{{ rule }} {{ rule }}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
} }

View File

@ -1,17 +1,21 @@
#jinja2: lstrip_blocks: "True", trim_blocks: "True"
# {{ ansible_managed }} # {{ ansible_managed }}
{% set outputmerged = nft_output_default_rules.copy() %} {% set outputmerged = nft_output_default_rules.copy() %}
{% set _ = outputmerged.update(nft_output_rules) %} {% set _ = outputmerged.update(nft_output_rules) %}
{% set _ = outputmerged.update(nft_output_group_rules) %} {% set _ = outputmerged.update(nft_output_group_rules) %}
{% if merged_groups and hostvars[inventory_hostname]['nft_combined_rules'].nft_output_group_rules is defined %}
{% set _ = outputmerged.update(hostvars[inventory_hostname]['nft_combined_rules'].nft_output_group_rules) %}
{% endif %}
{% set _ = outputmerged.update(nft_output_host_rules) %} {% set _ = outputmerged.update(nft_output_host_rules) %}
chain output { chain output {
{% for group, rules in outputmerged|dictsort %} {% for group, rules in outputmerged|dictsort %}
# {{ group }} # {{ group }}
{% if not rules %} {% if not rules %}
# (none) # (none)
{% endif %} {% endif %}
{% for rule in rules %} {% for rule in rules %}
{{ rule }} {{ rule }}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
} }

View File

@ -1,17 +1,21 @@
#jinja2: lstrip_blocks: "True", trim_blocks: "True"
# {{ ansible_managed }} # {{ ansible_managed }}
{% set postroutingmerged = nft__nat_default_postrouting_rules.copy() %} {% set postroutingmerged = nft__nat_default_postrouting_rules.copy() %}
{% set _ = postroutingmerged.update(nft__nat_postrouting_rules) %} {% set _ = postroutingmerged.update(nft__nat_postrouting_rules) %}
{% set _ = postroutingmerged.update(nft__nat_group_postrouting_rules) %} {% set _ = postroutingmerged.update(nft__nat_group_postrouting_rules) %}
{% if merged_groups and hostvars[inventory_hostname]['nft_combined_rules'].nft__nat_group_postrouting_rules is defined %}
{% set _ = postroutingmerged.update(hostvars[inventory_hostname]['nft_combined_rules'].nft__nat_group_postrouting_rules) %}
{% endif %}
{% set _ = postroutingmerged.update(nft__nat_host_postrouting_rules) %} {% set _ = postroutingmerged.update(nft__nat_host_postrouting_rules) %}
chain postrouting { chain postrouting {
{% for group, rules in postroutingmerged|dictsort %} {% for group, rules in postroutingmerged|dictsort %}
# {{ group }} # {{ group }}
{% if not rules %} {% if not rules %}
# (none) # (none)
{% endif %} {% endif %}
{% for rule in rules %} {% for rule in rules %}
{{ rule }} {{ rule }}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
} }

View File

@ -1,17 +1,21 @@
#jinja2: lstrip_blocks: "True", trim_blocks: "True"
# {{ ansible_managed }} # {{ ansible_managed }}
{% set preroutingmerged = nft__nat_default_prerouting_rules.copy() %} {% set preroutingmerged = nft__nat_default_prerouting_rules.copy() %}
{% set _ = preroutingmerged.update(nft__nat_prerouting_rules) %} {% set _ = preroutingmerged.update(nft__nat_prerouting_rules) %}
{% set _ = preroutingmerged.update(nft__nat_group_prerouting_rules) %} {% set _ = preroutingmerged.update(nft__nat_group_prerouting_rules) %}
{% if merged_groups and hostvars[inventory_hostname]['nft_combined_rules'].nft__nat_group_prerouting_rules is defined %}
{% set _ = preroutingmerged.update(hostvars[inventory_hostname]['nft_combined_rules'].nft__nat_group_prerouting_rules) %}
{% endif %}
{% set _ = preroutingmerged.update(nft__nat_host_prerouting_rules) %} {% set _ = preroutingmerged.update(nft__nat_host_prerouting_rules) %}
chain prerouting { chain prerouting {
{% for group, rules in preroutingmerged|dictsort %} {% for group, rules in preroutingmerged|dictsort %}
# {{ group }} # {{ group }}
{% if not rules %} {% if not rules %}
# (none) # (none)
{% endif %} {% endif %}
{% for rule in rules %} {% for rule in rules %}
{{ rule }} {{ rule }}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
} }

View File

@ -1,16 +1,20 @@
#jinja2: lstrip_blocks: "True", trim_blocks: "True"
# {{ ansible_managed }} # {{ ansible_managed }}
{% set setmerged = nft_set_default.copy() %} {% set setmerged = nft_set_default.copy() %}
{% set _ = setmerged.update(nft_set) %} {% set _ = setmerged.update(nft_set) %}
{% set _ = setmerged.update(nft_set_group) %} {% set _ = setmerged.update(nft_set_group) %}
{% if merged_groups and hostvars[inventory_hostname]['nft_combined_rules'].nft_set_group is defined %}
{% set _ = setmerged.update(hostvars[inventory_hostname]['nft_combined_rules'].nft_set_group) %}
{% endif %}
{% set _ = setmerged.update(nft_set_host) %} {% set _ = setmerged.update(nft_set_host) %}
{% for set, rules in setmerged|dictsort %} {% for set, rules in setmerged|dictsort %}
{% if rules %} {% if rules %}
set {{ set }} { set {{ set }} {
{% for rule in rules %} {% for rule in rules %}
{{ rule }} {{ rule }}
{% endfor %} {% endfor %}
} }
{% endif %} {% endif %}
{% endfor %} {% endfor %}