diff --git a/library/system/firewalld b/library/system/firewalld index 4665d03a94..9526abbeff 100644 --- a/library/system/firewalld +++ b/library/system/firewalld @@ -36,6 +36,11 @@ options: - "Name of a port to add/remove to/from firewalld must be in the form PORT/PROTOCOL" required: false default: null + rich_rule: + description: + - "Rich rule to add/remove to/from firewalld" + required: false + default: null zone: description: - 'The firewalld zone to add/remove to/from (NOTE: default zone can be configured per system but "public" is default from upstream. Available choices can be extended based on per-system configs, listed here are "out of the box" defaults).' @@ -67,6 +72,7 @@ EXAMPLES = ''' - firewalld: service=https permanent=true state=enabled - firewalld: port=8081/tcp permanent=true state=disabled - firewalld: zone=dmz service=http permanent=true state=enabled +- firewalld: rich_rule='rule service name="ftp" audit limit value="1/m" accept' permanent=true state=enabled ''' import os @@ -154,12 +160,50 @@ def set_service_disabled_permanent(zone, service): fw_settings.removeService(service) fw_zone.update(fw_settings) + +#################### +# rich rule handling +# +def get_rich_rule_enabled(zone, rule): + if rule in fw.getRichRules(zone): + return True + else: + return False + +def set_rich_rule_enabled(zone, rule, timeout): + fw.addRichRule(zone, rule, timeout) + +def set_rich_rule_disabled(zone, rule): + fw.removeRichRule(zone, rule) + +def get_rich_rule_enabled_permanent(zone, rule): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + if rule in fw_settings.getRichRules(): + return True + else: + return False + +def set_rich_rule_enabled_permanent(zone, rule): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.addRichRule(rule) + fw_zone.update(fw_settings) + +def set_rich_rule_disabled_permanent(zone, rule): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.removeRichRule(rule) + fw_zone.update(fw_settings) + + def main(): module = AnsibleModule( argument_spec = dict( service=dict(required=False,default=None), port=dict(required=False,default=None), + rich_rule=dict(required=False,default=None), zone=dict(required=False,default=None), permanent=dict(type='bool',required=True), state=dict(choices=['enabled', 'disabled'], required=True), @@ -176,6 +220,7 @@ def main(): changed=False msgs = [] service = module.params['service'] + rich_rule = module.params['rich_rule'] if module.params['port'] != None: port, protocol = module.params['port'].split('/') @@ -201,8 +246,16 @@ def main(): module.fail_json(msg="firewalld connection can't be established,\ version likely too old. Requires firewalld >= 2.0.11") - if service != None and port != None: - module.fail_json(msg='can only operate on port or service at once') + modification_count = 0 + if service != None: + modification_count += 1 + if port != None: + modification_count += 1 + if rich_rule != None: + modification_count += 1 + + if modification_count > 1: + module.fail_json(msg='can only operate on port, service or rich_rule at once') if service != None: if permanent: @@ -288,6 +341,47 @@ def main(): msgs.append("Changed port %s to %s" % ("%s/%s" % (port, protocol), \ desired_state)) + if rich_rule != None: + if permanent: + is_enabled = get_rich_rule_enabled_permanent(zone, rich_rule) + msgs.append('Permanent operation') + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_rich_rule_enabled_permanent(zone, rich_rule) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_rich_rule_disabled_permanent(zone, rich_rule) + changed=True + else: + is_enabled = get_rich_rule_enabled(zone, rich_rule) + msgs.append('Non-permanent operation') + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_rich_rule_enabled(zone, rich_rule, timeout) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_rich_rule_disabled(zone, rich_rule) + changed=True + + if changed == True: + msgs.append("Changed rich_rule %s to %s" % (rich_rule, desired_state)) + module.exit_json(changed=changed, msg=', '.join(msgs))