Michael Grote
ccaaabc1be
Reviewed-on: #583 Co-authored-by: Michael Grote <michael.grote@posteo.de> Co-committed-by: Michael Grote <michael.grote@posteo.de>
397 lines
13 KiB
Python
397 lines
13 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright: (c) 2021, Hideki Saito <saito@fgrep.org>
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
from __future__ import (absolute_import, division, print_function)
|
|
__metaclass__ = type
|
|
|
|
DOCUMENTATION = r'''
|
|
---
|
|
module: firewalld_info
|
|
short_description: Gather information about firewalld
|
|
description:
|
|
- This module gathers information about firewalld rules.
|
|
options:
|
|
active_zones:
|
|
description: Gather information about active zones.
|
|
type: bool
|
|
default: false
|
|
zones:
|
|
description:
|
|
- Gather information about specific zones.
|
|
- If only works if C(active_zones) is set to C(false).
|
|
required: false
|
|
type: list
|
|
elements: str
|
|
requirements:
|
|
- firewalld >= 0.2.11
|
|
- python-firewall
|
|
- python-dbus
|
|
author:
|
|
- Hideki Saito (@saito-hideki)
|
|
'''
|
|
|
|
EXAMPLES = r'''
|
|
- name: Gather information about active zones
|
|
ansible.posix.firewalld_info:
|
|
active_zones: true
|
|
register: result
|
|
|
|
- name: Print default zone for debugging
|
|
ansible.builtin.debug:
|
|
var: result.firewalld_info.default_zone
|
|
|
|
- name: Gather information about specific zones
|
|
ansible.posix.firewalld_info:
|
|
zones:
|
|
- public
|
|
- external
|
|
- internal
|
|
register: result
|
|
'''
|
|
|
|
RETURN = r'''
|
|
active_zones:
|
|
description:
|
|
- Gather active zones only if turn it C(true).
|
|
returned: success
|
|
type: bool
|
|
sample: false
|
|
collected_zones:
|
|
description:
|
|
- A list of collected zones.
|
|
returned: success
|
|
type: list
|
|
sample: [external, internal]
|
|
undefined_zones:
|
|
description:
|
|
- A list of undefined zones in C(zones) option.
|
|
- C(undefined_zones) will be ignored for gathering process.
|
|
returned: success
|
|
type: list
|
|
sample: [foo, bar]
|
|
firewalld_info:
|
|
description:
|
|
- Returns various information about firewalld configuration.
|
|
returned: success
|
|
type: complex
|
|
contains:
|
|
version:
|
|
description:
|
|
- The version information of firewalld.
|
|
returned: success
|
|
type: str
|
|
sample: 0.8.2
|
|
default_zone:
|
|
description:
|
|
- The zone name of default zone.
|
|
returned: success
|
|
type: str
|
|
sample: public
|
|
zones:
|
|
description:
|
|
- A dict of zones to gather information.
|
|
returned: success
|
|
type: complex
|
|
contains:
|
|
zone:
|
|
description:
|
|
- The zone name registered in firewalld.
|
|
returned: success
|
|
type: complex
|
|
sample: external
|
|
contains:
|
|
target:
|
|
description:
|
|
- A list of services in the zone.
|
|
returned: success
|
|
type: str
|
|
sample: ACCEPT
|
|
icmp_block_inversion:
|
|
description:
|
|
- The ICMP block inversion to block
|
|
all ICMP requests.
|
|
returned: success
|
|
type: bool
|
|
sample: false
|
|
interfaces:
|
|
description:
|
|
- A list of network interfaces.
|
|
returned: success
|
|
type: list
|
|
sample:
|
|
- 'eth0'
|
|
- 'eth1'
|
|
sources:
|
|
description:
|
|
- A list of source network address.
|
|
returned: success
|
|
type: list
|
|
sample:
|
|
- '172.16.30.0/24'
|
|
- '172.16.31.0/24'
|
|
services:
|
|
description:
|
|
- A list of network services.
|
|
returned: success
|
|
type: list
|
|
sample:
|
|
- 'dhcp'
|
|
- 'dns'
|
|
- 'ssh'
|
|
ports:
|
|
description:
|
|
- A list of network port with protocol.
|
|
returned: success
|
|
type: list
|
|
sample:
|
|
- - "22"
|
|
- "tcp"
|
|
- - "80"
|
|
- "tcp"
|
|
protocols:
|
|
description:
|
|
- A list of network protocol.
|
|
returned: success
|
|
type: list
|
|
sample:
|
|
- "icmp"
|
|
- "ipv6-icmp"
|
|
forward:
|
|
description:
|
|
- The network interface forwarding.
|
|
- This parameter supports on python-firewall
|
|
0.9.0(or later) and is not collected in earlier
|
|
versions.
|
|
returned: success
|
|
type: bool
|
|
sample: false
|
|
masquerade:
|
|
description:
|
|
- The network interface masquerading.
|
|
returned: success
|
|
type: bool
|
|
sample: false
|
|
forward_ports:
|
|
description:
|
|
- A list of forwarding port pair with protocol.
|
|
returned: success
|
|
type: list
|
|
sample:
|
|
- "icmp"
|
|
- "ipv6-icmp"
|
|
source_ports:
|
|
description:
|
|
- A list of network source port with protocol.
|
|
returned: success
|
|
type: list
|
|
sample:
|
|
- - "30000"
|
|
- "tcp"
|
|
- - "30001"
|
|
- "tcp"
|
|
icmp_blocks:
|
|
description:
|
|
- A list of blocking icmp protocol.
|
|
returned: success
|
|
type: list
|
|
sample:
|
|
- "echo-request"
|
|
rich_rules:
|
|
description:
|
|
- A list of rich language rule.
|
|
returned: success
|
|
type: list
|
|
sample:
|
|
- "rule protocol value=\"icmp\" reject"
|
|
- "rule priority=\"32767\" reject"
|
|
'''
|
|
|
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
|
from ansible.module_utils._text import to_native
|
|
from ansible_collections.ansible.posix.plugins.module_utils.version import StrictVersion
|
|
|
|
|
|
try:
|
|
import dbus
|
|
HAS_DBUS = True
|
|
except ImportError:
|
|
HAS_DBUS = False
|
|
|
|
try:
|
|
import firewall.client as fw_client
|
|
import firewall.config as fw_config
|
|
HAS_FIREWALLD = True
|
|
except ImportError:
|
|
HAS_FIREWALLD = False
|
|
|
|
|
|
def get_version():
|
|
return fw_config.VERSION
|
|
|
|
|
|
def get_active_zones(client):
|
|
return client.getActiveZones().keys()
|
|
|
|
|
|
def get_all_zones(client):
|
|
return client.getZones()
|
|
|
|
|
|
def get_default_zone(client):
|
|
return client.getDefaultZone()
|
|
|
|
|
|
def get_zone_settings(client, zone):
|
|
return client.getZoneSettings(zone)
|
|
|
|
|
|
def get_zone_target(zone_settings):
|
|
return zone_settings.getTarget()
|
|
|
|
|
|
def get_zone_icmp_block_inversion(zone_settings):
|
|
return zone_settings.getIcmpBlockInversion()
|
|
|
|
|
|
def get_zone_interfaces(zone_settings):
|
|
return zone_settings.getInterfaces()
|
|
|
|
|
|
def get_zone_sources(zone_settings):
|
|
return zone_settings.getSources()
|
|
|
|
|
|
def get_zone_services(zone_settings):
|
|
return zone_settings.getServices()
|
|
|
|
|
|
def get_zone_ports(zone_settings):
|
|
return zone_settings.getPorts()
|
|
|
|
|
|
def get_zone_protocols(zone_settings):
|
|
return zone_settings.getProtocols()
|
|
|
|
|
|
# This function supports python-firewall 0.9.0(or later).
|
|
def get_zone_forward(zone_settings):
|
|
return zone_settings.getForward()
|
|
|
|
|
|
def get_zone_masquerade(zone_settings):
|
|
return zone_settings.getMasquerade()
|
|
|
|
|
|
def get_zone_forward_ports(zone_settings):
|
|
return zone_settings.getForwardPorts()
|
|
|
|
|
|
def get_zone_source_ports(zone_settings):
|
|
return zone_settings.getSourcePorts()
|
|
|
|
|
|
def get_zone_icmp_blocks(zone_settings):
|
|
return zone_settings.getIcmpBlocks()
|
|
|
|
|
|
def get_zone_rich_rules(zone_settings):
|
|
return zone_settings.getRichRules()
|
|
|
|
|
|
def main():
|
|
module_args = dict(
|
|
active_zones=dict(required=False, type='bool', default=False),
|
|
zones=dict(required=False, type='list', elements='str'),
|
|
)
|
|
|
|
module = AnsibleModule(
|
|
argument_spec=module_args,
|
|
supports_check_mode=True,
|
|
)
|
|
|
|
firewalld_info = dict()
|
|
result = dict(
|
|
changed=False,
|
|
active_zones=module.params['active_zones'],
|
|
collected_zones=list(),
|
|
undefined_zones=list(),
|
|
warnings=list(),
|
|
)
|
|
|
|
# Exit with failure message if requirements modules are not installed.
|
|
if not HAS_DBUS:
|
|
module.fail_json(msg=missing_required_lib('python-dbus'))
|
|
if not HAS_FIREWALLD:
|
|
module.fail_json(msg=missing_required_lib('python-firewall'))
|
|
|
|
# If you want to show warning messages in the task running process,
|
|
# you can append the message to the 'warn' list.
|
|
warn = list()
|
|
|
|
try:
|
|
client = fw_client.FirewallClient()
|
|
|
|
# Gather general information of firewalld.
|
|
firewalld_info['version'] = get_version()
|
|
firewalld_info['default_zone'] = get_default_zone(client)
|
|
|
|
# Gather information for zones.
|
|
zones_info = dict()
|
|
collect_zones = list()
|
|
ignore_zones = list()
|
|
if module.params['active_zones']:
|
|
collect_zones = get_active_zones(client)
|
|
elif module.params['zones']:
|
|
all_zones = get_all_zones(client)
|
|
specified_zones = module.params['zones']
|
|
collect_zones = list(set(specified_zones) & set(all_zones))
|
|
ignore_zones = list(set(specified_zones) - set(collect_zones))
|
|
warn.append(
|
|
'Please note: zone:(%s) have been ignored in the gathering process.' % ','.join(ignore_zones))
|
|
else:
|
|
collect_zones = get_all_zones(client)
|
|
|
|
for zone in collect_zones:
|
|
# Gather settings for each zone based on the output of
|
|
# 'firewall-cmd --info-zone=<ZONE>' command.
|
|
zone_info = dict()
|
|
zone_settings = get_zone_settings(client, zone)
|
|
zone_info['target'] = get_zone_target(zone_settings)
|
|
zone_info['icmp_block_inversion'] = get_zone_icmp_block_inversion(zone_settings)
|
|
zone_info['interfaces'] = get_zone_interfaces(zone_settings)
|
|
zone_info['sources'] = get_zone_sources(zone_settings)
|
|
zone_info['services'] = get_zone_services(zone_settings)
|
|
zone_info['ports'] = get_zone_ports(zone_settings)
|
|
zone_info['protocols'] = get_zone_protocols(zone_settings)
|
|
zone_info['masquerade'] = get_zone_masquerade(zone_settings)
|
|
zone_info['forward_ports'] = get_zone_forward_ports(zone_settings)
|
|
zone_info['source_ports'] = get_zone_source_ports(zone_settings)
|
|
zone_info['icmp_blocks'] = get_zone_icmp_blocks(zone_settings)
|
|
zone_info['rich_rules'] = get_zone_rich_rules(zone_settings)
|
|
|
|
# The 'forward' parameter supports on python-firewall 0.9.0(or later).
|
|
if StrictVersion(firewalld_info['version']) >= StrictVersion('0.9.0'):
|
|
zone_info['forward'] = get_zone_forward(zone_settings)
|
|
|
|
zones_info[zone] = zone_info
|
|
firewalld_info['zones'] = zones_info
|
|
except AttributeError as e:
|
|
module.fail_json(msg=('firewalld probably not be running, Or the following method '
|
|
'is not supported with your python-firewall version. (Error: %s)') % to_native(e))
|
|
except dbus.exceptions.DBusException as e:
|
|
module.fail_json(msg=('Unable to gather firewalld settings.'
|
|
' You may need to run as the root user or'
|
|
' use become. (Error: %s)' % to_native(e)))
|
|
|
|
result['collected_zones'] = collect_zones
|
|
result['undefined_zones'] = ignore_zones
|
|
result['firewalld_info'] = firewalld_info
|
|
result['warnings'] = warn
|
|
module.exit_json(**result)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|