diff --git a/library/net_infrastructure/firewalld b/library/net_infrastructure/firewalld new file mode 100644 index 0000000000..01d4f3fae6 --- /dev/null +++ b/library/net_infrastructure/firewalld @@ -0,0 +1,299 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013, Adam Miller (maxamillion@fedoraproject.org) +# +# 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 . + +DOCUMENTATION = ''' +--- +module: firewalld +short_description: Manage arbitrary ports/services with firewalld +description: + - This module allows for addition or deletion of services and ports either tcp or udp in either running or permanent firewalld rules +version_added: "1.3" +options: + service: + description: + - "Name of a service to add/remove to/from firewalld - service must be listed in /etc/services" + required: false + default: null + port: + description: + - "Name of a port to add/remove to/from firewalld must be in the form PORT/PROTOCOL" + 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).' + required: false + default: system-default(public) + choices: [ "work", "drop", "internal", "external", "trusted", "home", "dmz", "public", "block"] + permanent: + description: + - "Should this configuration be in the running firewalld configuration or persist across reboots" + required: true + default: true + state: + description: + - "Should this port accept(enabled) or reject(disabled) connections" + required: true + default: enabled + timeout: + description: + - "The amount of time the rule should be in effect for when non-permanent" + required: false + default: 0 +notes: + - Not tested on any debian based system +requirements: [ firewalld >= 0.2.11 ] +author: Adam Miller +''' + +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 +''' + +import os +import re +import sys + +try: + import firewall.config + FW_VERSION = firewall.config.VERSION + + from firewall.client import FirewallClient + fw = FirewallClient() +except ImportError: + print "fail=True msg='firewalld required for this module'" + sys.exit(1) + +################ +# port handling +# +def get_port_enabled(zone, port_proto): + if port_proto in fw.getPorts(zone): + return True + else: + return False + +def set_port_enabled(zone, port, protocol, timeout): + fw.addPort(zone, port, protocol, timeout) + +def set_port_disabled(zone, port, protocol): + fw.removePort(zone, port, protocol) + +def get_port_enabled_permanent(zone, port_proto): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + if tuple(port_proto) in fw_settings.getPorts(): + return True + else: + return False + +def set_port_enabled_permanent(zone, port, protocol): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.addPort(port, protocol) + fw_zone.update(fw_settings) + +def set_port_disabled_permanent(zone, port, protocol): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.removePort(port, protocol) + fw_zone.update(fw_settings) + + +#################### +# service handling +# +def get_service_enabled(zone): + if service in fw.getServices(zone): + return True + else: + return False + +def set_service_enabled(zone, service, timeout): + fw.addService(zone, service, timeout) + +def set_service_disabled(zone, service): + fw.removeService(zone, service) + +def get_service_enabled_permanent(zone, service): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + if service in fw_settings.getServices(): + return True + else: + return False + +def set_service_enabled_permanent(zone, service): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.addService(service) + fw_zone.update(fw_settings) + +def set_service_disabled_permanent(zone, service): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.removeService(service) + fw_zone.update(fw_settings) + +def main(): + + module = AnsibleModule( + argument_spec = dict( + service=dict(required=False,default=None), + port=dict(required=False,default=None), + zone=dict(required=False,default=None), + permanent=dict(type='bool',required=True), + state=dict(choices=['enabled', 'disabled'], required=True), + timeout=dict(required=False,default=0), + ), + supports_check_mode=True + ) + + ## Pre-run version checking + if FW_VERSION < "0.2.11": + module.fail_json(msg='unsupported version of firewalld, requires >= 2.0.11') + + ## Global Vars + changed=False + msgs = [] + service = module.params['service'] + + if module.params['port'] != None: + port, protocol = module.params['port'].split('/') + if protocol == None: + module.fail_json(msg='improper port format (missing protocol?)') + else: + port = None + + if module.params['zone'] != None: + zone = module.params['zone'] + else: + zone = fw.getDefaultZone() + + permanent = module.params['permanent'] + desired_state = module.params['state'] + timeout = module.params['timeout'] + + ## Check for firewalld running + try: + if fw.connected == False: + module.fail_json(msg='firewalld service must be running') + except AttributeError: + 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') + + if service != None: + if permanent: + is_enabled = get_service_enabled_permanent(zone, service) + msgs.append('Permanent operation') + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_service_enabled_permanent(zone, service) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_service_disabled_permanent(zone, service) + changed=True + else: + is_enabled = get_service_enabled(zone, service) + msgs.append('Non-permanent operation') + + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_service_enabled(zone, service, timeout) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_service_disabled(zone, service) + changed=True + + if changed == True: + msgs.append("Changed service %s to %s" % (service, desired_state)) + + if port != None: + if permanent: + is_enabled = get_port_enabled_permanent(zone, [port, protocol]) + msgs.append('Permanent operation') + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_port_enabled_permanent(zone, port, protocol) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_port_disabled_permanent(zone, port, protocol) + changed=True + else: + is_enabled = get_port_enabled(zone, [port,protocol]) + msgs.append('Non-permanent operation') + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_port_enabled(zone, port, protocol, timeout) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_port_disabled(zone, port, protocol) + changed=True + + if changed == True: + msgs.append("Changed port %s to %s" % ("%s/%s" % (port, protocol), \ + desired_state)) + + module.exit_json(changed=changed, msg=', '.join(msgs)) + + +################################################# +# include magic from lib/ansible/module_common.py +#<> + +main() +