New module [ufw]: this module handles Ubuntu UFW operations
* Updated documentation related to IPv6 usage. BugFixes: * Solved the default_policy and state mutual exclusive status. * Fixed changed status for IPv6 addresses. Added @otnateos patch.
This commit is contained in:
parent
04a6dc6d12
commit
651c04a3ec
1 changed files with 268 additions and 0 deletions
268
library/system/ufw
Normal file
268
library/system/ufw
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# (c) 2013, Aleksey Ovcharenko <aleksey.ovcharenko@gmail.com>
|
||||||
|
# (c) 2013, James Martin <jmartin@basho.com>
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ufw
|
||||||
|
short_description: This module handles Ubuntu UFW operations
|
||||||
|
description:
|
||||||
|
- This module handles Ubuntu UFW operations
|
||||||
|
options:
|
||||||
|
default_policy:
|
||||||
|
description:
|
||||||
|
- Change the default policy for incoming traffic.
|
||||||
|
required: false
|
||||||
|
choices: ['allow', 'deny', 'reject']
|
||||||
|
default: None
|
||||||
|
delete:
|
||||||
|
description:
|
||||||
|
- Delete rule instead of creation.
|
||||||
|
required: false
|
||||||
|
choices: ['yes', 'no']
|
||||||
|
default: 'no'
|
||||||
|
state:
|
||||||
|
description: |
|
||||||
|
I(enable) reloads firewall and enables firewall on boot.
|
||||||
|
I(disable) unloads firewall and disables firewall on boot.
|
||||||
|
I(reload) reloads firewall.
|
||||||
|
I(reset) disables and resets firewall to installation defaults.
|
||||||
|
I(allow) adds allow rule. See B(EXAMPLES).
|
||||||
|
I(deny) adds deny rule. See B(EXAMPLES).
|
||||||
|
I(reject) adds reject rule. See B(EXAMPLES).
|
||||||
|
I(limit) adds limit rule. Currently only IPv4 is supported. See B(EXAMPLES).
|
||||||
|
required: false
|
||||||
|
choices: ['enable', 'disable', 'reload', 'reset', 'allow', 'deny', 'reject', 'limit']
|
||||||
|
aliases: ['rule']
|
||||||
|
default: 'allow'
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Use profile located in /etc/ufw/applications.d
|
||||||
|
required: false
|
||||||
|
default: None
|
||||||
|
version_added: "2.1"
|
||||||
|
from_ip:
|
||||||
|
description:
|
||||||
|
- Source IP address.
|
||||||
|
required: false
|
||||||
|
aliases: ['src']
|
||||||
|
default: 'any'
|
||||||
|
from_port:
|
||||||
|
description:
|
||||||
|
- Source port.
|
||||||
|
required: false
|
||||||
|
default: 'any'
|
||||||
|
to_ip:
|
||||||
|
description:
|
||||||
|
- Destination IP address.
|
||||||
|
required: false
|
||||||
|
aliases: ['dest']
|
||||||
|
default: 'any'
|
||||||
|
to_port:
|
||||||
|
description:
|
||||||
|
- Destination port.
|
||||||
|
required: false
|
||||||
|
default: 'any'
|
||||||
|
aliases: ['port']
|
||||||
|
proto:
|
||||||
|
description:
|
||||||
|
- TCP/IP protocol.
|
||||||
|
choices: ['any', 'tcp', 'udp', 'ipv6']
|
||||||
|
required: false
|
||||||
|
log:
|
||||||
|
description:
|
||||||
|
- Toggles logging. Logged packets use the LOG_KERN syslog facility.
|
||||||
|
choices: ['yes', 'no']
|
||||||
|
required: false
|
||||||
|
default: 'no'
|
||||||
|
version_added: 2.0
|
||||||
|
notes:
|
||||||
|
- See C(man 8 ufw) for more example.
|
||||||
|
requirements: [ ]
|
||||||
|
author: Aleksey Ovcharenko
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Allow everything and enable UFW
|
||||||
|
ufw: state={{ item }}
|
||||||
|
with_items:
|
||||||
|
- allow
|
||||||
|
- enable
|
||||||
|
|
||||||
|
# Sometimes it is desirable to let the sender know when traffic is
|
||||||
|
# being denied, rather than simply ignoring it. In these cases, use
|
||||||
|
# reject instead of deny. For example:
|
||||||
|
ufw: state=reject port=auth
|
||||||
|
|
||||||
|
# ufw supports connection rate limiting, which is useful for protecting
|
||||||
|
# against brute-force login attacks. ufw will deny connections if an IP
|
||||||
|
# address has attempted to initiate 6 or more connections in the last
|
||||||
|
# 30 seconds. See http://www.debian-administration.org/articles/187
|
||||||
|
# for details. Typical usage is:
|
||||||
|
ufw: state=limit port=ssh proto=tcp
|
||||||
|
|
||||||
|
# Allow OpenSSH
|
||||||
|
ufw: state=allow name=OpenSSH
|
||||||
|
|
||||||
|
# Deny all access to port 53:
|
||||||
|
ufw: state=deny port=53
|
||||||
|
|
||||||
|
# Allow all access to tcp port 80:
|
||||||
|
ufw: state=allow to_port=80 proto=tcp
|
||||||
|
|
||||||
|
# Allow all access from RFC1918 networks to this host:
|
||||||
|
ufw: state=allow from_ip={{ item }}
|
||||||
|
with_items:
|
||||||
|
- 10.0.0.0/8
|
||||||
|
- 172.16.0.0/12
|
||||||
|
- 192.168.0.0/16
|
||||||
|
|
||||||
|
# Deny access to udp port 514 from host 1.2.3.4:
|
||||||
|
ufw: state=deny proto=udp from_ip=1.2.3.4 to_port=514
|
||||||
|
|
||||||
|
# Allow access to udp 1.2.3.4 port 5469 from 1.2.3.5 port 5469:
|
||||||
|
ufw: state=allow proto=udp from_ip=1.2.3.5 from_port=5469 to_ip=1.2.3.4 to_port=5469
|
||||||
|
|
||||||
|
# Deny all traffic from the IPv6 2001:db8::/32 to tcp port 25 on this host.
|
||||||
|
# Note that IPv6 must be enabled in /etc/default/ufw for IPv6 firewalling to work.
|
||||||
|
ufw: state=deny proto=tcp src=2001:db8::/32 port=25
|
||||||
|
'''
|
||||||
|
|
||||||
|
import platform
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec = dict(
|
||||||
|
default_policy = dict(default=None, choices=['allow', 'deny', 'reject'], required=False),
|
||||||
|
state = dict(default=None, aliases=['rule'], choices=['enable', 'disable', 'reload', 'reset', 'allow', 'deny', 'reject', 'limit'], required=False),
|
||||||
|
name = dict(default=None, required=False),
|
||||||
|
from_ip = dict(default='any', aliases=['src'], required=False),
|
||||||
|
from_port = dict(default='any', required=False),
|
||||||
|
to_ip = dict(default='any', aliases=['dest'], required=False),
|
||||||
|
to_port = dict(default='any', aliases=['port'], required=False),
|
||||||
|
proto = dict(default='any', choices=['any', 'tcp', 'udp', 'ipv6'], required=False),
|
||||||
|
delete = dict(default=False, choices=BOOLEANS, required=False),
|
||||||
|
log = dict(default=False, choices=BOOLEANS, required=False)
|
||||||
|
),
|
||||||
|
supports_check_mode = True
|
||||||
|
)
|
||||||
|
|
||||||
|
default_policy = module.params.get('default_policy')
|
||||||
|
state = module.params.get('state')
|
||||||
|
name = module.params.get('name')
|
||||||
|
from_ip = module.params.get('from_ip')
|
||||||
|
from_port = module.params.get('from_port')
|
||||||
|
to_ip = module.params.get('to_ip')
|
||||||
|
to_port = module.params.get('to_port')
|
||||||
|
proto = module.params.get('proto')
|
||||||
|
delete = module.params['delete']
|
||||||
|
log = module.params['log']
|
||||||
|
|
||||||
|
system = platform.system()
|
||||||
|
|
||||||
|
if "Linux" not in system:
|
||||||
|
module.exit_json(msg="Not implemented for system %s. Only Linux (Ubuntu) is supported" % (system), changed=False)
|
||||||
|
else:
|
||||||
|
dist = platform.dist()
|
||||||
|
if dist and 'Ubuntu' not in dist[0]:
|
||||||
|
module.exit_json(msg="Not implemented for distrubution %s. Only Ubuntu is supported" % (dist[0]), changed=False)
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
result['state'] = state
|
||||||
|
|
||||||
|
cmd = module.get_bin_path('ufw')
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
cmd = cmd + ' --dry-run'
|
||||||
|
|
||||||
|
if default_policy:
|
||||||
|
if state:
|
||||||
|
module.fail_json(msg="'default_policy' and 'state' are mutually exclusive options.")
|
||||||
|
else:
|
||||||
|
if default_policy in ['allow', 'deny', 'reject']:
|
||||||
|
cmd = cmd + ' default %s' % (default_policy)
|
||||||
|
changed_marker = "Default incoming policy changed to '%s'\n(be sure to update your rules accordingly)" % (default_policy)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="Wrong default policy %s. See 'ansible-doc ufw' for usage." % (default_policy))
|
||||||
|
|
||||||
|
if not default_policy:
|
||||||
|
if not state:
|
||||||
|
module.fail_json(msg="You must specify either 'default_policy' or 'state' option.")
|
||||||
|
else:
|
||||||
|
if state in 'enable':
|
||||||
|
cmd = cmd + ' -f %s' % (state)
|
||||||
|
changed_marker = 'Firewall is active and enabled on system startup'
|
||||||
|
elif state in 'disable':
|
||||||
|
cmd = cmd + ' -f %s' % (state)
|
||||||
|
changed_marker = 'Firewall stopped and disabled on system startup'
|
||||||
|
elif state in 'reload':
|
||||||
|
cmd = cmd + ' -f %s' % (state)
|
||||||
|
changed_marker = 'Firewall reloaded'
|
||||||
|
elif state in 'reset':
|
||||||
|
cmd = cmd + ' -f %s' % (state)
|
||||||
|
changed_marker = 'Backing up'
|
||||||
|
elif state in ['allow', 'deny', 'reject', 'limit']:
|
||||||
|
changed_marker = ['Rules updated', 'Rules updated (v6)', 'Rule added', 'Rule added (v6)', 'Rule deleted', 'Rule deleted (v6)' ]
|
||||||
|
if delete:
|
||||||
|
cmd = cmd + ' delete'
|
||||||
|
|
||||||
|
cmd = cmd + ' %s' % (state)
|
||||||
|
if log:
|
||||||
|
cmd = cmd + ' log'
|
||||||
|
if name:
|
||||||
|
cmd = cmd + ' %s' % (name)
|
||||||
|
else:
|
||||||
|
if proto and proto not in 'any':
|
||||||
|
cmd = cmd + ' proto %s' % (proto)
|
||||||
|
if from_ip and from_ip not in 'any':
|
||||||
|
cmd = cmd + ' from %s' % (from_ip)
|
||||||
|
if from_port and from_port not in 'any':
|
||||||
|
cmd = cmd + ' port %s' % (from_port)
|
||||||
|
elif from_port and from_port not in 'any':
|
||||||
|
cmd = cmd + ' from port %s' % (from_port)
|
||||||
|
|
||||||
|
if to_ip:
|
||||||
|
cmd = cmd + ' to %s' % (to_ip)
|
||||||
|
if to_port and to_port not in 'any':
|
||||||
|
cmd = cmd + ' port %s' % (to_port)
|
||||||
|
elif to_port and to_port not in 'any':
|
||||||
|
cmd = cmd + ' to port %s' % (to_port)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="Wrong rule %s. See 'ansible-doc ufw' for usage." % (state))
|
||||||
|
|
||||||
|
(rc, out, err) = module.run_command(cmd)
|
||||||
|
|
||||||
|
if rc != 0:
|
||||||
|
if err:
|
||||||
|
module.fail_json(msg=err)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg=out)
|
||||||
|
|
||||||
|
result['cmd'] = cmd
|
||||||
|
result['msg'] = out.rstrip()
|
||||||
|
|
||||||
|
if isinstance(changed_marker, basestring):
|
||||||
|
result['changed'] = result['msg'] in changed_marker
|
||||||
|
else:
|
||||||
|
result['changed'] = any(item in result['msg'] for item in changed_marker)
|
||||||
|
|
||||||
|
return module.exit_json(**result)
|
||||||
|
|
||||||
|
# include magic from lib/ansible/module_common.py
|
||||||
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||||
|
|
||||||
|
main()
|
Loading…
Reference in a new issue