From feff22b6179e000a5f88df48996ded351b6fc900 Mon Sep 17 00:00:00 2001 From: srw Date: Wed, 21 Aug 2024 01:45:31 +0000 Subject: [PATCH] ansible role for deploying firewalld rules --- .gitignore | 1 + LICENSE | 20 ++++++++++++ README.md | 67 ++++++++++++++++++++++++++++++++++++++ defaults/main.yml | 6 ++++ handlers/main.yml | 12 +++++++ meta/main.yml | 35 ++++++++++++++++++++ tasks/ipsets.yml | 23 +++++++++++++ tasks/main.yml | 53 ++++++++++++++++++++++++++++++ tasks/rules.yml | 82 +++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 299 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 defaults/main.yml create mode 100644 handlers/main.yml create mode 100644 meta/main.yml create mode 100644 tasks/ipsets.yml create mode 100644 tasks/main.yml create mode 100644 tasks/rules.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5addd2c --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2024 Shane Wadleigh + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3fe4b0c --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# ansible-role-firewalld + +This role allows adding and removing most types of firewalld rules from the default zone + + - https://firewalld.org/ + + +## Task Configuration + +``` +- name: Test adding and removeing services etc + hosts: test + become: true + roles: + - role: firewalld + firewalld_ipset_add: + - name: peers + ips: + - 207.188.6.74 + - 207.188.6.12 + - 207.188.6.49 + + firewalld_add: + - name: public + masquerade: false + forward: true + services: + - http + - https + - ssh + ports: + - 53/tcp + - 53/udp + - 67/udp + - 547/udp + forwards: + - port: 443 + proto: udp + to: 51820 + - name: ftl + interfaces: + - lo + ports: + - 4711/tcp + + firewalld_remove: + - name: public + masquerade: true + services: + - http + - https +``` + + +## Deployment and Removal + +Deploy + +``` +ansible-playbook -i hosts site.yml --tags=firewalld --limit=somehost +``` + +Remove + +``` +ansible-playbook -i hosts site.yml --tags=firewalld --extra-vars "firewall_action=remove" --limit=somehost +``` diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..f2be36e --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,6 @@ +--- +firewalld_packages: + - firewalld + +firewalld_service_name: firewalld +firewalld_default_zone: public diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..85ea00e --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,12 @@ +--- + +- name: Start/Enable firewalld + listen: start-firewalld + ansible.builtin.systemd: + name: "{{ firewalld_service_name }}" + state: restarted + enabled: true + +- name: Reload firewalld + listen: reload-firewalld + ansible.builtin.command: "firewall-cmd --reload" diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..97ed34f --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,35 @@ +--- +dependencies: [] + +galaxy_info: + role_name: firewalld + author: srw + description: Ansible role for configuring firewalld rules + company: "Midwestern Mac, LLC" + license: "license (BSD, MIT)" + min_ansible_version: "2.10" + platforms: + - name: Fedora + versions: + - all + - name: Debian + versions: + - buster + - bullseye + - bookworm + - name: Ubuntu + versions: + - bionic + - focal + - jammy + - name: Alpine + version: + - all + - name: ArchLinux + versions: + - all + galaxy_tags: + - server + - system + - firewall + - security diff --git a/tasks/ipsets.yml b/tasks/ipsets.yml new file mode 100644 index 0000000..cae25c3 --- /dev/null +++ b/tasks/ipsets.yml @@ -0,0 +1,23 @@ +--- +- name: Manage ipsets + tags: firewalld + block: + + - name: new ipset + ansible.builtin.shell: firewall-cmd -q --permanent --new-ipset="{{ item.name }}" --type=hash:ip || echo "ipset already exists" + changed_when: true + ignore_errors: true + loop: "{{ firewall_rules }}" + when: + - firewall_action == "add" + - firewall_rules is defined and firewall_rules | length > 0 + + - name: "{{ firewall_action }} ip" + ansible.builtin.command: firewall-cmd --permanent --ipset={{ item.name }}{% for ip in item.ips %} --{{ firewall_action }}-entry={{ ip }}{% endfor %} + changed_when: true + loop: "{{ firewall_rules }}" + when: + - firewall_rules is defined + - item.ips is defined and item.ips | length > 0 + + notify: reload-firewalld diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..d157627 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,53 @@ +--- +- name: Setup and configure firewalld service + tags: firewalld + block: + + - name: Install firewalld packages + ansible.builtin.package: + name: "{{ item }}" + state: present + with_items: "{{ firewalld_packages }}" + when: + - firewalld_packages | length > 0 + - firewalld_add is defined and firewalld_add | length > 0 + - firewalld_ipset_add is defined and firewalld_ipset_add | length > 0 + notify: start-firewalld + + # Add and Remove ipsets + + - name: Removing ipsets + ansible.builtin.include_tasks: ipsets.yml + vars: + firewall_action: "remove" + firewall_rules: "{{ firewalld_ipset_remove }}" + when: + - firewalld_ipset_remove is defined and firewalld_ipset_remove | length > 0 + + - name: Adding ipsets + ansible.builtin.include_tasks: ipsets.yml + vars: + firewall_action: "add" + firewall_rules: "{{ firewalld_ipset_add }}" + when: + - firewalld_ipset_add is defined and firewalld_ipset_add | length > 0 + - firewalld_add is defined and firewalld_add | length > 0 + + # Add and Remove Rules + + - name: Removing interfaces, services, ports, rules + ansible.builtin.include_tasks: rules.yml + vars: + firewall_action: "remove" + firewall_rules: "{{ firewalld_remove }}" + when: + - firewalld_remove is defined and firewalld_remove | length > 0 + + + - name: Adding zones, interfaces, services, ports, rules + ansible.builtin.include_tasks: rules.yml + vars: + firewall_action: "add" + firewall_rules: "{{ firewalld_add }}" + when: + - firewalld_add is defined and firewalld_add | length > 0 \ No newline at end of file diff --git a/tasks/rules.yml b/tasks/rules.yml new file mode 100644 index 0000000..9c46982 --- /dev/null +++ b/tasks/rules.yml @@ -0,0 +1,82 @@ +--- +- name: Create Zones, then apply interfaces and rules + tags: firewalld + block: + + - name: New zones + ansible.builtin.shell: firewall-cmd -q --permanent --new-zone="{{ item.name }}" || echo "zone already exists" + changed_when: true + ignore_errors: true + loop: "{{ firewall_rules }}" + when: + - firewall_action == "add" + - firewall_rules is defined and firewall_rules | length > 0 + + - name: "{{ firewall_action }} interfaces" + ansible.builtin.command: firewall-cmd --permanent --zone={{ item.name }}{% for interface in item.interfaces %} --{{ firewall_action }}-interface={{ interface }}{% endfor %} + changed_when: true + loop: "{{ firewall_rules }}" + when: + - firewall_rules is defined + - item.interfaces is defined and item.interfaces | length > 0 + + - name: "{{ firewall_action }} services" + ansible.builtin.command: firewall-cmd --permanent --zone={{ item.name }}{% for service in item.services %} --{{ firewall_action }}-service={{ service }}{% endfor %} + changed_when: true + loop: "{{ firewall_rules }}" + when: + - firewall_rules is defined + - item.services is defined and item.services | length > 0 + + - name: "{{ firewall_action }} ports" + ansible.builtin.command: firewall-cmd --permanent --zone={{ item.name }}{% for port in item.ports %} --{{ firewall_action }}-port={{ port }}{% endfor %} + changed_when: true + loop: "{{ firewall_rules }}" + when: + - firewall_rules is defined + - item.ports is defined and item.ports | length > 0 + + - name: "{{ firewall_action }} rich rules" + ansible.builtin.command: firewall-cmd --permanent --zone={{ item.name }}{% for rule in item.rules %} --{{ firewall_action }}-rich-rule='{{ rule }}'{% endfor %} + changed_when: true + loop: "{{ firewall_rules }}" + when: + - firewall_rules is defined + - item.rules is defined and item.rules | length > 0 + + - name: "{{ firewall_action }} sources" + ansible.builtin.command: firewall-cmd --permanent --zone={{ item.name }}{% for source in item.sources %} --{{ firewall_action }}-source={{ source }}{% endfor %} + changed_when: true + loop: "{{ firewall_rules }}" + when: + - firewall_rules is defined + - item.sources is defined and item.sources | length > 0 + + - name: "{{ firewall_action }} forwards" + ansible.builtin.command: firewall-cmd --permanent --zone={{ item.name }}{% for forward in item.forwards %} --{{ firewall_action }}-forward-port=port={{ forward.port }}:proto={{ forward.proto | d('tcp')}}:toport={{ forward.to }}:toaddr={{ forward.toaddr | d('') }}{% endfor %} + changed_when: true + loop: "{{ firewall_rules }}" + when: + - firewall_rules is defined + - item.forwards is defined and item.forwards | length > 0 + + - name: Set forwarding + ansible.builtin.command: firewall-cmd --permanent {% if item.forward %}--add-forward{% else %}--remove-forward{% endif %} + changed_when: true + loop: "{{ firewall_rules }}" + when: + - firewall_rules is defined and firewall_rules | length > 0 + - item.forward is defined + + - name: Set masquerading + ansible.builtin.firewalld: + zone: "{{ item.name }}" + masquerade: "{{ item.masquerade | d('false') }}" + permanent: true + state: enabled + loop: "{{ firewall_rules }}" + when: + - firewall_rules is defined and firewall_rules | length > 0 + - item.masquerade is defined + + notify: reload-firewalld