mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
firewalld: add zone target set (#526)
* firewalld: add zone target set Fixes https://github.com/ansible/ansible/issues/49232 Signed-off-by: Adam Miller <admiller@redhat.com> * fix sanity tests, add example of zone target setting Signed-off-by: Adam Miller <admiller@redhat.com> * test different zone/target combination as we're not hitting default settings Signed-off-by: Adam Miller <admiller@redhat.com> * fix enabled values for zone operations Signed-off-by: Adam Miller <admiller@redhat.com> * Apply suggestions from code review Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
42a43586f1
commit
42c5cdf01a
4 changed files with 154 additions and 1 deletions
2
changelogs/fragments/firewalld_zone_target.yml
Normal file
2
changelogs/fragments/firewalld_zone_target.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- firewalld - new feature, can now set ``target`` for a ``zone`` (https://github.com/ansible-collections/community.general/pull/526).
|
|
@ -83,6 +83,13 @@ options:
|
||||||
description:
|
description:
|
||||||
- Whether to run this module even when firewalld is offline.
|
- Whether to run this module even when firewalld is offline.
|
||||||
type: bool
|
type: bool
|
||||||
|
target:
|
||||||
|
description:
|
||||||
|
- firewalld Zone target
|
||||||
|
- If state is set to C(absent), this will reset the target to default
|
||||||
|
choices: [ default, ACCEPT, DROP, REJECT ]
|
||||||
|
type: str
|
||||||
|
version_added: 0.2.0
|
||||||
notes:
|
notes:
|
||||||
- Not tested on any Debian based system.
|
- Not tested on any Debian based system.
|
||||||
- Requires the python2 bindings of firewalld, which may not be installed by default.
|
- Requires the python2 bindings of firewalld, which may not be installed by default.
|
||||||
|
@ -161,6 +168,12 @@ EXAMPLES = r'''
|
||||||
permanent: yes
|
permanent: yes
|
||||||
icmp_block: echo-request
|
icmp_block: echo-request
|
||||||
|
|
||||||
|
- firewalld:
|
||||||
|
zone: internal
|
||||||
|
state: present
|
||||||
|
permanent: yes
|
||||||
|
target: ACCEPT
|
||||||
|
|
||||||
- name: Redirect port 443 to 8443 with Rich Rule
|
- name: Redirect port 443 to 8443 with Rich Rule
|
||||||
firewalld:
|
firewalld:
|
||||||
rich_rule: rule family=ipv4 forward-port port=443 protocol=tcp to-port=8443
|
rich_rule: rule family=ipv4 forward-port port=443 protocol=tcp to-port=8443
|
||||||
|
@ -568,6 +581,53 @@ class SourceTransaction(FirewallTransaction):
|
||||||
self.update_fw_settings(fw_zone, fw_settings)
|
self.update_fw_settings(fw_zone, fw_settings)
|
||||||
|
|
||||||
|
|
||||||
|
class ZoneTargetTransaction(FirewallTransaction):
|
||||||
|
"""
|
||||||
|
ZoneTargetTransaction
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, module, action_args=None, zone=None, desired_state=None,
|
||||||
|
permanent=True, immediate=False, enabled_values=None, disabled_values=None):
|
||||||
|
super(ZoneTargetTransaction, self).__init__(
|
||||||
|
module, action_args=action_args, desired_state=desired_state, zone=zone,
|
||||||
|
permanent=permanent, immediate=immediate,
|
||||||
|
enabled_values=enabled_values or ["present", "enabled"],
|
||||||
|
disabled_values=disabled_values or ["absent", "disabled"])
|
||||||
|
|
||||||
|
self.enabled_msg = "Set zone %s target to %s" % \
|
||||||
|
(self.zone, action_args[0])
|
||||||
|
|
||||||
|
self.disabled_msg = "Reset zone %s target to default" % \
|
||||||
|
(self.zone)
|
||||||
|
|
||||||
|
self.tx_not_permanent_error_msg = "Zone operations must be permanent. " \
|
||||||
|
"Make sure you didn't set the 'permanent' flag to 'false' or the 'immediate' flag to 'true'."
|
||||||
|
|
||||||
|
def get_enabled_immediate(self, target):
|
||||||
|
self.module.fail_json(msg=self.tx_not_permanent_error_msg)
|
||||||
|
|
||||||
|
def get_enabled_permanent(self, target):
|
||||||
|
fw_zone, fw_settings = self.get_fw_zone_settings()
|
||||||
|
current_target = fw_settings.getTarget()
|
||||||
|
return (current_target == target)
|
||||||
|
|
||||||
|
def set_enabled_immediate(self, target):
|
||||||
|
self.module.fail_json(msg=self.tx_not_permanent_error_msg)
|
||||||
|
|
||||||
|
def set_enabled_permanent(self, target):
|
||||||
|
fw_zone, fw_settings = self.get_fw_zone_settings()
|
||||||
|
fw_settings.setTarget(target)
|
||||||
|
self.update_fw_settings(fw_zone, fw_settings)
|
||||||
|
|
||||||
|
def set_disabled_immediate(self, target):
|
||||||
|
self.module.fail_json(msg=self.tx_not_permanent_error_msg)
|
||||||
|
|
||||||
|
def set_disabled_permanent(self, target):
|
||||||
|
fw_zone, fw_settings = self.get_fw_zone_settings()
|
||||||
|
fw_settings.setTarget("default")
|
||||||
|
self.update_fw_settings(fw_zone, fw_settings)
|
||||||
|
|
||||||
|
|
||||||
class ZoneTransaction(FirewallTransaction):
|
class ZoneTransaction(FirewallTransaction):
|
||||||
"""
|
"""
|
||||||
ZoneTransaction
|
ZoneTransaction
|
||||||
|
@ -633,10 +693,12 @@ def main():
|
||||||
interface=dict(type='str'),
|
interface=dict(type='str'),
|
||||||
masquerade=dict(type='str'),
|
masquerade=dict(type='str'),
|
||||||
offline=dict(type='bool'),
|
offline=dict(type='bool'),
|
||||||
|
target=dict(type='str', required=False, choices=['default', 'ACCEPT', 'DROP', 'REJECT']),
|
||||||
),
|
),
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
required_by=dict(
|
required_by=dict(
|
||||||
interface=('zone',),
|
interface=('zone',),
|
||||||
|
target=('zone',),
|
||||||
source=('permanent',),
|
source=('permanent',),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -668,6 +730,7 @@ def main():
|
||||||
rich_rule = module.params['rich_rule']
|
rich_rule = module.params['rich_rule']
|
||||||
source = module.params['source']
|
source = module.params['source']
|
||||||
zone = module.params['zone']
|
zone = module.params['zone']
|
||||||
|
target = module.params['target']
|
||||||
|
|
||||||
if module.params['port'] is not None:
|
if module.params['port'] is not None:
|
||||||
if '/' in module.params['port']:
|
if '/' in module.params['port']:
|
||||||
|
@ -696,12 +759,14 @@ def main():
|
||||||
modification_count += 1
|
modification_count += 1
|
||||||
if source is not None:
|
if source is not None:
|
||||||
modification_count += 1
|
modification_count += 1
|
||||||
|
if target is not None:
|
||||||
|
modification_count += 1
|
||||||
|
|
||||||
if modification_count > 1:
|
if modification_count > 1:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg='can only operate on port, service, rich_rule, masquerade, icmp_block, icmp_block_inversion, interface or source at once'
|
msg='can only operate on port, service, rich_rule, masquerade, icmp_block, icmp_block_inversion, interface or source at once'
|
||||||
)
|
)
|
||||||
elif modification_count > 0 and desired_state in ['absent', 'present']:
|
elif (modification_count > 0) and (desired_state in ['absent', 'present']) and (target is None):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg='absent and present state can only be used in zone level operations'
|
msg='absent and present state can only be used in zone level operations'
|
||||||
)
|
)
|
||||||
|
@ -832,6 +897,20 @@ def main():
|
||||||
changed, transaction_msgs = transaction.run()
|
changed, transaction_msgs = transaction.run()
|
||||||
msgs = msgs + transaction_msgs
|
msgs = msgs + transaction_msgs
|
||||||
|
|
||||||
|
if target is not None:
|
||||||
|
|
||||||
|
transaction = ZoneTargetTransaction(
|
||||||
|
module,
|
||||||
|
action_args=(target,),
|
||||||
|
zone=zone,
|
||||||
|
desired_state=desired_state,
|
||||||
|
permanent=permanent,
|
||||||
|
immediate=immediate,
|
||||||
|
)
|
||||||
|
|
||||||
|
changed, transaction_msgs = transaction.run()
|
||||||
|
msgs = msgs + transaction_msgs
|
||||||
|
|
||||||
''' If there are no changes within the zone we are operating on the zone itself '''
|
''' If there are no changes within the zone we are operating on the zone itself '''
|
||||||
if modification_count == 0 and desired_state in ['absent', 'present']:
|
if modification_count == 0 and desired_state in ['absent', 'present']:
|
||||||
|
|
||||||
|
|
|
@ -33,3 +33,6 @@
|
||||||
|
|
||||||
# firewalld source operation test cases
|
# firewalld source operation test cases
|
||||||
- import_tasks: source_test_cases.yml
|
- import_tasks: source_test_cases.yml
|
||||||
|
|
||||||
|
# firewalld zone target operation test cases
|
||||||
|
- import_tasks: zone_target_test_cases.yml
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Test playbook for the firewalld module - source operations
|
||||||
|
# (c) 2020, Adam Miller <admiller@redhat.com>
|
||||||
|
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
- name: firewalld dmz zone target DROP
|
||||||
|
firewalld:
|
||||||
|
zone: dmz
|
||||||
|
permanent: True
|
||||||
|
state: present
|
||||||
|
target: DROP
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: assert firewalld dmz zone target DROP present worked
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
|
||||||
|
- name: firewalld dmz zone target DROP rerun (verify not changed)
|
||||||
|
firewalld:
|
||||||
|
zone: dmz
|
||||||
|
permanent: True
|
||||||
|
state: present
|
||||||
|
target: DROP
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: assert firewalld dmz zone target DROP present worked (verify not changed)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
|
- name: firewalld dmz zone target DROP absent
|
||||||
|
firewalld:
|
||||||
|
zone: dmz
|
||||||
|
permanent: True
|
||||||
|
state: absent
|
||||||
|
target: DROP
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: assert firewalld dmz zone target DROP absent worked
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
|
||||||
|
- name: firewalld dmz zone target DROP rerun (verify not changed)
|
||||||
|
firewalld:
|
||||||
|
zone: dmz
|
||||||
|
permanent: True
|
||||||
|
state: absent
|
||||||
|
target: DROP
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: assert firewalld dmz zone target DROP present worked (verify not changed)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
Loading…
Reference in a new issue