├── tests ├── inventory └── test.yml ├── .gitignore ├── handlers └── main.yml ├── molecule ├── default │ ├── INSTALL.rst │ ├── prepare.yml │ ├── converge.yml │ ├── molecule.yml │ └── verify.yml └── second-change │ ├── molecule.yml │ ├── converge.yml │ └── verify.yml ├── meta └── main.yml ├── .yamllint ├── LICENSE ├── .travis.yml ├── defaults └── main.yml ├── .gitlab-ci.yml ├── README.md └── tasks └── main.yml /tests/inventory: -------------------------------------------------------------------------------- 1 | localhost 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vaultpass 2 | .retry 3 | secret 4 | *.secret 5 | .venv 6 | .vscode 7 | *.tmp 8 | -------------------------------------------------------------------------------- /tests/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | remote_user: root 4 | roles: 5 | - ryandaniels.firewalld 6 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Reload firewalld 3 | #command: firewall-cmd --reload 4 | systemd: 5 | name: firewalld 6 | state: reloaded 7 | when: firewalld_managed|bool and stat_service_firewalld_status.rc == 0 8 | -------------------------------------------------------------------------------- /molecule/default/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: firewalld 4 | author: Ryan Daniels 5 | description: Role to manage firewalld configuration using simple variables. All changes made in "offline" mode to prevent blocking existing services. 6 | license: MIT 7 | min_ansible_version: 2.3 8 | platforms: 9 | - name: EL 10 | versions: 11 | - 7 12 | - 8 13 | - name: Fedora 14 | versions: 15 | - 30 16 | - 31 17 | - name: ArchLinux 18 | versions: 19 | - all 20 | galaxy_tags: 21 | - firewalld 22 | - firewall 23 | - system 24 | - security 25 | - networking 26 | - tcp 27 | - port 28 | 29 | dependencies: [] 30 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | # Based on ansible-lint config 3 | extends: default 4 | 5 | rules: 6 | braces: 7 | max-spaces-inside: 1 8 | level: error 9 | brackets: 10 | max-spaces-inside: 1 11 | level: error 12 | colons: 13 | max-spaces-after: -1 14 | level: error 15 | commas: 16 | max-spaces-after: -1 17 | level: error 18 | comments: disable 19 | comments-indentation: disable 20 | document-start: disable 21 | empty-lines: 22 | max: 3 23 | level: error 24 | hyphens: 25 | level: error 26 | indentation: disable 27 | key-duplicates: enable 28 | line-length: disable 29 | new-line-at-end-of-file: disable 30 | new-lines: 31 | type: unix 32 | trailing-spaces: disable 33 | truthy: disable 34 | -------------------------------------------------------------------------------- /molecule/second-change/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | driver: 5 | name: docker 6 | # lint: | 7 | # set -e 8 | # yamllint . 9 | # ansible-lint 10 | # lint: ansible-lint 11 | # platforms: 12 | # - name: instance 13 | # image: docker.io/pycontribs/centos:7 14 | # pre_build_image: true 15 | platforms: 16 | - name: instance 17 | privileged: true 18 | # image: centos:7 19 | image: ${MOLECULE_DISTRO:-centos:7} 20 | command: ${MOLECULE_DOCKER_COMMAND:-"/sbin/init"} 21 | # command: /sbin/init 22 | tmpfs: 23 | - /run 24 | - /tmp 25 | volumes: 26 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 27 | provisioner: 28 | name: ansible 29 | # playbooks: 30 | # converge: ${MOLECULE_PLAYBOOK:-converge.yml} 31 | verifier: 32 | name: ansible 33 | # directory: ../tests/ 34 | scenario: 35 | test_sequence: 36 | # - create 37 | # - prepare 38 | - converge 39 | - verify 40 | - cleanup 41 | - destroy 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ryan Daniels 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | # python: "2.7" 4 | services: docker 5 | 6 | # Use the new container infrastructure 7 | sudo: false 8 | 9 | # Install ansible 10 | addons: 11 | apt: 12 | packages: 13 | - python-pip 14 | 15 | env: 16 | global: 17 | - ROLE_NAME: firewalld 18 | matrix: 19 | - MOLECULE_DISTRO: centos:7 20 | - MOLECULE_DISTRO: centos:8 21 | # Fedora 29 has problem with ip6tables kernel module 22 | # - MOLECULE_DISTRO: fedora:29 23 | # - MOLECULE_DISTRO: fedora:30 24 | - MOLECULE_DISTRO: fedora:31 25 | # - MOLECULE_DISTRO: archlinux 26 | 27 | install: 28 | # Install ansible 29 | - pip install ansible ansible-lint 'molecule[docker]' 30 | 31 | # Check ansible version 32 | - ansible --version 33 | 34 | # Create ansible.cfg with correct roles_path 35 | - printf '[defaults]\nroles_path=../' >ansible.cfg 36 | 37 | before_script: 38 | # Use actual Ansible Galaxy role name for the project directory. 39 | - cd ../ 40 | - mv ansible-role-$ROLE_NAME ryandaniels.$ROLE_NAME 41 | - cd ryandaniels.$ROLE_NAME 42 | 43 | script: 44 | # Basic role syntax check 45 | - ansible-playbook tests/test.yml -i tests/inventory --syntax-check 46 | # - molecule test 47 | - molecule test --destroy=never && molecule test --scenario-name second-change 48 | # - molecule destroy 49 | 50 | notifications: 51 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ 52 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | debug_enabled_default: false 3 | proxy_env: [] 4 | #Do not change firewalld_reload_hint_result 5 | firewalld_reload_hint_result: false 6 | 7 | firewalld_managed: false 8 | firewalld_show_config: true 9 | firewalld_check_problem_service_managed: true 10 | firewalld_check_problem_service: 11 | - docker.service 12 | firewalld_start: false 13 | firewalld_managed_pkg: true 14 | firewalld_packages: 15 | - firewalld 16 | 17 | firewalld_public_remove_default: [] 18 | # firewalld_public_remove_default: 19 | # - mdns 20 | # - samba-client 21 | 22 | firewalld_internal_remove_default: [] 23 | # firewalld_internal_remove_default: 24 | # - mdns 25 | # - samba-client 26 | 27 | firewalld_zone_source: [] 28 | # firewalld_zone_source: 29 | # - zone: internal 30 | # state: enabled 31 | # # state: disabled 32 | # source: 33 | # - "192.168.22.64/26" 34 | # - "192.168.23.64/26" 35 | # - zone: internal 36 | # # state: enabled 37 | # state: disabled 38 | # source: 39 | # - "192.168.32.64/26" 40 | # - "192.168.33.64/26" 41 | # - zone: public 42 | # # state: enabled 43 | # state: disabled 44 | # source: 45 | # - "192.168.48.192/26" 46 | # - "192.168.49.192/26" 47 | 48 | firewalld_custom_service: [] 49 | # firewalld_custom_service: 50 | # - name: app123-public 51 | # zone: public 52 | # # state: disabled 53 | # state: enabled 54 | # description: app123 firewall rules for public zone 55 | # port_protocol: 56 | # - 5000/tcp 57 | # - name: app123-internal 58 | # zone: internal 59 | # # state: disabled 60 | # state: enabled 61 | # description: app123 firewall rules for internal zone 62 | # port_protocol: 63 | # - 8080/tcp 64 | # - 9000/tcp 65 | # - name: zabbix-agent 66 | # zone: public 67 | # state: enabled 68 | # port_protocol: 69 | # # - 10050/tcp 70 | # - 3333/tcp 71 | # - name: openvpn 72 | # zone: public 73 | # state: enabled 74 | -------------------------------------------------------------------------------- /molecule/default/prepare.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Prepare 3 | hosts: all 4 | vars: 5 | proxy_env: [] 6 | 7 | tasks: 8 | 9 | #Fix for CentOS 7 on OpenVZ virtualization / custom kernel missing modules needed by firewalld 10 | #source: https://www.getpagespeed.com/server-setup/fix-firewalld-in-centos-7 11 | # MODULES_DIR=/lib/modules/$(uname -r) 12 | # mkdir -p ${MODULES_DIR} 13 | # # touch ${MODULES_DIR}/modules.{builtin,order} 14 | # /bin/truncate --size=0 ${MODULES_DIR}/modules.builtin 15 | # /bin/truncate --size=0 ${MODULES_DIR}/modules.order 16 | # for i in /sys/module/*; do echo kernel/${i##**/}.ko; done >> ${MODULES_DIR}/modules.builtin 17 | # depmod -a 18 | 19 | - name: firewalld | Install packages dependencies for OpenVZ / custom kernel workaround 20 | package: 21 | name: kmod 22 | update_cache: yes 23 | state: installed 24 | environment: "{{ proxy_env }}" 25 | when: 26 | - ansible_virtualization_type|lower == "docker" 27 | - ansible_os_family|lower == "redhat" 28 | 29 | - name: firewalld | fix OpenVZ virtualization or custom kernel missing kernel modules 30 | shell: MODULES_DIR=/lib/modules/$(uname -r) && \ 31 | mkdir -p ${MODULES_DIR} && \ 32 | /bin/truncate --size=0 ${MODULES_DIR}/modules.builtin && \ 33 | /bin/truncate --size=0 ${MODULES_DIR}/modules.order && \ 34 | for i in /sys/module/*; do echo kernel/${i##**/}.ko; done >> ${MODULES_DIR}/modules.builtin && \ 35 | depmod -a 36 | register: cmd 37 | # failed_when: false 38 | ignore_errors: true 39 | # changed_when: false 40 | # no_log: True 41 | when: 42 | - ansible_virtualization_type|lower == "docker" 43 | - ansible_os_family|lower == "redhat" 44 | 45 | # - name: debug fix OpenVZ output 46 | # debug: var=cmd 47 | # when: 48 | # # - ansible_os_family == "RedHat" 49 | # # - ansible_distribution_major_version == '7' 50 | # # - firewalld_managed|bool 51 | # - ansible_virtualization_type|lower == "docker" 52 | # - ansible_os_family|lower == "redhat" 53 | # # - debug_enabled_default|bool 54 | -------------------------------------------------------------------------------- /molecule/second-change/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | become: true 5 | 6 | vars: 7 | debug_enabled_default: false 8 | firewalld_managed: true 9 | firewalld_start: true 10 | firewalld_managed_pkg: true 11 | firewalld_packages: 12 | - firewalld 13 | 14 | # firewalld_public_remove_default: [] 15 | firewalld_public_remove_default: 16 | - mdns 17 | - samba-client 18 | 19 | # firewalld_internal_remove_default: [] 20 | firewalld_internal_remove_default: 21 | - mdns 22 | - samba-client 23 | 24 | # firewalld_zone_source: [] 25 | firewalld_zone_source: 26 | - zone: internal 27 | # state: enabled 28 | state: disabled 29 | source: 30 | - "192.168.22.64/26" 31 | - "192.168.23.64/26" 32 | - zone: internal 33 | state: enabled 34 | # state: disabled 35 | source: 36 | - "192.168.32.64/26" 37 | - "192.168.33.64/26" 38 | - zone: public 39 | # state: enabled 40 | state: disabled 41 | source: 42 | - "192.168.48.192/26" 43 | - "192.168.49.192/26" 44 | 45 | # firewalld_custom_service: [] 46 | firewalld_custom_service: 47 | - name: app123-public 48 | zone: public 49 | state: disabled 50 | # state: enabled 51 | description: app123 firewall rules for public zone 52 | port_protocol: 53 | - 5000/tcp 54 | - name: app123-internal 55 | zone: internal 56 | # state: disabled 57 | state: enabled 58 | description: app123 firewall rules for internal zone 59 | port_protocol: 60 | - 8089/tcp 61 | - 8501/udp 62 | - 9000/tcp 63 | - name: zabbix-agent 64 | zone: public 65 | state: enabled 66 | port_protocol: 67 | # - 10050/tcp 68 | - 3333/tcp 69 | - name: openvpn 70 | zone: public 71 | state: enabled 72 | 73 | tasks: 74 | - name: "Include firewalld" 75 | include_role: 76 | name: "ryandaniels.firewalld" 77 | -------------------------------------------------------------------------------- /molecule/default/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | become: true 5 | 6 | vars: 7 | debug_enabled_default: false 8 | firewalld_managed: true 9 | firewalld_show_config: false 10 | firewalld_check_problem_service_managed: true 11 | firewalld_start: true 12 | firewalld_managed_pkg: true 13 | firewalld_packages: 14 | - firewalld 15 | 16 | # firewalld_public_remove_default: [] 17 | firewalld_public_remove_default: 18 | - mdns 19 | - samba-client 20 | 21 | # firewalld_internal_remove_default: [] 22 | firewalld_internal_remove_default: 23 | - mdns 24 | - samba-client 25 | 26 | # firewalld_zone_source: [] 27 | firewalld_zone_source: 28 | - zone: internal 29 | state: enabled 30 | # state: disabled 31 | source: 32 | - "192.168.22.64/26" 33 | - "192.168.23.64/26" 34 | - zone: internal 35 | # state: enabled 36 | state: disabled 37 | source: 38 | - "192.168.32.64/26" 39 | - "192.168.33.64/26" 40 | - zone: public 41 | # state: enabled 42 | state: disabled 43 | source: 44 | - "192.168.48.192/26" 45 | - "192.168.49.192/26" 46 | 47 | # firewalld_custom_service: [] 48 | firewalld_custom_service: 49 | - name: app123-public 50 | zone: public 51 | # state: disabled 52 | state: enabled 53 | description: app123 firewall rules for public zone 54 | port_protocol: 55 | - 5000/tcp 56 | - name: app123-internal 57 | zone: internal 58 | # state: disabled 59 | state: enabled 60 | description: app123 firewall rules for internal zone 61 | port_protocol: 62 | - 8080/tcp 63 | - 8500/udp 64 | - 9000/tcp 65 | - name: zabbix-agent 66 | zone: public 67 | state: enabled 68 | port_protocol: 69 | # - 10050/tcp 70 | - 3333/tcp 71 | - name: openvpn 72 | zone: public 73 | state: enabled 74 | 75 | tasks: 76 | - name: "Include firewalld" 77 | include_role: 78 | name: "ryandaniels.firewalld" 79 | -------------------------------------------------------------------------------- /molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | driver: 5 | name: docker 6 | # lint: | 7 | # set -e 8 | # yamllint . 9 | # ansible-lint 10 | lint: ansible-lint 11 | # platforms: 12 | # - name: instance 13 | # image: docker.io/pycontribs/centos:7 14 | # pre_build_image: true 15 | platforms: 16 | - name: instance 17 | privileged: true 18 | # image: centos:7.6.1810 19 | # image: centos:7.7.1908 20 | # image: centos:7 21 | image: ${MOLECULE_DISTRO:-centos:7} 22 | # command: /sbin/init 23 | # image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest" 24 | command: ${MOLECULE_DOCKER_COMMAND:-"/sbin/init"} 25 | # pre_build_image: true 26 | # Only enable this if variable exists 27 | buildargs: 28 | http_proxy: ${http_proxy-""} 29 | https_proxy: ${https_proxy-""} 30 | tmpfs: 31 | - /run 32 | - /tmp 33 | volumes: 34 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 35 | provisioner: 36 | name: ansible 37 | log: false 38 | # playbooks: 39 | # converge: ${MOLECULE_PLAYBOOK:-converge.yml} 40 | verifier: 41 | name: ansible 42 | # directory: ../tests/ 43 | scenario: 44 | test_sequence: 45 | - dependency 46 | - lint 47 | - cleanup 48 | - destroy 49 | - syntax 50 | - create 51 | - prepare 52 | - converge 53 | - idempotence 54 | - side_effect 55 | - verify 56 | - cleanup 57 | - destroy 58 | # scenario: 59 | # create_sequence: 60 | # - dependency 61 | # - create 62 | # - prepare 63 | # check_sequence: 64 | # - dependency 65 | # - cleanup 66 | # - destroy 67 | # - create 68 | # - prepare 69 | # - converge 70 | # - check 71 | # - destroy 72 | # converge_sequence: 73 | # - dependency 74 | # - create 75 | # - prepare 76 | # - converge 77 | # destroy_sequence: 78 | # - dependency 79 | # - cleanup 80 | # - destroy 81 | # test_sequence: 82 | # - dependency 83 | # - lint 84 | # - cleanup 85 | # - destroy 86 | # - syntax 87 | # - create 88 | # - prepare 89 | # - converge 90 | # - idempotence 91 | # - side_effect 92 | # - verify 93 | # - cleanup 94 | # - destroy 95 | -------------------------------------------------------------------------------- /molecule/second-change/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Verify 3 | hosts: all 4 | tasks: 5 | 6 | - name: Check firewalld running 7 | command: systemctl status firewalld warn=false 8 | # register: stat_service_firewalld_status 9 | # ignore_errors: true 10 | changed_when: false 11 | # no_log: True 12 | # failed_when: not stat_service_firewalld_status.rc == 0 13 | 14 | # - debug: var=stat_service_firewalld_status 15 | 16 | - name: Check source ip removed from internal zone 17 | command: firewall-cmd --permanent --zone=internal --query-source=192.168.22.64/26 18 | register: cmd 19 | # ignore_errors: true 20 | changed_when: false 21 | failed_when: not cmd.rc == 1 22 | 23 | - name: Check source ip added to internal zone 24 | command: firewall-cmd --permanent --zone=internal --query-source=192.168.32.64/26 25 | register: cmd 26 | # ignore_errors: true 27 | changed_when: false 28 | # failed_when: not cmd.rc == 1 29 | 30 | - name: Check service removed 31 | command: firewall-cmd --permanent --zone=public --query-service=app123-public 32 | register: cmd 33 | # ignore_errors: true 34 | changed_when: false 35 | failed_when: not cmd.rc == 1 36 | 37 | #Can't query port since service is gone. 38 | # - name: Check port not added to custom service when disabled 39 | # command: firewall-cmd --permanent --service=app123-public --query-port=5000/tcp 40 | # register: cmd 41 | # ignore_errors: true 42 | # changed_when: false 43 | # failed_when: not cmd.rc == 1 44 | 45 | - name: Check tcp port added to custom service 46 | command: firewall-cmd --permanent --service=app123-internal --query-port=8089/tcp 47 | register: cmd 48 | # ignore_errors: true 49 | changed_when: false 50 | # failed_when: not cmd.rc == 0 51 | 52 | - name: Check port not added to custom service when removed from config 53 | command: firewall-cmd --permanent --service=app123-internal --query-port=8080/tcp 54 | register: cmd 55 | # ignore_errors: true 56 | changed_when: false 57 | failed_when: not cmd.rc == 1 58 | 59 | - name: Check udp port added to custom service 60 | command: firewall-cmd --permanent --service=app123-internal --query-port=8501/udp 61 | register: cmd 62 | # ignore_errors: true 63 | changed_when: false 64 | # failed_when: not cmd.rc == 0 65 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | image: quay.io/ansible/molecule:3.0.2 3 | services: 4 | - name: docker:dind 5 | entrypoint: ["dockerd-entrypoint.sh"] 6 | 7 | stages: 8 | - tests 9 | 10 | variables: 11 | GIT_STRATEGY: clone 12 | # DOCKER_HOST: "tcp://localhost:2375" 13 | DOCKER_TLS_CERTDIR: "" 14 | 15 | .molecule_test: 16 | variables: 17 | DOCKER_HOST: "tcp://docker:2375" 18 | PY_COLORS: 1 19 | tags: 20 | - docker 21 | before_script: 22 | - export ROLE_NAME=firewalld 23 | # - apk update && apk add --no-cache py3-pip 24 | - python3 -m pip install ansible-lint==4.2.0 25 | - docker -v 26 | - python3 --version 27 | - ansible --version 28 | - molecule --version 29 | - ansible-lint --version 30 | # Use actual Ansible Galaxy role name for the project directory. 31 | - cd ../ 32 | # - mv ansible-role-$ROLE_NAME ryandaniels.$ROLE_NAME 33 | # - cd ryandaniels.$ROLE_NAME 34 | - ln -s ansible-role-$ROLE_NAME ryandaniels.$ROLE_NAME 35 | - cd ryandaniels.$ROLE_NAME 36 | script: 37 | - molecule test --destroy=never && molecule test --scenario-name second-change 38 | # - molecule destroy 39 | # - sleep 3600 40 | # only: 41 | # refs: 42 | # - branches 43 | # - tags 44 | # - merge_requests 45 | # except: 46 | # changes: 47 | # - "**/*.{md,rst,gitignore}" 48 | # - "meta/*" 49 | 50 | molecule-centos7: 51 | stage: tests 52 | extends: .molecule_test 53 | variables: 54 | MOLECULE_DISTRO: "centos:7" 55 | 56 | molecule-centos8: 57 | stage: tests 58 | extends: .molecule_test 59 | variables: 60 | MOLECULE_DISTRO: "centos:8" 61 | 62 | molecule-fedora31: 63 | stage: tests 64 | extends: .molecule_test 65 | variables: 66 | MOLECULE_DISTRO: "fedora:31" 67 | 68 | #much slower but works 69 | # image: docker:git 70 | # services: 71 | # - docker:dind 72 | 73 | # stages: 74 | # - tests 75 | 76 | # before_script: 77 | # - export ROLE_NAME=firewalld 78 | # - apk update && apk add --no-cache docker 79 | # python3-dev py3-pip docker gcc git curl build-base 80 | # autoconf automake py3-cryptography linux-headers 81 | # musl-dev libffi-dev openssl-dev openssh 82 | # - python3 -m pip install ansible molecule docker ansible-lint 83 | # - docker -v 84 | # - python3 --version 85 | # - ansible --version 86 | # - molecule --version 87 | # - ansible-lint --version 88 | # # Use actual Ansible Galaxy role name for the project directory. 89 | # - cd ../ 90 | # # - mv ansible-role-$ROLE_NAME ryandaniels.$ROLE_NAME 91 | # # - cd ryandaniels.$ROLE_NAME 92 | # - ln -s ansible-role-$ROLE_NAME ryandaniels.$ROLE_NAME 93 | # - cd ryandaniels.$ROLE_NAME 94 | 95 | # molecule-centos7: 96 | # stage: tests 97 | # script: 98 | # - export MOLECULE_DISTRO="centos:7" 99 | # - molecule test --destroy=never && molecule test --scenario-name second-change 100 | # - molecule destroy 101 | 102 | # molecule-fedora31: 103 | # stage: tests 104 | # script: 105 | # - export MOLECULE_DISTRO="fedora:31" 106 | # - molecule test --destroy=never && molecule test --scenario-name second-change 107 | # - molecule destroy 108 | -------------------------------------------------------------------------------- /molecule/default/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Verify 3 | hosts: all 4 | tasks: 5 | 6 | # - name: show setup 7 | # setup: 8 | # gather_subset: 9 | # - 'all' 10 | # register: stat_setup 11 | 12 | # - name: debug stat_setup 13 | # debug: var=stat_setup 14 | 15 | - name: Check firewalld running 16 | command: systemctl status firewalld warn=false 17 | # register: stat_service_firewalld_status 18 | # ignore_errors: true 19 | changed_when: false 20 | # no_log: True 21 | # failed_when: not stat_service_firewalld_status.rc == 0 22 | 23 | # - name: debug stat_service_firewalld_status 24 | # debug: var=stat_service_firewalld_status 25 | 26 | - name: Check firewalld can reload 27 | command: firewall-cmd --reload 28 | register: stat_service_firewalld_reload 29 | # ignore_errors: true 30 | changed_when: false 31 | # no_log: True 32 | # failed_when: not stat_service_firewalld_reload.rc == 0 33 | 34 | - name: Check source ip added to internal zone 35 | command: firewall-cmd --permanent --zone=internal --query-source=192.168.22.64/26 36 | register: cmd 37 | # ignore_errors: true 38 | changed_when: false 39 | # failed_when: not cmd.rc == 0 40 | 41 | - name: Check source ip not added to internal zone 42 | command: firewall-cmd --permanent --zone=internal --query-source=192.168.32.64/26 43 | register: cmd 44 | # ignore_errors: true 45 | changed_when: false 46 | failed_when: not cmd.rc == 1 47 | 48 | - name: Check service created and in public zone 49 | command: firewall-cmd --permanent --zone=public --query-service=app123-public 50 | register: cmd 51 | # ignore_errors: true 52 | changed_when: false 53 | # failed_when: not cmd.rc == 0 54 | 55 | - name: Check service created and not in internal zone 56 | command: firewall-cmd --permanent --zone=internal --query-service=app123-public 57 | register: cmd 58 | # ignore_errors: true 59 | changed_when: false 60 | failed_when: not cmd.rc == 1 61 | 62 | - name: Check tcp port added to custom service 63 | command: firewall-cmd --permanent --service=app123-public --query-port=5000/tcp 64 | register: cmd 65 | # ignore_errors: true 66 | changed_when: false 67 | # failed_when: not cmd.rc == 0 68 | 69 | # - name: debug Check port added to custom service cmd 70 | # debug: var=cmd 71 | 72 | - name: Check udp port added to custom service 73 | command: firewall-cmd --permanent --service=app123-internal --query-port=8500/udp 74 | register: cmd 75 | # ignore_errors: true 76 | changed_when: false 77 | # failed_when: not cmd.rc == 0 78 | 79 | - name: Check custom port added to built-in service 80 | command: firewall-cmd --permanent --service=zabbix-agent --query-port=3333/tcp 81 | register: cmd 82 | # ignore_errors: true 83 | changed_when: false 84 | # failed_when: not cmd.rc == 0 85 | 86 | - name: Check default port not added to built-in service 87 | command: firewall-cmd --permanent --service=zabbix-agent --query-port=10050/tcp 88 | register: cmd 89 | # ignore_errors: true 90 | changed_when: false 91 | failed_when: not cmd.rc == 1 92 | 93 | # # Check firewalld running 94 | # - systemctl status firewalld 95 | # # Check source ip in internal zone 96 | # - sudo firewall-cmd --permanent --zone=internal --query-source=192.168.22.64/26 97 | # # Check source ip not in internal zone 98 | # - sudo firewall-cmd --permanent --zone=internal --query-source=192.168.32.64/26 || echo "success, not found" 99 | # # Check service created and in public zone 100 | # - sudo firewall-cmd --permanent --zone=public --query-service=app123-public 101 | # # Check service created and not in internal zone 102 | # - sudo firewall-cmd --permanent --zone=internal --query-service=app123-public || echo "success, not found" 103 | 104 | # # Check port added to custom service 105 | # - sudo firewall-cmd --permanent --service=app123-public --query-port=5000/tcp 106 | 107 | # # Check custom port added to built-in service 108 | # - sudo firewall-cmd --permanent --service=zabbix-agent --query-port=3333/tcp 109 | # # Check default port not added to built-in service 110 | # - sudo firewall-cmd --permanent --service=zabbix-agent --query-port=10050/tcp || echo "success, not found" 111 | 112 | # # Run the role/playbook again but make change 113 | # - "ansible-playbook -i tests/inventory tests/test-change.yml --connection=local --become" 114 | 115 | # # Check port not added to custom service when disabled 116 | # - sudo firewall-cmd --permanent --service=app123-public --query-port=5000/tcp || echo "success, not found" 117 | 118 | # # Check port added to custom service 119 | # - sudo firewall-cmd --permanent --service=app123-internal --query-port=8089/tcp 120 | # # Check port not added to custom service when removed from config 121 | # - sudo firewall-cmd --permanent --service=app123-internal --query-port=8080/tcp || echo "success, not found" 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Role: firewalld 2 | 3 | Add local firewall rules on server via firewalld. 4 | Why another Ansible role to manage firewalld? The role does everything in "offline" mode. Even creating a new service works offline. 5 | So there should be no issues when firewalld starts, and blocks EVERYTHING by default! (Make sure you test in non-production first, I cannot make any guarantees) 6 | This supports adding custom firewalld "services" into zones with custom ports. Also can add or remove ports for built-in services provided by firewalld. 7 | Removes unwanted default services from public/internal zone. 8 | 9 | Zones: Add IP ranges to Zones. To remove, change state to `disabled`. If only one IP range needs to be disabled, create a new zone entry for just that IP range. 10 | Services: `disable` a service will remove it from that zone as specified in the variables. Don't just delete the config to remove it! 11 | Ports: To remove a port, delete it from the config (under port_protocol). 12 | 13 | Since VMs could have different interfaces (eth0/eth1 etc.), interfaces aren't managed. 14 | 15 | Be careful, this will remove and add firewalld rules on the OS. Use with caution. 16 | 17 | firewalld manual: 18 | 19 | **Note**: Docker and firewalld do not get along. This role has a check enabled to fail this role if the docker service is running or enabled. 20 | For more information about firewalld and Docker: 21 | 22 | 23 | 24 | 25 | ## Testing 26 | 27 | Molecule is used for testing, and all features are tested. Changes are then made a second time and re-tested to be sure everything works. 28 | 29 | ## Distros tested 30 | 31 | * CentOS: 7.6, 7.7, 8.1 32 | * Fedora 30, 31 33 | * Arch Linux (firewalld version 0.8.1) - But who would run a bunch of Arch servers.. 34 | 35 | ## Dependencies 36 | 37 | * firewalld 38 | 39 | Tested with version 0.6.3 (Latest available in CentOS 7) 40 | Tested with version 0.6.6 (Latest available in Fedora 30) 41 | Tested with version 0.7.0 (Latest available in CentOS 8) 42 | Tested with version 0.7.3 (Latest available in Fedora 31) 43 | Tested with version 0.8.1 (Latest available in Arch Linux) 44 | 45 | ## Default Settings 46 | 47 | * Enable debug 48 | 49 | ```yaml 50 | debug_enabled_default: false 51 | ``` 52 | 53 | * Proxy (Needed when installing required packages if behind a proxy) 54 | 55 | ```yaml 56 | proxy_env: [] 57 | ``` 58 | 59 | * Role disabled by default. Change to true in group_vars or playbook etc 60 | 61 | ```yaml 62 | firewalld_managed: false 63 | ``` 64 | 65 | * Check if (Docker) service is running or enabled, and fail the role 66 | 67 | ```yaml 68 | firewalld_check_problem_service_managed: true 69 | ``` 70 | 71 | * Services to check, and fail the role 72 | 73 | ```yaml 74 | firewalld_check_problem_service: 75 | - docker.service 76 | ``` 77 | 78 | * Show configuration from variables 79 | 80 | ```yaml 81 | firewalld_show_config: false 82 | ``` 83 | 84 | * Start firewalld service 85 | 86 | ```yaml 87 | firewalld_start: false 88 | ``` 89 | 90 | * Install firewalld package 91 | 92 | ```yaml 93 | firewalld_managed_pkg: true 94 | ``` 95 | 96 | ## User Settings 97 | 98 | * Remove unwanted default services from public zone 99 | 100 | ```yaml 101 | firewalld_public_remove_default: 102 | - mdns 103 | - samba-client 104 | ``` 105 | 106 | * Remove unwanted default services from internal zone 107 | 108 | ```yaml 109 | firewalld_internal_remove_default: 110 | - mdns 111 | - samba-client 112 | ``` 113 | 114 | * Zone Config 115 | 116 | Full list of firewalld predefined zones: 117 | 118 | ```yaml 119 | firewalld_zone_source: 120 | - zone: name of predefined zone (ex. internal|public) (Required) 121 | state: enabled|disabled (Required) 122 | source: 123 | - "IP/Subnet" (Required) 124 | ``` 125 | 126 | * Service and Port Config 127 | 128 | ```yaml 129 | firewalld_custom_service: 130 | - name: service name (Required) 131 | zone: public|internal etc (See zone list above) (Required) 132 | state: enabled (Required) 133 | description: Description of service (Optional) 134 | port_protocol: (Required, unless a built-in service except when changing a default port for built-in service) 135 | - port/protocol (Required, unless a built-in service) 136 | ``` 137 | 138 | See example for more details. 139 | Get list of build-in services: 140 | 141 | ```bash 142 | firewall-offline-cmd --get-services 143 | ``` 144 | 145 | ## Example config file (inventories/dev-env/group_vars/all.yml) 146 | 147 | From the example below: 148 | IP ranges will be added/removed from a zone: 149 | 150 | * `192.168.22.64/26` and `192.168.23.64/26` will be added to the zone `internal` 151 | * `192.168.32.64/26` and `192.168.33.64/26` will be removed from the zone `internal` 152 | 153 | Custom services will be created with port(s) specified, and added to a zone: 154 | 155 | * `app123-public` service is created with port/protocol `5000/tcp`, and added to zone `public`. 156 | * `app123-internal` service is created with ports/protocol `8080/tcp`, `9000/tcp`, and added to zone `internal`. 157 | * `zabbix-agent` service (which is a built-in service in firewalld) is not using the default port (10050) since it's not in the config, `10050/tcp` is removed. Instead using port/protocol `3333/tcp`, and added to zone `public`. (Note: The port doesn't need to be commented out). 158 | * `openvpn` service (which is a built-in service in firewalld) is using the default port/protocol, and added to zone `public`. Since this service is built-in, you don't need to specify the port. But to be safe, you should still specify it. 159 | 160 | ```yaml 161 | --- 162 | firewalld_zone_source: 163 | - zone: internal 164 | state: enabled 165 | source: 166 | - "192.168.22.64/26" 167 | - "192.168.23.64/26" 168 | - zone: internal 169 | state: disabled 170 | source: 171 | - "192.168.32.64/26" 172 | - "192.168.33.64/26" 173 | 174 | firewalld_custom_service: 175 | - name: app123-public 176 | zone: public 177 | # state: disabled 178 | state: enabled 179 | description: app123 firewall rules for public zone 180 | port_protocol: 181 | - 5000/tcp 182 | - name: app123-internal 183 | zone: internal 184 | # state: disabled 185 | state: enabled 186 | description: app123 firewall rules for internal zone 187 | port_protocol: 188 | - 8080/tcp 189 | - 9000/tcp 190 | - name: zabbix-agent 191 | zone: public 192 | # state: disabled 193 | state: enabled 194 | port_protocol: 195 | # - 10050/tcp 196 | - 3333/tcp 197 | - name: openvpn 198 | zone: public 199 | state: enabled 200 | ``` 201 | 202 | ## Example Playbook firewalld.yml 203 | 204 | ```yaml 205 | --- 206 | - hosts: '{{ inventory }}' 207 | become: yes 208 | vars: 209 | # Use this role #RTFM 210 | # firewalld_managed: true 211 | roles: 212 | - firewalld 213 | ``` 214 | 215 | ## Usage 216 | 217 | By default no tasks will run unless you set `firewalld_managed=true`. This is by design to prevent accidents by people who don't RTFM. 218 | 219 | ```bash 220 | ansible-playbook firewalld.yml --extra-vars "inventory=centos7 firewalld_managed=true" -i hosts-dev 221 | ``` 222 | 223 | Skip installing packages (if known already there - speeds up task) 224 | 225 | ```bash 226 | ansible-playbook firewalld.yml --extra-vars "inventory=centos7 firewalld_managed=true" -i hosts --skip-tags=firewalld_pkg_install 227 | ``` 228 | 229 | Show more verbose output (debug info) 230 | 231 | ```bash 232 | ansible-playbook firewalld.yml --extra-vars "inventory=centos7 firewalld_managed=true debug_enabled_default=true" -i hosts-dev 233 | ``` 234 | 235 | Start firewalld service at end of role 236 | 237 | ```bash 238 | ansible-playbook firewalld.yml --extra-vars "inventory=centos7 firewalld_managed=true firewalld_start=true" -i hosts-dev 239 | ``` 240 | 241 | Only show configuration (from variables) 242 | 243 | ```bash 244 | ansible-playbook firewalld.yml --extra-vars "inventory=centos7 firewalld_managed=true firewalld_show_config=true" -i hosts --tags "firewalld_show_config" 245 | ``` 246 | 247 | ## firewalld Command Reference 248 | 249 | More commands can be found in firewalld documentation: 250 | 251 | Add IPs to a Zone: 252 | 253 | ```bash 254 | firewall-offline-cmd --zone=public --list-all 255 | 256 | firewall-offline-cmd --zone=internal --add-source=192.168.22.64/26 257 | firewall-offline-cmd --zone=internal --add-source=192.168.23.64/26 258 | ``` 259 | 260 | Add custom service to public zone: 261 | 262 | ```bash 263 | firewall-offline-cmd --new-service=app123-public 264 | firewall-offline-cmd --service=app123-public --set-short=app123-public 265 | firewall-offline-cmd --service=app123-public --set-description='app123 fw rules for public zone' 266 | firewall-offline-cmd --service=app123-public --add-port=5000/tcp 267 | firewall-offline-cmd --zone=public --add-service=app123-public 268 | ``` 269 | 270 | Add custom service to internal zone: 271 | 272 | ```bash 273 | firewall-offline-cmd --new-service=app123-internal 274 | firewall-offline-cmd --service=app123-internal --set-short=app123-internal 275 | firewall-offline-cmd --service=app123-internal --set-description='app123 fw rules for internal zone' 276 | firewall-offline-cmd --service=app123-internal --add-port=8080/tcp 277 | firewall-offline-cmd --service=app123-internal --add-port=9000/tcp 278 | firewall-offline-cmd --zone=internal --add-service=app123-internal 279 | 280 | firewall-offline-cmd --zone=internal --list-all 281 | ``` 282 | 283 | Get list of build-in services: 284 | 285 | ```bash 286 | firewall-offline-cmd --get-services 287 | ``` 288 | 289 | Misc useful commands: 290 | 291 | ```bash 292 | firewall-cmd --state 293 | firewall-cmd --get-active-zones 294 | 295 | firewall-offline-cmd --zone=public --list-all 296 | firewall-offline-cmd --zone=internal --list-all 297 | 298 | firewall-offline-cmd --zone=public --list-services 299 | firewall-offline-cmd --zone=internal --list-services 300 | 301 | firewall-offline-cmd --info-service=app123-public 302 | firewall-offline-cmd --info-service=app123-internal 303 | 304 | firewall-cmd --reload 305 | ``` 306 | 307 | ## iptables Command Reference 308 | 309 | List iptables that are active: 310 | 311 | ```bash 312 | iptables -nL 313 | ``` 314 | 315 | ## nftables Command Reference 316 | 317 | List nftables that are active: 318 | 319 | ```bash 320 | nft list tables 321 | nft list ruleset 322 | nft list table inet firewalld 323 | nft list chain inet firewalld filter_IN_public_allow 324 | ``` 325 | 326 | ## TODO 327 | 328 | * [x] Get working with firewalld started or stopped 329 | * [x] Confirm reload everywhere needed: "notify: Reload firewalld" 330 | * [ ] Add more tags to tasks 331 | * [x] Test this actually works if firewalld service is running and doesn't block traffic to running app 332 | * [x] Build travis tests for many scenarios 333 | * [ ] Improve/shorten changing/removing a port 334 | * [ ] --diff doesn't show much since using many commands. Show what's going to happen and add pause when is debug enabled? 335 | 336 | ## Author 337 | 338 | Ryan Daniels 339 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # - name: show setup 3 | # setup: 4 | # gather_subset: 5 | # - 'all' 6 | # register: stat_setup 7 | 8 | # - name: debug stat_setup 9 | # debug: var=stat_setup 10 | # when: 11 | # # - ansible_os_family == "RedHat" 12 | # # - ansible_distribution_major_version == '7' 13 | # - firewalld_managed|bool 14 | # # - debug_enabled_default|bool 15 | # tags: 16 | # - firewalld 17 | 18 | - block: 19 | # - name: debug groups 20 | # debug: var=groups 21 | - name: firewalld | Show firewalld_zone_source 22 | debug: var=firewalld_zone_source 23 | - name: firewalld | Show firewalld_custom_service 24 | debug: var=firewalld_custom_service 25 | - name: pause 26 | pause: 27 | seconds: 5 28 | when: 29 | # - ansible_os_family == "RedHat" 30 | # - ansible_distribution_major_version == '7' 31 | - firewalld_managed|bool 32 | # - debug_enabled_default|bool 33 | - firewalld_show_config|bool 34 | tags: 35 | - firewalld 36 | - firewalld_show_config 37 | 38 | - name: firewalld | Check for problem services 39 | command: systemctl show -p UnitFileState -p SubState {{ item }} warn=false 40 | register: stat_service_bad 41 | # failed_when: ("SubState=running" in stat_service_bad.stdout) or ("UnitFileState=enabled" in stat_service_bad.stdout) 42 | # ignore_errors: true 43 | changed_when: false 44 | # no_log: true 45 | # - debug: var=stat_service_bad.stdout_lines 46 | with_items: 47 | - "{{ firewalld_check_problem_service }}" 48 | when: 49 | - firewalld_managed|bool 50 | - firewalld_check_problem_service_managed|bool 51 | tags: 52 | - firewalld 53 | - firewalld_check_service 54 | 55 | # - debug: var=stat_service_bad.results 56 | # when: 57 | # - firewalld_managed|bool 58 | # - firewalld_check_problem_service_managed|bool 59 | # tags: 60 | # - firewalld 61 | # - firewalld_check_service 62 | 63 | - name: firewalld | Fail if specified problem service is running 64 | fail: 65 | msg: "{{ item.item }} service is running or enabled, and firewalld can cause a problem with that service" 66 | with_items: "{{ stat_service_bad.results }}" 67 | when: 68 | - firewalld_managed|bool 69 | - firewalld_check_problem_service_managed|bool 70 | - ("SubState=running" in item.stdout_lines) or ("UnitFileState=enabled" in item.stdout_lines) 71 | # loop_control: 72 | # label: "Service {{ item }} is running or enabled. It can have a problem with firewalld" 73 | tags: 74 | - firewalld 75 | - firewalld_check_service 76 | 77 | - name: Ensure required packages are installed 78 | package: 79 | name: "{{ firewalld_packages|default([]) }}" 80 | update_cache: yes 81 | state: present 82 | environment: "{{ proxy_env }}" 83 | when: 84 | # - ansible_os_family == "RedHat" 85 | # - ansible_distribution_major_version == '7' 86 | - firewalld_managed|bool 87 | - firewalld_managed_pkg|bool 88 | tags: 89 | - firewalld 90 | - firewalld_pkg_install 91 | 92 | - name: firewalld | check version 93 | command: firewall-offline-cmd -V warn=false 94 | register: stat_service_firewalld_version 95 | failed_when: false 96 | ignore_errors: true 97 | changed_when: false 98 | # no_log: True 99 | when: 100 | # - ansible_os_family == "RedHat" 101 | # - ansible_distribution_major_version == '7' 102 | - firewalld_managed|bool 103 | # - debug_enabled_default|bool 104 | tags: 105 | - firewalld 106 | 107 | - name: debug stat_service_firewalld_version 108 | debug: var=stat_service_firewalld_version.stdout_lines 109 | when: 110 | # - ansible_os_family == "RedHat" 111 | # - ansible_distribution_major_version == '7' 112 | - firewalld_managed|bool 113 | # - debug_enabled_default|bool 114 | tags: 115 | - firewalld 116 | 117 | - name: firewalld | check if running 118 | command: systemctl status firewalld warn=false 119 | register: stat_service_firewalld_status 120 | failed_when: false 121 | ignore_errors: true 122 | changed_when: false 123 | no_log: True 124 | when: 125 | # - ansible_os_family == "RedHat" 126 | # - ansible_distribution_major_version == '7' 127 | - firewalld_managed|bool 128 | tags: 129 | - firewalld 130 | 131 | - name: debug stat_service_firewalld_status 132 | debug: var=stat_service_firewalld_status.stdout_lines 133 | when: 134 | # - ansible_os_family == "RedHat" 135 | # - ansible_distribution_major_version == '7' 136 | - firewalld_managed|bool 137 | - debug_enabled_default|bool 138 | tags: 139 | - firewalld 140 | 141 | - name: firewalld | Config zone source IP 142 | firewalld: 143 | zone: "{{ item.0.zone }}" 144 | source: "{{ item.1 }}" 145 | state: "{{ item.0.state|default('enabled') }}" 146 | permanent: yes 147 | offline: yes 148 | notify: Reload firewalld 149 | with_subelements: 150 | - "{{ firewalld_zone_source|default({}) }}" 151 | - source 152 | when: 153 | # - ansible_os_family == "RedHat" 154 | # - ansible_distribution_major_version == '7' 155 | - firewalld_managed|bool 156 | # loop_control: 157 | # label: "Zone: {{ item.0.zone }} Source: {{ item.1 }}" 158 | tags: 159 | - firewalld 160 | 161 | #get active services 162 | #when item not in service list, firewalld reload is needed to see item in service list so can add to zone 163 | - name: firewalld | Get active services to determine if reload needed 164 | command: firewall-offline-cmd --get-services warn=false 165 | register: stat_service_firewalld_services 166 | failed_when: false 167 | ignore_errors: true 168 | changed_when: false 169 | no_log: true 170 | when: 171 | # - ansible_os_family == "RedHat" 172 | # - ansible_distribution_major_version == '7' 173 | - firewalld_managed|bool 174 | tags: 175 | - firewalld 176 | 177 | - name: debug stat_service_firewalld_services.stdout.split() 178 | debug: var=stat_service_firewalld_services.stdout.split() 179 | when: 180 | # - ansible_os_family == "RedHat" 181 | # - ansible_distribution_major_version == '7' 182 | - firewalld_managed|bool 183 | - debug_enabled_default|bool 184 | - stat_service_firewalld_status.rc == 0 185 | tags: 186 | - firewalld 187 | 188 | #Built-in services will fail to be removed fully. But they are removed from the zone below (Add/Remove service in zone) 189 | #Use this instead? firewall-offline-cmd --zone=public --remove-service-from-zone=zabbix-agent 190 | #But then custom services aren't fully deleted.. 191 | - name: firewalld | Remove custom service - failure expected if firewalld built-in service 192 | command: "firewall-offline-cmd --delete-service={{ item.name }}" 193 | ignore_errors: true 194 | notify: Reload firewalld 195 | with_items: 196 | - "{{ firewalld_custom_service|default({}) }}" 197 | when: 198 | # - ansible_os_family == "RedHat" 199 | # - ansible_distribution_major_version == '7' 200 | - firewalld_managed|bool 201 | - item.state == 'disabled' 202 | - 'item.name in stat_service_firewalld_services.stdout.split()' 203 | loop_control: 204 | label: "Removed service name: {{ item.name }}" 205 | tags: 206 | - firewalld 207 | - firewalld_remove_service 208 | 209 | #If only block can use loops.. 210 | # - block: 211 | - name: firewalld | Create custom service name 212 | command: "firewall-offline-cmd --new-service={{ item.name }}" 213 | # firewall-offline-cmd --service={{ item.name }} --set-short={{ item.name }} && \ 214 | # firewall-offline-cmd --service={{ item.name }} --set-description='{{ item.description }}' && \ 215 | # firewall-offline-cmd --service={{ item.name }} --add-port={{ item.port_protocol }} && \ 216 | # firewall-offline-cmd --zone={{ item.zone }} --add-service={{ item.name }}" 217 | with_items: 218 | - "{{ firewalld_custom_service|default({}) }}" 219 | when: 220 | # - ansible_os_family == "RedHat" 221 | # - ansible_distribution_major_version == '7' 222 | - firewalld_managed|bool 223 | - item.state == 'enabled' 224 | - 'item.name not in stat_service_firewalld_services.stdout.split()' 225 | loop_control: 226 | label: "Created service name: {{ item.name }}" 227 | tags: 228 | - firewalld 229 | - firewalld_create_service 230 | 231 | - name: firewalld | Get custom service set-short 232 | command: "firewall-offline-cmd --service={{ item.name }} --get-short" 233 | register: stat_firewalld_service_get_short 234 | failed_when: false 235 | ignore_errors: true 236 | changed_when: false 237 | # no_log: true 238 | with_items: "{{ firewalld_custom_service|default({}) }}" 239 | when: 240 | # - ansible_os_family == "RedHat" 241 | # - ansible_distribution_major_version == '7' 242 | - firewalld_managed|bool 243 | # - stat_service_firewalld_status.rc == 0 244 | loop_control: 245 | label: "{{ item.name }} - found short name: {{ stat_firewalld_service_get_short.stdout|d() }}" 246 | tags: 247 | - firewalld 248 | 249 | # - name: debug stat_firewalld_service_get_short 250 | # debug: var=stat_firewalld_service_get_short 251 | # # with_items: "{{ stat_firewalld_service_get_short.results }}" 252 | # when: 253 | # - debug_enabled_default|bool 254 | # - firewalld_managed|bool 255 | # # - stat_service_firewalld_status.rc == 0 256 | # tags: 257 | # - firewalld 258 | 259 | - name: firewalld | Set custom service set-short 260 | command: "firewall-offline-cmd --service={{ item.item.name }} --set-short={{ item.item.name }}" 261 | with_items: 262 | # - "{{ firewalld_custom_service|default({}) }}" 263 | - "{{ stat_firewalld_service_get_short.results }}" 264 | when: 265 | # - ansible_os_family == "RedHat" 266 | # - ansible_distribution_major_version == '7' 267 | - firewalld_managed|bool 268 | - item.item.state == 'enabled' 269 | - 'item.stdout != item.item.name' 270 | loop_control: 271 | label: "{{ item.item.name }} - set short name: {{ item.item.name }}" 272 | tags: 273 | - firewalld 274 | - firewalld_create_service 275 | 276 | - name: firewalld | Get custom service description 277 | command: "firewall-offline-cmd --service={{ item.name }} --get-description" 278 | register: stat_firewalld_service_get_description 279 | failed_when: false 280 | ignore_errors: true 281 | changed_when: false 282 | with_items: "{{ firewalld_custom_service|default({}) }}" 283 | when: 284 | # - ansible_os_family == "RedHat" 285 | # - ansible_distribution_major_version == '7' 286 | - firewalld_managed|bool 287 | loop_control: 288 | label: "{{ item.name }} - found description: {{ stat_firewalld_service_get_description.stdout|d() }}" 289 | tags: 290 | - firewalld 291 | 292 | # - name: debug stat_firewalld_service_get_description 293 | # debug: var=stat_firewalld_service_get_description 294 | # # with_items: "{{ stat_firewalld_service_get_description.results }}" 295 | # when: 296 | # - debug_enabled_default|bool 297 | # - firewalld_managed|bool 298 | # # - stat_service_firewalld_status.rc == 0 299 | # tags: 300 | # - firewalld 301 | 302 | - name: firewalld | Set custom service description 303 | command: "firewall-offline-cmd --service={{ item.item.name }} --set-description='{{ item.item.description }}'" 304 | with_items: 305 | - "{{ stat_firewalld_service_get_description.results }}" 306 | when: 307 | # - ansible_os_family == "RedHat" 308 | # - ansible_distribution_major_version == '7' 309 | - firewalld_managed|bool 310 | - item.item.state == 'enabled' 311 | - item.item.description is defined 312 | - item.stdout != item.item.description 313 | loop_control: 314 | label: "{{ item.item.name }} - set description: {{ item.item.description|default({}) }}" 315 | tags: 316 | - firewalld 317 | - firewalld_create_service 318 | 319 | #DONE: how to 'change' a port that's defined?? Can only 'disable' entire service. 320 | # Can add new ports. But not remove existing. 321 | #firewall-offline-cmd --service=zabbix-agent --get-ports 322 | #Remove ports in output of above command that aren't in variable provided. 323 | #Can't because built-in services I don't have ports for! Means all ports need to be defined! 324 | #DONE: add strict mode so this can be disabled (by default?). Not needed. Just dont remove ports if port_protocol is undefined. 325 | #TODO: Seems like round-about way to do this. Shorten somehow? 326 | 327 | #Remove if port is not defined in vars 328 | - name: firewalld | Get custom service ports in firewalld 329 | command: "firewall-offline-cmd --service={{ item.name }} --get-ports" 330 | register: stat_firewalld_service_get_service_port_list 331 | failed_when: false 332 | # ignore_errors: true 333 | changed_when: false 334 | with_items: 335 | - "{{ firewalld_custom_service|default({}) }}" 336 | when: 337 | # - ansible_os_family == "RedHat" 338 | # - ansible_distribution_major_version == '7' 339 | - firewalld_managed|bool 340 | # - item.state == 'enabled' 341 | loop_control: 342 | label: "{{ item.name }} - found ports: {{ stat_firewalld_service_get_service_port_list.stdout|d() }}" 343 | tags: 344 | - firewalld 345 | 346 | # - name: debug stat_firewalld_service_get_service_port_list 347 | # debug: var=stat_firewalld_service_get_service_port_list 348 | # when: 349 | # - debug_enabled_default|bool 350 | # - firewalld_managed|bool 351 | # tags: 352 | # - firewalld 353 | 354 | # - name: firewalld | debug stat_firewalld_service_get_service_port_list.results 355 | # debug: msg="{{ item.item.name }}, {{ item.stdout }}" #, item.rc={{ item.rc }}, item.item_debug={{ item.item|type_debug }}" 356 | # with_items: "{{ stat_firewalld_service_get_service_port_list.results }}" 357 | # when: 358 | # - ansible_os_family == "RedHat" 359 | # - ansible_distribution_major_version == '7' 360 | # - firewalld_managed|bool 361 | # - debug_enabled_default|bool 362 | # loop_control: 363 | # label: "" 364 | # tags: 365 | # - firewalld 366 | 367 | - name: firewalld | Set variable firewalld_service_port_list 368 | set_fact: 369 | firewalld_service_port_list: "{{ firewalld_service_port_list|default([]) + [{'name': item.item.name , 'port_protocol': item.item.port_protocol , 'port_stdout': item.stdout.split(' ')} ] }}" # noqa 204 370 | when: 371 | # - ansible_os_family == "RedHat" 372 | # - ansible_distribution_major_version == '7' 373 | - firewalld_managed|bool 374 | - item.item.port_protocol is defined #prevents removing ports of built-in firewalld services (if port_protocol is empty) 375 | # - item.rc != 0 376 | loop: "{{ stat_firewalld_service_get_service_port_list.results|flatten(levels=1) }}" 377 | loop_control: 378 | label: "" 379 | tags: 380 | - firewalld 381 | 382 | # - name: firewalld | show variable firewalld_service_port_list 383 | # debug: var=firewalld_service_port_list 384 | # when: debug_enabled_default|bool and firewalld_service_port_list is defined 385 | 386 | - name: firewalld | debug firewalld_service_port_list 387 | debug: msg="{{ item.name }}, {{ item.port_protocol }}, {{ item.port_stdout }}" #, item.rc={{ item.rc }}, item.item_debug={{ item.item|type_debug }}" 388 | with_items: "{{ firewalld_service_port_list }}" 389 | when: 390 | # - ansible_os_family == "RedHat" 391 | # - ansible_distribution_major_version == '7' 392 | - firewalld_managed|bool 393 | - debug_enabled_default|bool 394 | loop_control: 395 | label: "" 396 | tags: 397 | - firewalld 398 | 399 | - name: firewalld | Remove custom service ports not specified 400 | command: "firewall-offline-cmd --service={{ item.0.name }} --remove-port='{{ item.1 }}'" 401 | notify: Reload firewalld 402 | with_subelements: 403 | - "{{ firewalld_service_port_list }}" 404 | - port_stdout 405 | when: 406 | # - ansible_os_family == "RedHat" 407 | # - ansible_distribution_major_version == '7' 408 | - firewalld_managed|bool 409 | # - item.item.state == 'enabled' 410 | - item.1 is defined 411 | - item.1|length > 0 412 | - item.1 not in item.0.port_protocol 413 | loop_control: 414 | label: "{{ item.0.name }} - removed port: {{ item.1|default({}) }}" 415 | tags: 416 | - firewalld 417 | - firewalld_create_service 418 | 419 | # - name: pause 420 | # pause: 421 | # seconds: 30 422 | # when: debug_enabled_default|bool and firewalld_managed|bool 423 | # tags: 424 | # - firewalld 425 | 426 | #firewall-offline-cmd --service=app123-internal --query-port=2181/tcp 427 | - name: firewalld | Get custom service ports to add 428 | command: "firewall-offline-cmd --service={{ item.0.name }} --query-port={{ item.1 }}" 429 | register: stat_firewalld_service_get_service_port_add 430 | failed_when: false 431 | # ignore_errors: true 432 | changed_when: false 433 | with_subelements: 434 | - "{{ firewalld_custom_service|default({}) }}" 435 | - port_protocol 436 | - skip_missing: True 437 | when: 438 | # - ansible_os_family == "RedHat" 439 | # - ansible_distribution_major_version == '7' 440 | - firewalld_managed|bool 441 | - item.0.state == 'enabled' 442 | - item is defined 443 | - item.1 is defined 444 | loop_control: 445 | label: "{{ item.0.name }} - found: {{ 'True' if not stat_firewalld_service_get_service_port_add.rc|d(false)|bool else 'False' }}" 446 | tags: 447 | - firewalld 448 | 449 | # - name: firewalld | debug stat_firewalld_service_get_service_port_add 450 | # debug: var=stat_firewalld_service_get_service_port_add 451 | # when: 452 | # # - ansible_os_family == "RedHat" 453 | # # - ansible_distribution_major_version == '7' 454 | # - firewalld_managed|bool 455 | # - debug_enabled_default|bool 456 | # tags: 457 | # - firewalld 458 | 459 | - name: firewalld | debug stat_firewalld_service_get_service_port_add_add.results|last 460 | debug: msg="{{ item.item | last }}" #, item.rc={{ item.rc }}, item.item_debug={{ item.item|type_debug }}" 461 | with_items: "{{ stat_firewalld_service_get_service_port_add.results }}" 462 | when: 463 | # - ansible_os_family == "RedHat" 464 | # - ansible_distribution_major_version == '7' 465 | - firewalld_managed|bool 466 | - debug_enabled_default|bool 467 | loop_control: 468 | label: "" 469 | tags: 470 | - firewalld 471 | 472 | # - name: firewalld | debug stat_firewalld_service_get_service_port_add type_debug 473 | # debug: msg="item.item={{ item.item | last | type_debug }}" 474 | # when: debug_enabled_default|bool 475 | # loop: "{{ stat_firewalld_service_get_service_port_add.results|flatten(levels=1) }}" 476 | # loop_control: 477 | # label: "" 478 | 479 | #Don't need to use set_fact to create new var? just use stat_firewalld_service_get_service_port_add.results with the magic of map etc 480 | # - name: firewalld | Set variable firewalld_add_name_port 481 | # set_fact: 482 | # # test123: "{{ test123|default([]) }} name: {{ item.item|map(attribute='name')|list|select('defined')|list }} + {{ item.item|last }}" 483 | # # test123: "{{ test123|default([]) + [{'name': item.item|map(attribute='name')|list|select('defined')|list|join(', ') }] }}" 484 | # firewalld_add_name_port: "{{ firewalld_add_name_port|default([]) + [{'name': item.item|map(attribute='name')|list|select('defined')|list|join(', ') , 'port': item.item|last} ] }}" 485 | # when: 486 | # - ansible_os_family == "RedHat" 487 | # - ansible_distribution_major_version == '7' 488 | # - firewalld_managed|bool 489 | # - item.rc != 0 490 | # loop: "{{ stat_firewalld_service_get_service_port_add.results|flatten(levels=1) }}" 491 | # loop_control: 492 | # label: "" 493 | # tags: 494 | # - firewalld 495 | 496 | # - name: firewalld | show variable firewalld_add_name_port 497 | # debug: var=firewalld_add_name_port 498 | # when: debug_enabled_default|bool and firewalld_add_name_port is defined 499 | 500 | # - name: firewalld | show variable firewalld_add_name_port items 501 | # debug: msg="name={{ item.name }}, port={{ item.port }}" 502 | # when: debug_enabled_default|bool and item is defined 503 | # loop: "{{ firewalld_add_name_port|flatten(levels=1) }}" 504 | # loop_control: 505 | # label: "" 506 | 507 | # - name: firewalld | Set port for service 508 | # command: "firewall-offline-cmd --service={{ item.name }} --add-port={{ item.port }}" 509 | # # with_subelements: 510 | # # - "{{ firewalld_custom_service|default({}) }}" 511 | # # - port_protocol 512 | # with_items: 513 | # # - "{{ firewalld_custom_service|default({}) }}" 514 | # - "{{ firewalld_add_name_port }}" 515 | # when: 516 | # - ansible_os_family == "RedHat" 517 | # - ansible_distribution_major_version == '7' 518 | # - firewalld_managed|bool 519 | # - item is defined 520 | # # - item.state == 'enabled' 521 | # # - item.rc != 0 522 | # # - '" " ~ item.1 ~ " " not in stat_service_firewalld_services.stdout' 523 | # loop_control: 524 | # label: "{{ item.name }} - added port: {{ item.port }}" 525 | # tags: 526 | # - firewalld 527 | # - firewalld_create_service 528 | 529 | #Don't need to use set_fact to create new var. just use stat_firewalld_service_get_service_port_add.results with the magic of map etc 530 | - name: firewalld | Add port for custom service 531 | command: "firewall-offline-cmd --service={{ item.item|map(attribute='name')|list|select('defined')|list|join(', ') }} --add-port={{ item.item|last }}" 532 | notify: Reload firewalld 533 | with_items: 534 | - "{{ stat_firewalld_service_get_service_port_add.results }}" 535 | when: 536 | # - ansible_os_family == "RedHat" 537 | # - ansible_distribution_major_version == '7' 538 | - firewalld_managed|bool 539 | - item.rc is defined 540 | # - item is not skipped 541 | - item.rc != 0 542 | loop_control: 543 | label: "{{ item.item|map(attribute='name')|list|select('defined')|list|join(', ') }} - added port: {{ item.item|last }}" 544 | tags: 545 | - firewalld 546 | - firewalld_create_service 547 | 548 | # - name: debug stat_service_firewalld_services 549 | # debug: var=stat_service_firewalld_services.stdout 550 | # when: 551 | # # - ansible_os_family == "RedHat" 552 | # # - ansible_distribution_major_version == '7' 553 | # - firewalld_managed|bool 554 | # - debug_enabled_default|bool 555 | # - stat_service_firewalld_status.rc == 0 556 | # tags: 557 | # - firewalld 558 | 559 | - name: set fact firewalld reload needed 560 | set_fact: 561 | firewalld_reload_hint_result: true 562 | with_items: "{{ firewalld_custom_service }}" 563 | when: 564 | # - ansible_os_family == "RedHat" 565 | # - ansible_distribution_major_version == '7' 566 | - firewalld_managed|bool 567 | - stat_service_firewalld_status.rc == 0 568 | # - stat_service_firewalld_services is failed 569 | - item.state == 'enabled' 570 | - 'item.name not in stat_service_firewalld_services.stdout.split()' 571 | loop_control: 572 | label: "{{ item.name }} not in firewalld service list" 573 | tags: 574 | - firewalld 575 | 576 | - name: debug firewalld_reload_hint_result 577 | debug: var=firewalld_reload_hint_result 578 | when: 579 | # - ansible_os_family == "RedHat" 580 | # - ansible_distribution_major_version == '7' 581 | - firewalld_managed|bool 582 | - debug_enabled_default|bool 583 | - stat_service_firewalld_status.rc == 0 584 | tags: 585 | - firewalld 586 | 587 | #Reload firewall now (if running) so service is visible for next task 588 | #Don't reload if doing remove/re-add right away. not needed since service is visible 589 | #reload here causes outage if firewalld running and app123 is in service! Don't reload yet if exists.. 590 | - name: firewalld | reload firewalld 591 | #command: firewall-cmd --reload 592 | systemd: 593 | name: firewalld 594 | state: reloaded 595 | when: 596 | # - ansible_os_family == "RedHat" 597 | # - ansible_distribution_major_version == '7' 598 | - firewalld_managed|bool 599 | - stat_service_firewalld_status.rc == 0 600 | - firewalld_reload_hint_result|bool 601 | tags: 602 | - firewalld 603 | - skip_ansible_lint 604 | 605 | - name: firewalld | Add/Remove service in zone 606 | # command: 'firewall-offline-cmd --zone=internal --add-service=app123-internal' 607 | firewalld: 608 | service: "{{ item.name }}" 609 | zone: "{{ item.zone }}" 610 | state: "{{ item.state }}" 611 | offline: yes 612 | permanent: yes 613 | notify: Reload firewalld 614 | with_items: "{{ firewalld_custom_service|default({}) }}" 615 | when: 616 | # - ansible_os_family == "RedHat" 617 | # - ansible_distribution_major_version == '7' 618 | - firewalld_managed|bool 619 | loop_control: 620 | # label: "{{ item.name }} - found=0, not found=1: {{ stat_firewalld_service_get_service_zone.rc }}" 621 | label: "{{ item.name }} - {{ item.state }} in zone {{ item.zone }}" 622 | tags: 623 | - firewalld 624 | #End - add service to zone 625 | 626 | #Remove default firewalld services that are not needed from public zone 627 | - name: firewalld | Remove default firewalld services from public zone 628 | firewalld: 629 | service: "{{ item }}" 630 | zone: public 631 | state: disabled 632 | offline: yes 633 | permanent: yes 634 | notify: Reload firewalld 635 | with_items: "{{ firewalld_public_remove_default }}" 636 | when: 637 | # - ansible_os_family == "RedHat" 638 | # - ansible_distribution_major_version == '7' 639 | - firewalld_managed|bool 640 | - firewalld_public_remove_default is defined 641 | tags: 642 | - firewalld 643 | - firewalld_remove_default 644 | 645 | #Remove default firewalld services that are not needed from internal zone 646 | - name: firewalld | Remove default firewalld services from internal zone 647 | firewalld: 648 | service: "{{ item }}" 649 | zone: internal 650 | state: disabled 651 | offline: yes 652 | permanent: yes 653 | notify: Reload firewalld 654 | with_items: "{{ firewalld_internal_remove_default }}" 655 | when: 656 | # - ansible_os_family == "RedHat" 657 | # - ansible_distribution_major_version == '7' 658 | - firewalld_managed|bool 659 | - firewalld_internal_remove_default is defined 660 | tags: 661 | - firewalld 662 | - firewalld_remove_default 663 | 664 | - name: firewalld | Start the firewalld service 665 | systemd: 666 | name: firewalld 667 | state: started 668 | enabled: yes 669 | register: stat_service_firewalld_start 670 | when: 671 | # - ansible_os_family == "RedHat" 672 | # - ansible_distribution_major_version == '7' 673 | - firewalld_managed|bool 674 | - firewalld_start|bool 675 | tags: 676 | - firewalld 677 | - firewalld_start 678 | 679 | - name: pause to wait in case firewalld service fails to start 680 | pause: 681 | seconds: 10 682 | when: 683 | - firewalld_managed|bool 684 | - firewalld_start|bool 685 | - stat_service_firewalld_start.changed 686 | tags: 687 | - firewalld 688 | - firewalld_start 689 | 690 | - name: firewalld | check if running 691 | command: systemctl status firewalld warn=false 692 | register: stat_service_firewalld_status_end 693 | failed_when: not stat_service_firewalld_status_end.rc == 0 694 | # ignore_errors: true 695 | changed_when: false 696 | # no_log: True 697 | when: 698 | # - ansible_os_family == "RedHat" 699 | # - ansible_distribution_major_version == '7' 700 | - firewalld_managed|bool 701 | - firewalld_start|bool 702 | - stat_service_firewalld_start.changed 703 | tags: 704 | - firewalld 705 | - firewalld_start 706 | 707 | - name: debug stat_service_firewalld_status_end 708 | debug: var=stat_service_firewalld_status_end.stdout_lines 709 | when: 710 | # - ansible_os_family == "RedHat" 711 | # - ansible_distribution_major_version == '7' 712 | - firewalld_managed|bool 713 | - firewalld_start|bool 714 | - stat_service_firewalld_start.changed 715 | - debug_enabled_default|bool 716 | tags: 717 | - firewalld 718 | - firewalld_start 719 | 720 | #Fedora <30 claims firewalld is running but ip6tables is not working. 721 | #Force a reload check to be safe. 722 | - name: firewalld | Check firewalld can reload 723 | command: firewall-cmd --reload 724 | changed_when: false 725 | when: 726 | # - ansible_os_family == "RedHat" 727 | # - ansible_distribution_major_version == '7' 728 | - firewalld_managed|bool 729 | - (firewalld_start|bool or stat_service_firewalld_status.rc == 0) 730 | --------------------------------------------------------------------------------