Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/ops 78 implement highlevel configuration of rules #27

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@
!.vscode/settings.json
!.vscode/extensions.json
.idea
\#*\#
*~
*.pyc
pytestdebug.log
.cache
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,40 @@ $ git clone https://github.com/weareinteractive/ansible-ufw.git weareinteractive

Here is a list of all the default variables for this role, which are also available in `defaults/main.yml`.

| Variable | Default | Comments (type) |
| :--- | :--- | :--- |
| ufw_allow_tcp_ports | | List of tcp ports/services which are open to the public |
| ufw_allow_udp_ports | | List of udp ports/services which are open to the public |
| ufw_allow_interfaces | | List of interfaces through which access is generally allowed |
| ufw_ports_acl | | List of dictionary structure containing rule configuration. Structure is documented below. |


ufw_ports_acl structure
-----------------------

```yaml
ufw_ports_acl:
- name: SSH
port: 22
ips: "{{ firewall_ssh_ips }}"
- name: SNMP
port: 161
proto: UDP
ips: "{{ firewall_snmp_ips }}"
```

| Variable | Default | Comments (type) |
| :--- | :--- | :--- |
| name | | A name identifying the rule |
| port | | Destination port |
| proto | | Protocol to be used |
| ips | | List of source IP addresses |






```yaml
---
# Start the service and enable it on system boot
Expand Down Expand Up @@ -74,6 +108,37 @@ ufw_config:
# Path to the configuration file
ufw_config_file: /etc/default/ufw

ufw_allow_tcp_ports:
- 80
- 443
- ssh

ufw_allow_udp_ports:
- 161

ufw_allow_interfaces:
- openvpntun+

firewall_ssh_ips: "{{ firewall_ssh_ips_default }}"
firewall_ssh_ips_default:
- x.x.x.x
- y.y.y.y

firewall_snmp_ips: "{{ firewall_snmp_ips_default }}"
firewall_snmp_ips_default:
- a.a.a.a
- b.b.b.b

ufw_ports_acl:
- name: SSH
port: 22
ips: "{{ firewall_ssh_ips }}"
- name: SNMP
port: 161
proto: UDP
ips: "{{ firewall_snmp_ips }}"


```

## Handlers
Expand Down
18 changes: 18 additions & 0 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,21 @@ ufw_config:

# Path to the configuration file
ufw_config_file: /etc/default/ufw

# List of TCP ports to be opened to the public
ufw_allow_tcp_ports: []

# List of UDP ports to be opened to the public
ufw_allow_udp_ports: []

# List of interfaces to be opened to the public
ufw_allow_interfaces: []

# List of rules to be opened. Format of the structure:
# - name: <name>
# port: 22
# proto: TCP (default)
# ips:
# - a.a.a.a
# - b.b.b.b
ufw_ports_acl: []
23 changes: 22 additions & 1 deletion molecule/default/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,29 @@
collections:
- community.general
vars:
ufw_enabled: false
ufw_enabled: true
ufw_rules: []
ufw_allow_tcp_ports:
- 80
- https
ufw_allow_udp_ports:
- 161
- 162
ufw_allow_interfaces:
- tun0
- openvpntap0
ufw_ports_acl:
- name: SSH
port: 22
ips:
- 10.0.0.0/8
- 192.168.0.0/16
- name: SIP
port: 5060
proto: UDP
ips:
- 10.0.0.0/24
- 192.168.0.0/24

pre_tasks:
- name: Update apt cache.
Expand Down
6 changes: 4 additions & 2 deletions molecule/default/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ dependency:
driver:
name: docker
lint: |
set -e
yamllint .
ansible-lint
platforms:
Expand All @@ -21,4 +20,7 @@ provisioner:
playbooks:
converge: ${MOLECULE_PLAYBOOK:-converge.yml}
verifier:
name: ansible
name: testinfra
options:
v: 1
sudo: true
145 changes: 145 additions & 0 deletions molecule/default/tests/test_default.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
# :Project: weareinteractive.ufw ansible role - unittests
# :Created: Fri 17 Sep 2021 21:31:46 CEST
# :Author: Peter Warasin <[email protected]>
# :License: GPLv2
# :Copyright: © 2021 Endian s.r.l.
#


"""
test_default.py - default unittest file.

This file contains unittests using testinfra used to test if the
ansible role does what we wanted that it would do.
"""

from types import SimpleNamespace
import pytest


@pytest.fixture(name="facts", scope="module")
def fixture_facts(host):
"""
Set up the environment before the test.

Setup environment by retrieving information from host which we
need for out tests.

:param value: host
:type value: the link to the testinfra host
:return: an object holding the retrieved ansible facts
:rtype: types.SimpleNamespace
"""
ansible_facts = host.ansible("setup")["ansible_facts"]
ret = SimpleNamespace()
ret.host_os = ansible_facts["ansible_lsb"]["codename"]
return ret


def test_service(host):
"""
Tests if the firewalld service is enabled.

This test method checks if the firewalld service is enabled.

:param host: the link to the testinfra host provided by fixture
:type host: Host object
"""
service = host.service("ufw")
assert service.is_enabled


def test_ufw_allow_tcp_ports(host, facts):
"""
Tests if the configured TCP ports are open.

This test method checks if iptable rules do exist which open
ports as configured in the inventory.

:param value: host
:type value: the link to the testinfra host
:param facts: Retrieved ansible facts
:type facts: types.SimpleNamespace
"""
rules = host.iptables.rules()

testrules = [
"-A ufw-user-input -p tcp -m tcp --dport 80 -j ACCEPT",
"-A ufw-user-input -p tcp -m tcp --dport 443 -j ACCEPT",
]

for testrule in testrules:
assert testrule in rules


def test_ufw_allow_udp_ports(host, facts):
"""
Tests if the configured UDP ports are open.

This test method checks if iptable rules do exist which open
ports as configured in the inventory.

:param value: host
:type value: the link to the testinfra host
:param facts: Retrieved ansible facts
:type facts: types.SimpleNamespace
"""
rules = host.iptables.rules()

testrules = [
"-A ufw-user-input -p udp -m udp --dport 161 -j ACCEPT",
"-A ufw-user-input -p udp -m udp --dport 162 -j ACCEPT",
]

for testrule in testrules:
assert testrule in rules


def test_allow_interfaces(host, facts):
"""
Tests if firewall allows access from NICs configured in the inventory.

This test method checks if iptable rules do exist which allow
all traffic coming in through the NICs configured in the inventory.

:param value: host
:type value: the link to the testinfra host
:param facts: Retrieved ansible facts
:type facts: types.SimpleNamespace
"""
rules = host.iptables.rules()

testrules = [
"-A ufw-user-input -i openvpntap0 -j ACCEPT",
"-A ufw-user-input -i tun0 -j ACCEPT",
]

for testrule in testrules:
assert testrule in rules


def test_ports_acl(host, facts):
"""
Tests if ufw_ports_acl list is configured for the given IP addresses.

This test method checks if iptable rules do exist which open
the whole list of rules defined in ufw_ports_acl which is configured
in the inventory.

:param value: host
:type value: the link to the testinfra host
:param facts: Retrieved ansible facts
:type facts: types.SimpleNamespace
"""
rules = host.iptables.rules()

testrules = [
"-A ufw-user-input -s 10.0.0.0/8 -p tcp -m tcp --dport 22 -j ACCEPT",
"-A ufw-user-input -s 192.168.0.0/16 -p tcp -m tcp --dport 22 -j ACCEPT",
"-A ufw-user-input -s 10.0.0.0/24 -p udp -m udp --dport 5060 -j ACCEPT",
"-A ufw-user-input -s 192.168.0.0/24 -p udp -m udp --dport 5060 -j ACCEPT",
]

for testrule in testrules:
assert testrule in rules
Loading