diff --git a/defaults/main.yml b/defaults/main.yml
index 4f04a03..447e4a2 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -2,7 +2,20 @@
firewalld_default_zone: public
firewalld_allow_zone_drifting: False
+# @var firewalld_ipsets:description: A firewalld ipset configuration provides the information of an ip set for firewalld.
+# @var firewalld_ipsets:example: >
+# firewalld_ipsets:
+# - name: appserver
+# type: "hash:net"
+# short: "App Servers"
+# description: "Allow http access from all appservers"
+# option: {}
+# entry:
+# - 192.168.2.1
+# - 192.168.2.2
+# @end
firewalld_ipsets: []
+
firewalld_services: []
# @var firewalld_zones:example: >
diff --git a/molecule/rocky8/tests/test_default.py b/molecule/rocky8/tests/test_default.py
index 18236da..3bd1aa4 100644
--- a/molecule/rocky8/tests/test_default.py
+++ b/molecule/rocky8/tests/test_default.py
@@ -5,3 +5,14 @@ import testinfra.utils.ansible_runner
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ["MOLECULE_INVENTORY_FILE"]
).get_hosts("all")
+
+
+def test_firewalld_is_installed(host):
+ firewalld = host.package("firewalld")
+ assert firewalld.is_installed
+
+
+def test_firewalld_running_and_enabled(host):
+ firewalld = host.service("firewalld")
+ assert firewalld.is_running
+ assert firewalld.is_enabled
diff --git a/tasks/setup.yml b/tasks/setup.yml
index 1cf72ab..98d4de6 100644
--- a/tasks/setup.yml
+++ b/tasks/setup.yml
@@ -7,10 +7,18 @@
- firewalld
- python3-firewall
+ - name: Configure firewalld
+ template:
+ src: etc/firewalld/firewalld.conf.j2
+ dest: /etc/firewalld/firewalld.conf
+ mode: 0644
+ notify: __firewalld_reload
+
- name: Configure firewalld ipsets
template:
src: etc/firewalld/ipsets/ipset.xml.j2
dest: /etc/firewalld/ipsets/{{ item.name }}.xml
+ mode: 0640
loop: "{{ firewalld_ipsets }}"
loop_control:
label: "{{ item.name }}"
@@ -22,21 +30,22 @@
file_type: file
patterns: "*.xml"
register: __firewalld_ipsets_active
- changed_when: false
- failed_when: false
+ changed_when: False
+ failed_when: False
- name: Remove unmanaged ipsets
file:
- path: "/etc/firewalld/ipsets/{{ item }}"
+ path: "{{ item }}"
state: absent
loop: "{{ __firewalld_ipsets_active.files | map(attribute='path') | list }}"
notify: __firewalld_reload
- when: item | replace('.xml','') not in firewalld_ipsets | map(attribute='name') | list
+ when: (item | basename | splitext | first) not in (firewalld_ipsets | map(attribute='name') | list)
- name: Configure firewalld services
template:
src: etc/firewalld/services/service.xml.j2
dest: /etc/firewalld/services/{{ item.name }}.xml
+ mode: 0640
loop: "{{ firewalld_services }}"
loop_control:
label: "{{ item.name }}"
@@ -48,21 +57,22 @@
file_type: file
patterns: "*.xml"
register: __firewalld_services_active
- changed_when: false
- failed_when: false
+ changed_when: False
+ failed_when: False
- name: Remove unmanaged services
file:
- path: "/etc/firewalld/services/{{ item }}"
+ path: "{{ item }}"
state: absent
loop: "{{ __firewalld_services_active.files | map(attribute='path') | list }}"
notify: __firewalld_reload
- when: item | replace('.xml','') not in firewalld_services | map(attribute='name') | list
+ when: (item | basename | splitext | first) not in (firewalld_services | map(attribute='name') | list)
- name: Configure firewalld zones
template:
src: etc/firewalld/zones/zone.xml.j2
dest: /etc/firewalld/zones/{{ item.name }}.xml
+ mode: 0640
loop: "{{ firewalld_zones }}"
loop_control:
label: "{{ item.name }}"
@@ -74,16 +84,16 @@
file_type: file
patterns: "*.xml"
register: __firewalld_zones_active
- changed_when: false
- failed_when: false
+ changed_when: False
+ failed_when: False
- name: Remove unmanaged zones
file:
- path: "/etc/firewalld/zones/{{ item }}"
+ path: "{{ item }}"
state: absent
loop: "{{ __firewalld_zones_active.files | map(attribute='path') | list }}"
notify: __firewalld_reload
- when: item | replace('.xml','') not in firewalld_zones | map(attribute='name') | list
+ when: (item | basename | splitext | first) not in (firewalld_zones | map(attribute='name') | list)
- name: Ensure service is up and running
service:
diff --git a/templates/etc/firewalld/firewalld.conf.j2 b/templates/etc/firewalld/firewalld.conf.j2
index 404be15..8c71afe 100644
--- a/templates/etc/firewalld/firewalld.conf.j2
+++ b/templates/etc/firewalld/firewalld.conf.j2
@@ -1,78 +1,13 @@
#jinja2: lstrip_blocks: True
{{ ansible_managed | comment }}
-# default zone
-# The default zone used if an empty zone string is used.
-# Default: public
DefaultZone={{ firewalld_default_zone }}
-
-# Clean up on exit
-# If set to no or false the firewall configuration will not get cleaned up
-# on exit or stop of firewalld
-# Default: yes
CleanupOnExit=yes
-
-# Lockdown
-# If set to enabled, firewall changes with the D-Bus interface will be limited
-# to applications that are listed in the lockdown whitelist.
-# The lockdown whitelist file is lockdown-whitelist.xml
-# Default: no
Lockdown=no
-
-# IPv6_rpfilter
-# Performs a reverse path filter test on a packet for IPv6. If a reply to the
-# packet would be sent via the same interface that the packet arrived on, the
-# packet will match and be accepted, otherwise dropped.
-# The rp_filter for IPv4 is controlled using sysctl.
-# Note: This feature has a performance impact. See man page FIREWALLD.CONF(5)
-# for details.
-# Default: yes
IPv6_rpfilter=yes
-
-# IndividualCalls
-# Do not use combined -restore calls, but individual calls. This increases the
-# time that is needed to apply changes and to start the daemon, but is good for
-# debugging.
-# Default: no
IndividualCalls=no
-
-# LogDenied
-# Add logging rules right before reject and drop rules in the INPUT, FORWARD
-# and OUTPUT chains for the default rules and also final reject and drop rules
-# in zones. Possible values are: all, unicast, broadcast, multicast and off.
-# Default: off
LogDenied=off
-
-# FirewallBackend
-# Selects the firewall backend implementation.
-# Choices are:
-# - nftables (default)
-# - iptables (iptables, ip6tables, ebtables and ipset)
FirewallBackend=nftables
-
-# FlushAllOnReload
-# Flush all runtime rules on a reload. In previous releases some runtime
-# configuration was retained during a reload, namely; interface to zone
-# assignment, and direct rules. This was confusing to users. To get the old
-# behavior set this to "no".
-# Default: yes
FlushAllOnReload=yes
-
-# RFC3964_IPv4
-# As per RFC 3964, filter IPv6 traffic with 6to4 destination addresses that
-# correspond to IPv4 addresses that should not be routed over the public
-# internet.
-# Defaults to "yes".
RFC3964_IPv4=yes
-
-# AllowZoneDrifting
-# Older versions of firewalld had undocumented behavior known as "zone
-# drifting". This allowed packets to ingress multiple zones - this is a
-# violation of zone based firewalls. However, some users rely on this behavior
-# to have a "catch-all" zone, e.g. the default zone. You can enable this if you
-# desire such behavior. It's disabled by default for security reasons.
-# Note: If "yes" packets will only drift from source based zones to interface
-# based zones (including the default zone). Packets never drift from interface
-# based zones to other interfaces based zones (including the default zone).
-# Possible values; "yes", "no". Defaults to "yes".
AllowZoneDrifting={{ firewalld_allow_zone_drifting | bool | ternary("yes", "no", "no") }}
diff --git a/templates/etc/firewalld/ipsets/ipset.xml.j2 b/templates/etc/firewalld/ipsets/ipset.xml.j2
index e69de29..86a3d52 100644
--- a/templates/etc/firewalld/ipsets/ipset.xml.j2
+++ b/templates/etc/firewalld/ipsets/ipset.xml.j2
@@ -0,0 +1,16 @@
+#jinja2: lstrip_blocks: True
+
+
+{% if item.short is defined %}
+ {{ item.short }}
+{% endif %}
+{% if item.description is defined %}
+ {{ item.description }}
+{% endif %}
+{% for name, value in (item.option | default({})).items() %}
+
+{% endfor %}
+{% for entry in item.entry | default([]) %}
+ {{ entry }}
+{% endfor %}
+
diff --git a/templates/etc/firewalld/services/service.xml.j2 b/templates/etc/firewalld/services/service.xml.j2
index e69de29..f1d6afb 100644
--- a/templates/etc/firewalld/services/service.xml.j2
+++ b/templates/etc/firewalld/services/service.xml.j2
@@ -0,0 +1,21 @@
+#jinja2: lstrip_blocks: True
+
+
+{% if item.short is defined %}
+ {{ item.short }}
+{% endif %}
+{% if item.description is defined %}
+ {{ item.description }}
+{% endif %}
+{% for tag in item %}
+{# Tags which can be used several times #}
+{% if tag in ["port", "protocol", "source-port", "module"] %}
+{% for subtag in item[tag] %}
+ <{{ tag }}{% for name, value in subtag.items() %} {{ name }}="{{ value }}"{% endfor %}/>
+{% endfor %}
+{# Tags which can be used once #}
+{% elif tag in ["destination"] %}
+ <{{ tag }}{% for name, value in tag.items() | default({}) %} {{ name }}="{{ value }}"{% endfor %}/>
+{% endif %}
+{% endfor %}
+
diff --git a/templates/etc/firewalld/zones/zone.xml.j2 b/templates/etc/firewalld/zones/zone.xml.j2
index 26f6b44..d172507 100644
--- a/templates/etc/firewalld/zones/zone.xml.j2
+++ b/templates/etc/firewalld/zones/zone.xml.j2
@@ -1,6 +1,4 @@
#jinja2: lstrip_blocks: True
-{{ ansible_managed | comment("xml") }}
-
{{ item.short | default(item.name) | upper }}
@@ -11,12 +9,12 @@
{% for tag in item %}
{# Settings which can be used several times #}
- {% if tag in ['interface','source','service','port','protocol','icmp-block','forward-port','source-port'] %}
+ {% if tag in ["interface", "source", "service", "port", "protocol", "icmp-block", "forward-port", "source-port"] %}
{% for subtag in item[tag] %}
- <{{ tag }}{% for name,value in subtag.items() %} {{ name }}="{{ value }}"{% endfor %}/>
+ <{{ tag }}{% for name, value in subtag.items() %} {{ name }}="{{ value }}"{% endfor %}/>
{% endfor %}
{# Settings which can be used once #}
- {% elif tag in ['icmp-block-inversion','masquerade'] and item[tag] == True %}
+ {% elif tag in ["icmp-block-inversion", "masquerade"] and item[tag] == True %}
<{{ tag }}/>
{% endif %}
{% endfor %}
@@ -26,10 +24,10 @@
{% for rule in item.rule | default([]) %}
{% for tag in rule %}
- {% if tag in ['source','destination','service','port','icmp-block','icmp-type','masquerade','forward-port'] %}
- <{{ tag }}{% for name,value in tag.items() | default({}) %} {{ name }}="{{ value }}"{% endfor %}/>
- {% elif tag in ['log','audit','accept','drop','mark','reject'] %}
- <{{ tag }}{% for name,value in tag.items() %} {{ name }}="{{ value }}"{% endfor %}>
+ {% if tag in ["source", "destination", "service", "port", "icmp-block", "icmp-type", "masquerade", "forward-port"] %}
+ <{{ tag }}{% for name, value in tag.items() | default({}) %} {{ name }}="{{ value }}"{% endfor %}/>
+ {% elif tag in ["log", "audit", "accept", "drop", "mark", "reject"] %}
+ <{{ tag }}{% for name, value in tag.items() %} {{ name }}="{{ value }}"{% endfor %}>
{% endif %}
{% if tag.limit is defined %}