diff --git a/.github/workflows/stackhpc-all-in-one.yml b/.github/workflows/stackhpc-all-in-one.yml index 611a56699..c5aa3e368 100644 --- a/.github/workflows/stackhpc-all-in-one.yml +++ b/.github/workflows/stackhpc-all-in-one.yml @@ -223,6 +223,7 @@ jobs: admin_bootproto: dhcp admin_ips: controller0: "{{ access_ip_v4.value }}" + admin_zone: admin EOF - name: Write Terraform network interface config diff --git a/doc/source/configuration/cephadm.rst b/doc/source/configuration/cephadm.rst index 9c839b42e..bcb13cd6c 100644 --- a/doc/source/configuration/cephadm.rst +++ b/doc/source/configuration/cephadm.rst @@ -344,6 +344,8 @@ should be used in the Kolla Manila configuration e.g.: manila_cephfs_filesystem_name: manila-cephfs +.. _RGWs-With-Ceph: + RADOS Gateways -------------- diff --git a/doc/source/configuration/firewall.rst b/doc/source/configuration/firewall.rst new file mode 100644 index 000000000..2a14d8d6c --- /dev/null +++ b/doc/source/configuration/firewall.rst @@ -0,0 +1,462 @@ +.. _firewall: + +======== +Firewall +======== + +StackHPC Kayobe configuration provides a standardised firewalld configuration. +The configuration uses the :kayobe-doc:`firewall +` host configuration +functionality of Kayobe. + +The firewall configuration is provided in +``etc/kayobe/inventory/group_vars/all/firewall``. + +Enabling StackHPC firewalld rules +================================= + +The standardised firewalld configuration is not enabled by default and must be +actively opted into. To do so, make the following changes in +``etc/kayobe/.yml`` (or +``etc/kayobe/environments//.yml`` if environments are being +used). + +Controller firewalld Configuration +---------------------------------- + +.. code-block:: yaml + :caption: ``controllers.yml`` + + ############################################################################### + # Controller node firewalld configuration. + + # Whether to install and enable firewalld. + controller_firewalld_enabled: true + + # A list of zones to create. Each item is a dict containing a 'zone' item. + controller_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + + # A firewalld zone to set as the default. Default is unset, in which case + # the default zone will not be changed. + # Predefined zones are listed here: + # https://firewalld.org/documentation/zone/predefined-zones.html + controller_firewalld_default_zone: trusted + + # A list of firewall rules to apply. Each item is a dict containing + # arguments to pass to the firewalld module. Arguments are omitted if not + # provided, with the following exceptions: + # - offline: true + # - permanent: true + # - state: enabled + controller_firewalld_rules: "{{ stackhpc_firewalld_rules }}" + +Compute firewalld Configuration +------------------------------- + +.. code-block:: yaml + :caption: ``compute.yml`` + + ############################################################################### + # Compute node firewalld configuration. + + # Whether to install and enable firewalld. + compute_firewalld_enabled: true + + # A list of zones to create. Each item is a dict containing a 'zone' item. + compute_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + + # A firewalld zone to set as the default. Default is unset, in which case + # the default zone will not be changed. + # Predefined zones are listed here: + # https://firewalld.org/documentation/zone/predefined-zones.html + compute_firewalld_default_zone: trusted + + # A list of firewall rules to apply. Each item is a dict containing + # arguments to pass to the firewalld module. Arguments are omitted if not + # provided, with the following exceptions: + # - offline: true + # - permanent: true + # - state: enabled + compute_firewalld_rules: "{{ stackhpc_firewalld_rules }}" + +Storage firewalld Configuration +------------------------------- + +.. code-block:: yaml + :caption: ``storage.yml`` + + ############################################################################### + # storage node firewalld configuration. + + # Whether to install and enable firewalld. + storage_firewalld_enabled: true + + # A list of zones to create. Each item is a dict containing a 'zone' item. + storage_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + + # A firewalld zone to set as the default. Default is unset, in which case + # the default zone will not be changed. + # Predefined zones are listed here: + # https://firewalld.org/documentation/zone/predefined-zones.html + storage_firewalld_default_zone: trusted + + # A list of firewall rules to apply. Each item is a dict containing + # arguments to pass to the firewalld module. Arguments are omitted if not + # provided, with the following exceptions: + # - offline: true + # - permanent: true + # - state: enabled + storage_firewalld_rules: "{{ stackhpc_firewalld_rules }}" + +If using RADOS Gateway, you can customise ``stackhpc_ceph_firewalld_radosgw_port`` to match +the ``rgw_frontend_port`` as documented in :ref:`RGWs-with-Ceph`. + +Monitoring firewalld Configuration +---------------------------------- + +.. code-block:: yaml + :caption: ``monitoring.yml`` + + ############################################################################### + # monitoring node firewalld configuration. + + # Whether to install and enable firewalld. + monitoring_firewalld_enabled: true + + # A list of zones to create. Each item is a dict containing a 'zone' item. + monitoring_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + + # A firewalld zone to set as the default. Default is unset, in which case + # the default zone will not be changed. + # Predefined zones are listed here: + # https://firewalld.org/documentation/zone/predefined-zones.html + monitoring_firewalld_default_zone: trusted + + # A list of firewall rules to apply. Each item is a dict containing + # arguments to pass to the firewalld module. Arguments are omitted if not + # provided, with the following exceptions: + # - offline: true + # - permanent: true + # - state: enabled + monitoring_firewalld_rules: "{{ stackhpc_firewalld_rules }}" + +Infrastructure VM firewalld Configuration +----------------------------------------- + +The standard firewalld configuration has rules for wazuh-manager and Ansible +control host Infrastructure VMs. + +.. code-block:: yaml + :caption: ``infra-vms.yml`` + + ############################################################################### + # Infrastructure VM node firewalld configuration + + # Whether to install and enable firewalld. + infra_vm_firewalld_enabled: true + + # A list of zones to create. Each item is a dict containing a 'zone' item. + infra_vm_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + + # A firewalld zone to set as the default. Default is unset, in which case + # the default zone will not be changed. + # Predefined zones are listed here: + # https://firewalld.org/documentation/zone/predefined-zones.html + infra_vm_firewalld_default_zone: trusted + + # A list of firewall rules to apply. Each item is a dict containing + # arguments to pass to the firewalld module. Arguments are omitted if not + # provided, with the following exceptions: + # - offline: true + # - permanent: true + # - state: enabled + infra_vm_firewalld_rules: "{{ stackhpc_firewalld_rules }}" + +When configuring wazuh-manager, remember to set ``wazuh_dashboard_net_name`` if you have customised +the network where the Wazuh dashboard is exposed. + +Seed firewalld Configuration +---------------------------- + +.. code-block:: yaml + :caption: ``seed.yml`` + + ############################################################################### + # seed node firewalld configuration. + + # Whether to install and enable firewalld. + seed_firewalld_enabled: true + + # A list of zones to create. Each item is a dict containing a 'zone' item. + seed_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + + # A firewalld zone to set as the default. Default is unset, in which case + # the default zone will not be changed. + # Predefined zones are listed here: + # https://firewalld.org/documentation/zone/predefined-zones.html + seed_firewalld_default_zone: trusted + + # A list of firewall rules to apply. Each item is a dict containing + # arguments to pass to the firewalld module. Arguments are omitted if not + # provided, with the following exceptions: + # - offline: true + # - permanent: true + # - state: enabled + seed_firewalld_rules: "{{ stackhpc_firewalld_rules }}" + +Seed Hypervisor firewalld Configuration +--------------------------------------- + +.. code-block:: yaml + :caption: ``seed_hypervisor.yml`` + + ############################################################################### + # seed_hypervisor node firewalld configuration. + + # Whether to install and enable firewalld. + seed_hypervisor_firewalld_enabled: true + + # A list of zones to create. Each item is a dict containing a 'zone' item. + seed_hypervisor_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + + # A firewalld zone to set as the default. Default is unset, in which case + # the default zone will not be changed. + # Predefined zones are listed here: + # https://firewalld.org/documentation/zone/predefined-zones.html + seed_hypervisor_firewalld_default_zone: trusted + + # A list of firewall rules to apply. Each item is a dict containing + # arguments to pass to the firewalld module. Arguments are omitted if not + # provided, with the following exceptions: + # - offline: true + # - permanent: true + # - state: enabled + seed_hypervisor_firewalld_rules: "{{ stackhpc_firewalld_rules }}" + +The following workaround is needed to prevent VM network traffic from being blocked: + +.. code-block:: yaml + :caption: ``seed_hypervisor.yml`` + + seed_hypervisor_sysctl_parameters: + # By default this is 1, which causes layer 2 traffic flowing through Linux + # bridges to pass through iptables. This blocks traffic from VMs (seed, wazuh) to + # the Internet. + net.bridge.bridge-nf-call-iptables: 0 + +The hope is that in the future this can be replaced by some additional firewalld configuration. + +Kolla-Ansible configuration +--------------------------- + +Ensure Kolla Ansible opens up ports in firewalld for services on the public +API network: + +.. code-block:: yaml + :caption: ``etc/kayobe/kolla/globals.yml`` + + enable_external_api_firewalld: true + external_api_firewalld_zone: "{{ public_net_name | net_zone }}" + +Network configuration +--------------------- + +Ensure every network in ``networks.yml`` has a zone defined. The standard +configuration is to set the internal network zone to ``trusted`` and every +other zone to the name of the network. See +``etc/kayobe/environments/ci-multinode/networks.yml`` for a practical example. + +Custom rules +------------ + +Custom firewalld rules can be added to ``stackhpc_firewalld_rules_extra`` + +The variable is a list of firewall rules to apply. Each item is a dictionary +containing arguments to pass to the firewalld module. The variable can be +defined as a group var or host var in the kayobe inventory. + +The structure of custom rules is different from the default rules. Custom rules +use the firewalld Ansible module format. Arguments are omitted if not provided, +with the following exceptions: + +* ``offline: true`` +* ``permanent: true`` +* ``state: enabled`` + +The main differences are that the ``zone`` argument is mandatory, and the +``network`` argument is not. + +The example below would enable SSH in the ``provision_oc`` zone, and disable +UDP port 1000 in the ``admin_oc`` zone for the Wazuh manager Infrastructure +VM: + +.. code-block:: yaml + :caption: ``etc/kayobe/inventory/group_vars/wazuh_manager/firewall`` + + stackhpc_firewalld_rules_extra: + - service: ssh + zone: "{{ provision_oc_net_name | net_zone }}" + state: enabled + - port: 1000/udp + zone: "{{ admin_oc_net_name | net_zone }}" + state: disabled + +Extra rules have higher precedence than the default rules but are not +validated before being applied. Use with caution. If you need to add a custom +rule, consider adding it to the default rule list with an appropriate boolean +condition, and where possible merge your changes back into upstream SKC. + +Validation +---------- + +The ``kayobe configuration dump`` command can be used to view all the rules +that will be applied to a host. + +.. code-block:: bash + + kayobe configuration dump --var-name stackhpc_firewalld_rules --limit + +A shorter version, ``stackhpc_firewalld_rules_debug`` prints the rules in a +simplified format: + +.. code-block:: bash + + kayobe configuration dump --var-name stackhpc_firewalld_rules_debug --limit + +If the commands above print a template, rather than a list of rules, the +configuration may be invalid. The ``kayobe configuration dump`` command can be +used on other variables such as ``stackhpc_firewalld_rules_default`` or +``stackhpc_*_firewalld_rules_template`` to debug the configuration. See the +`How it works`_ section for more details. + +It can be useful to print the active ports on each type of host, to create +rules for running services. The internal network is currently left open. The +below command will print all other open ports: + +.. code-block:: bash + + ss -lntpu | grep --invert-match '' + +It is strongly recommended that you dry-run the changes using ``--diff`` and +``--check`` before applying to a production system: + +.. code-block:: bash + :caption: ``Overcloud diff example`` + + kayobe overcloud host configure -t firewall --diff --check + +Baseline checks +^^^^^^^^^^^^^^^ + +Before applying, it is a good idea to take note of any actively firing alerts +and run Tempest to gather a baseline. See the :doc:`Tempest +` page for more details. + +Applying changes +---------------- + +Before applying these changes, you should be completely sure you are not going +to lock yourself out of any hosts. If you are deploying these changes to a test +environment, consider setting a password on the stack user so that you can +access the host through a BMC or other virtual console. + +The following Kayobe command can be used to set a password on all overcloud +hosts: + +.. code-block:: bash + + kayobe overcloud host command run --command "echo 'stack:super-secret-password' | sudo chpasswd" --show-output + +The ``firewalld-watchdog.yml`` playbook can be used to set up a timer that +disables the firewalld service after a period of time (default 600s). It should +be used as follows: + +.. code-block:: bash + + # Enable the watchdog BEFORE applying the firewall configuration + kayobe playbook run etc/kayobe/ansible/firewalld-watchdog.yml -l + + # Disable the watchdog after applying the firewall configuration + kayobe playbook run etc/kayobe/ansible/firewalld-watchdog.yml -l -e firewalld_watchdog_state=absent + +If the firewall rules block connectivity, the second playbook run (disabling +the watchdog) will fail. You will still be able to get in after the watchdog +triggers. Remember to disable the watchdog when you are finished, otherwise the +firewall will be disabled! + +Changes should be applied to controllers one at a time to ensure connectivity +is not lost. + +Once you are sure you know what you are doing, use the ``kayobe * host +configure`` commands to apply the firewall changes: + +.. code-block:: bash + + # For Seed Hypervisor hosts + kayobe seed hypervisor host configure -t network,firewall + # For Seed hosts + kayobe seed host configure -t network,firewall + # For Infrastructure VM hosts + kayobe infra vm host configure -t network,firewall + # For the First Controller + kayobe overcloud host configure -t network,firewall -l controllers[0] + # For the Second Controller + kayobe overcloud host configure -t network,firewall -l controllers[1] + # For the Third Controller + kayobe overcloud host configure -t network,firewall -l controllers[2] + # For the rest of the Overcloud hosts + kayobe overcloud host configure -t network,firewall + +Debugging +--------- + +To test the changes, first check for any firing alerts, then try simple smoke +tests (create a VM, list OpenStack endpoints etc.), then run Tempest. + +If the firewall configuration is causing errors, it is often useful to log +blocked packets. + +.. code-block:: bash + + sudo sed -i s/LogDenied=off/LogDenied=all/g /etc/firewalld/firewalld.conf + sudo systemctl restart firewalld + +Dropped packets will be logged to ``dmesg``. + +How it works +============ + +The standard firewall rule configuration is stored in +``etc/kayobe/inventory/group_vars/all/firewall``. + +The file contains sections for different host groups. There are sections for: + +* Common (all hosts) +* Controllers +* Compute +* Storage +* Monitoring +* Wazuh Manager Infrastructure VM +* Ansible Control host Infrastructure VM +* Seed +* Seed Hypervisor + +Each of these sections contains a template. The template is made of sets of +rules. The rules can then be enabled and disabled in sets, based on properties +of the cloud. For example, if ``kolla_enable_designate`` is true, a set of +rules will be enabled in ``stackhpc_controller_firewalld_rules_template``. + +The templates are combined into a single list, +``stackhpc_firewalld_rules_template``. Templates are selected according to the +host's group membership, as well as a set of common rules, which is enabled for +all hosts. + +The rules are then formatted into a single list of the enabled default rules: +``stackhpc_firewalld_rules_default``. The Rules are manipulated to reduce +duplication. When no zone is specified in a rule template, it is inferred from +the network. They are also validated. Conflicting rules will result in an +error. Non-applicable rules are dropped. + +The default rules are combined with any extra rules defined for the deployment. +The complete set of controller firewalld rules is +``stackhpc_firewalld_rules``. diff --git a/doc/source/configuration/index.rst b/doc/source/configuration/index.rst index f8be7891a..2a42bd473 100644 --- a/doc/source/configuration/index.rst +++ b/doc/source/configuration/index.rst @@ -8,16 +8,17 @@ the various features provided. .. toctree:: :maxdepth: 1 - walled-garden release-train host-images lvm swap cephadm monitoring - wazuh vault + wazuh + walled-garden + security-hardening + firewall magnum-capi ci-cd - security-hardening cloudkitty diff --git a/etc/kayobe/ansible/firewalld-watchdog.yml b/etc/kayobe/ansible/firewalld-watchdog.yml new file mode 100644 index 000000000..874992df7 --- /dev/null +++ b/etc/kayobe/ansible/firewalld-watchdog.yml @@ -0,0 +1,69 @@ +--- +# This playbook can be applied in advance of rolling out a firewall +# configuration. It sets up a timer that disables the firewalld service after a +# period of time (default 600s). It should be used as follows: +# 1. Enable firewalld-watchdog +# kayobe playbook run etc/kayobe/ansible/firewalld-watchdog.yml -l +# 2. Apply firewall config +# kayobe host configure -l -t network,firewall +# 3. Disable watchdog +# kayobe playbook run etc/kayobe/ansible/firewalld-watchdog.yml -l -e firewalld_watchdog_state=absent +# If the firewall changes result in being locked out of the system, the +# watchdog will disable the firewall after the timeout. +# Remember to disable the watchdog, otherwise the firewall will be disabled! + +- name: Create a systemd timer to stop firewalld + hosts: seed:seed-hypervisor:overcloud:infra-vms + tags: + - firewalld-watchdog + vars: + # Watchdog state: present or absent. + firewalld_watchdog_state: present + # Watchdog timeout in seconds. + firewalld_watchdog_timeout_s: 600 + become: true + tasks: + - when: firewalld_watchdog_state == 'present' + block: + - name: Create firewalld-watchdog service unit file + ansible.builtin.copy: + dest: /etc/systemd/system/firewalld-watchdog.service + content: | + [Unit] + Description=Firewalld watchdog service + + [Service] + Type=oneshot + ExecStart=/usr/bin/systemctl stop firewalld + register: service_result + + - name: Create firewalld-watchdog timer unit file + ansible.builtin.copy: + dest: /etc/systemd/system/firewalld-watchdog.timer + content: | + [Unit] + Description=Firewalld watchdog timer + + [Timer] + OnActiveSec={{ firewalld_watchdog_timeout_s }} + Unit=firewalld-watchdog.service + + [Install] + WantedBy=timers.target + register: timer_result + + - name: Enable or disable firewalld-watchdog timer + ansible.builtin.systemd_service: + name: firewalld-watchdog.timer + daemon_reload: "{{ service_result is changed or timer_result is changed }}" + enabled: false + state: "{{ 'started' if firewalld_watchdog_state == 'present' else 'stopped' }}" + + - name: Remove firewalld-watchdog unit files + ansible.builtin.file: + path: "/etc/systemd/system/{{ item }}" + state: absent + loop: + - firewalld-watchdog.service + - firewalld-watchdog.timer + when: firewalld_watchdog_state == 'absent' diff --git a/etc/kayobe/environments/ci-aio/controllers.yml b/etc/kayobe/environments/ci-aio/controllers.yml index b34536705..8972187df 100644 --- a/etc/kayobe/environments/ci-aio/controllers.yml +++ b/etc/kayobe/environments/ci-aio/controllers.yml @@ -10,3 +10,11 @@ controller_bootstrap_user: "{{ os_distribution if os_distribution == 'ubuntu' el # for the exact configuration. controller_lvm_groups: - "{{ stackhpc_lvm_group_rootvg }}" + +# Controller firewalld configuration. See inventory/group_vars/all/firewall for +# the exact configuration. +controller_firewalld_zones: "{{ stackhpc_firewalld_zones }}" +controller_firewalld_rules: "{{ stackhpc_firewalld_rules }}" +# FIXME(wszumski): Firewall disabled in OVS temporarily until someone has a change to fix it. +controller_firewalld_enabled: "{{ kolla_enable_ovn | bool }}" +controller_firewalld_default_zone: "drop" diff --git a/etc/kayobe/environments/ci-aio/hooks/overcloud-host-configure/post.d/10-debug-firewall.yml b/etc/kayobe/environments/ci-aio/hooks/overcloud-host-configure/post.d/10-debug-firewall.yml new file mode 100644 index 000000000..f0fa29978 --- /dev/null +++ b/etc/kayobe/environments/ci-aio/hooks/overcloud-host-configure/post.d/10-debug-firewall.yml @@ -0,0 +1,9 @@ +--- + +- hosts: overcloud + gather_facts: false + tasks: + - name: Configure firewalld to log blocked traffic + command: firewall-cmd --set-log-denied=all + become: true + when: firewalld_enabled | bool diff --git a/etc/kayobe/environments/ci-aio/kolla/globals.yml b/etc/kayobe/environments/ci-aio/kolla/globals.yml index 9f058ed19..2244b5bf5 100644 --- a/etc/kayobe/environments/ci-aio/kolla/globals.yml +++ b/etc/kayobe/environments/ci-aio/kolla/globals.yml @@ -15,6 +15,9 @@ opensearch_heap_size: 200m # Increase Grafana timeout grafana_start_first_node_retries: 20 +# Open up ports in firewalld for services on the public API network. +enable_external_api_firewalld: "{{ controller_firewalld_enabled | bool }}" + # Ensure Rabbit is deployed with HA rather than quorum queues (to test migrations) om_enable_rabbitmq_high_availability: true om_enable_rabbitmq_quorum_queues: false diff --git a/etc/kayobe/environments/ci-aio/networks.yml b/etc/kayobe/environments/ci-aio/networks.yml index 216696eaa..e3cc4d43d 100644 --- a/etc/kayobe/environments/ci-aio/networks.yml +++ b/etc/kayobe/environments/ci-aio/networks.yml @@ -89,6 +89,7 @@ aio_neutron_allocation_pool_end: 192.168.33.127 aio_inspection_allocation_pool_start: 192.168.33.128 aio_inspection_allocation_pool_end: 192.168.33.254 aio_vip_address: 192.168.33.2 +aio_zone: aio ############################################################################### # Network virtual patch link configuration. diff --git a/etc/kayobe/environments/ci-multinode/compute.yml b/etc/kayobe/environments/ci-multinode/compute.yml index 7e7701cf0..a00207b41 100644 --- a/etc/kayobe/environments/ci-multinode/compute.yml +++ b/etc/kayobe/environments/ci-multinode/compute.yml @@ -4,3 +4,26 @@ compute_bootstrap_user: "{{ os_distribution if os_distribution == 'ubuntu' else # format. compute_lvm_groups: - "{{ stackhpc_lvm_group_rootvg }}" + +############################################################################### +# Compute node firewalld configuration. + +# Whether to install and enable firewalld. +compute_firewalld_enabled: true + +# A list of zones to create. Each item is a dict containing a 'zone' item. +compute_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + +# A firewalld zone to set as the default. Default is unset, in which case +# the default zone will not be changed. +# Predefined zones are listed here: +# https://firewalld.org/documentation/zone/predefined-zones.html +compute_firewalld_default_zone: trusted + +# A list of firewall rules to apply. Each item is a dict containing +# arguments to pass to the firewalld module. Arguments are omitted if not +# provided, with the following exceptions: +# - offline: true +# - permanent: true +# - state: enabled +compute_firewalld_rules: "{{ stackhpc_firewalld_rules }}" diff --git a/etc/kayobe/environments/ci-multinode/controllers.yml b/etc/kayobe/environments/ci-multinode/controllers.yml index 73c31c27f..173bcc371 100644 --- a/etc/kayobe/environments/ci-multinode/controllers.yml +++ b/etc/kayobe/environments/ci-multinode/controllers.yml @@ -4,3 +4,27 @@ controller_bootstrap_user: "{{ os_distribution if os_distribution == 'ubuntu' el # format. controller_lvm_groups: - "{{ stackhpc_lvm_group_rootvg }}" + + +############################################################################### +# Controller node firewalld configuration. + +# Whether to install and enable firewalld. +controller_firewalld_enabled: true + +# A list of zones to create. Each item is a dict containing a 'zone' item. +controller_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + +# A firewalld zone to set as the default. Default is unset, in which case +# the default zone will not be changed. +# Predefined zones are listed here: +# https://firewalld.org/documentation/zone/predefined-zones.html +controller_firewalld_default_zone: trusted + +# A list of firewall rules to apply. Each item is a dict containing +# arguments to pass to the firewalld module. Arguments are omitted if not +# provided, with the following exceptions: +# - offline: true +# - permanent: true +# - state: enabled +controller_firewalld_rules: "{{ stackhpc_firewalld_rules }}" diff --git a/etc/kayobe/environments/ci-multinode/infra-vms.yml b/etc/kayobe/environments/ci-multinode/infra-vms.yml index c388a3c73..33bb0b91e 100644 --- a/etc/kayobe/environments/ci-multinode/infra-vms.yml +++ b/etc/kayobe/environments/ci-multinode/infra-vms.yml @@ -4,3 +4,26 @@ infra_vm_bootstrap_user: "{{ os_distribution if os_distribution == 'ubuntu' else # format. infra_vm_lvm_groups: - "{{ stackhpc_lvm_group_rootvg }}" + +############################################################################### +# Infrastructure VM node firewalld configuration + +# Whether to install and enable firewalld. +infra_vm_firewalld_enabled: true + +# A list of zones to create. Each item is a dict containing a 'zone' item. +infra_vm_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + +# A firewalld zone to set as the default. Default is unset, in which case +# the default zone will not be changed. +# Predefined zones are listed here: +# https://firewalld.org/documentation/zone/predefined-zones.html +infra_vm_firewalld_default_zone: trusted + +# A list of firewall rules to apply. Each item is a dict containing +# arguments to pass to the firewalld module. Arguments are omitted if not +# provided, with the following exceptions: +# - offline: true +# - permanent: true +# - state: enabled +infra_vm_firewalld_rules: "{{ stackhpc_firewalld_rules }}" diff --git a/etc/kayobe/environments/ci-multinode/inventory/group_vars/all/firewall.yml b/etc/kayobe/environments/ci-multinode/inventory/group_vars/all/firewall.yml new file mode 100644 index 000000000..ca1f9b475 --- /dev/null +++ b/etc/kayobe/environments/ci-multinode/inventory/group_vars/all/firewall.yml @@ -0,0 +1,7 @@ +--- + +stackhpc_firewalld_rules_extra: + - port: "{{ vxlan_dstport }}/udp" + network: "{{ admin_oc_net_name }}" + zone: "{{ admin_oc_net_name | net_zone }}" + state: enabled diff --git a/etc/kayobe/environments/ci-multinode/kolla/globals.yml b/etc/kayobe/environments/ci-multinode/kolla/globals.yml index 599618500..354a8c310 100644 --- a/etc/kayobe/environments/ci-multinode/kolla/globals.yml +++ b/etc/kayobe/environments/ci-multinode/kolla/globals.yml @@ -62,6 +62,10 @@ designate_backend: "bind9" designate_recursion: "yes" designate_forwarders_addresses: "1.1.1.1; 8.8.8.8" +# Open up ports in firewalld for services on the public API network. +enable_external_api_firewalld: true +external_api_firewalld_zone: "{{ public_net_name | net_zone }}" + ############################################################################ # RabbitMQ diff --git a/etc/kayobe/environments/ci-multinode/monitoring.yml b/etc/kayobe/environments/ci-multinode/monitoring.yml new file mode 100644 index 000000000..fa9bbf0be --- /dev/null +++ b/etc/kayobe/environments/ci-multinode/monitoring.yml @@ -0,0 +1,23 @@ +--- +############################################################################### +# monitoring node firewalld configuration. + +# Whether to install and enable firewalld. +monitoring_firewalld_enabled: true + +# A list of zones to create. Each item is a dict containing a 'zone' item. +monitoring_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + +# A firewalld zone to set as the default. Default is unset, in which case +# the default zone will not be changed. +# Predefined zones are listed here: +# https://firewalld.org/documentation/zone/predefined-zones.html +monitoring_firewalld_default_zone: trusted + +# A list of firewall rules to apply. Each item is a dict containing +# arguments to pass to the firewalld module. Arguments are omitted if not +# provided, with the following exceptions: +# - offline: true +# - permanent: true +# - state: enabled +monitoring_firewalld_rules: "{{ stackhpc_firewalld_rules }}" diff --git a/etc/kayobe/environments/ci-multinode/networks.yml b/etc/kayobe/environments/ci-multinode/networks.yml index c0a7ff69e..59d3760b9 100644 --- a/etc/kayobe/environments/ci-multinode/networks.yml +++ b/etc/kayobe/environments/ci-multinode/networks.yml @@ -71,12 +71,16 @@ storage_mgmt_net_name: storage_mgmt ############################################################################### # Network definitions. +# Admin overcloud network +admin_oc_zone: "admin_oc" + # Internal network internal_cidr: 192.168.37.0/24 internal_mtu: "{{ ansible_facts.default_ipv4.mtu - 50 }}" internal_allocation_pool_start: 192.168.37.3 internal_allocation_pool_end: 192.168.37.254 internal_vlan: 101 +internal_zone: "trusted" # External network external_cidr: 192.168.38.0/24 @@ -84,6 +88,7 @@ external_mtu: "{{ ansible_facts.default_ipv4.mtu - 50 }}" external_allocation_pool_start: 192.168.38.3 external_allocation_pool_end: 192.168.38.128 external_vlan: 102 +external_zone: "external" # Public network public_cidr: 192.168.39.0/24 @@ -91,6 +96,7 @@ public_mtu: "{{ ansible_facts.default_ipv4.mtu - 50 }}" public_allocation_pool_start: 192.168.39.3 public_allocation_pool_end: 192.168.39.254 public_vlan: 103 +public_zone: "public" # Tunnel network tunnel_cidr: 192.168.40.0/24 @@ -98,6 +104,7 @@ tunnel_mtu: "{{ ansible_facts.default_ipv4.mtu - 50 }}" tunnel_allocation_pool_start: 192.168.40.3 tunnel_allocation_pool_end: 192.168.40.254 tunnel_vlan: 104 +tunnel_zone: "tunnel" # Storage network storage_cidr: 192.168.41.0/24 @@ -105,6 +112,7 @@ storage_mtu: "{{ ansible_facts.default_ipv4.mtu - 50 }}" storage_allocation_pool_start: 192.168.41.3 storage_allocation_pool_end: 192.168.41.254 storage_vlan: 105 +storage_zone: "storage" # Storage management network # NOTE: Skipping the .42 subnet to avoid a collision with a popular number. @@ -113,6 +121,7 @@ storage_mgmt_mtu: "{{ ansible_facts.default_ipv4.mtu - 50 }}" storage_mgmt_allocation_pool_start: 192.168.43.3 storage_mgmt_allocation_pool_end: 192.168.43.254 storage_mgmt_vlan: 106 +storage_mgmt_zone: "storage_mgmt" # Provision overcloud network provision_oc_cidr: 192.168.33.0/24 @@ -120,6 +129,7 @@ provision_oc_mtu: "{{ ansible_facts.default_ipv4.mtu - 50 }}" provision_oc_allocation_pool_start: 192.168.33.128 provision_oc_allocation_pool_end: 192.168.33.254 provision_oc_vlan: 107 +provision_oc_zone: "provision_oc" ############################################################################### # Network virtual patch link configuration. diff --git a/etc/kayobe/environments/ci-multinode/seed-hypervisor.yml b/etc/kayobe/environments/ci-multinode/seed-hypervisor.yml new file mode 100644 index 000000000..d64b776fc --- /dev/null +++ b/etc/kayobe/environments/ci-multinode/seed-hypervisor.yml @@ -0,0 +1,23 @@ +--- +############################################################################### +# seed_hypervisor node firewalld configuration. + +# Whether to install and enable firewalld. +seed_hypervisor_firewalld_enabled: true + +# A list of zones to create. Each item is a dict containing a 'zone' item. +seed_hypervisor_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + +# A firewalld zone to set as the default. Default is unset, in which case +# the default zone will not be changed. +# Predefined zones are listed here: +# https://firewalld.org/documentation/zone/predefined-zones.html +seed_hypervisor_firewalld_default_zone: trusted + +# A list of firewall rules to apply. Each item is a dict containing +# arguments to pass to the firewalld module. Arguments are omitted if not +# provided, with the following exceptions: +# - offline: true +# - permanent: true +# - state: enabled +seed_hypervisor_firewalld_rules: "{{ stackhpc_firewalld_rules }}" diff --git a/etc/kayobe/environments/ci-multinode/seed.yml b/etc/kayobe/environments/ci-multinode/seed.yml index bb9e3c6bf..e732258c1 100644 --- a/etc/kayobe/environments/ci-multinode/seed.yml +++ b/etc/kayobe/environments/ci-multinode/seed.yml @@ -27,3 +27,26 @@ snat_rules_manila: source_ip: "{{ ansible_facts[storage_interface].ipv4.address | default }}" # Only add the storage snat rule if we are using manila-cephfs. snat_rules: "{{ snat_rules_default + snat_rules_manila if (kolla_enable_manila | bool and kolla_enable_manila_backend_cephfs_native | bool) else snat_rules_default }}" + +############################################################################### +# seed node firewalld configuration. + +# Whether to install and enable firewalld. +seed_firewalld_enabled: true + +# A list of zones to create. Each item is a dict containing a 'zone' item. +seed_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + +# A firewalld zone to set as the default. Default is unset, in which case +# the default zone will not be changed. +# Predefined zones are listed here: +# https://firewalld.org/documentation/zone/predefined-zones.html +seed_firewalld_default_zone: trusted + +# A list of firewall rules to apply. Each item is a dict containing +# arguments to pass to the firewalld module. Arguments are omitted if not +# provided, with the following exceptions: +# - offline: true +# - permanent: true +# - state: enabled +seed_firewalld_rules: "{{ stackhpc_firewalld_rules }}" diff --git a/etc/kayobe/environments/ci-multinode/storage.yml b/etc/kayobe/environments/ci-multinode/storage.yml index b152af472..11f7cf71e 100644 --- a/etc/kayobe/environments/ci-multinode/storage.yml +++ b/etc/kayobe/environments/ci-multinode/storage.yml @@ -4,3 +4,26 @@ storage_bootstrap_user: "{{ os_distribution if os_distribution == 'ubuntu' else # format. storage_lvm_groups: - "{{ stackhpc_lvm_group_rootvg }}" + +############################################################################### +# storage node firewalld configuration. + +# Whether to install and enable firewalld. +storage_firewalld_enabled: true + +# A list of zones to create. Each item is a dict containing a 'zone' item. +storage_firewalld_zones: "{{ stackhpc_firewalld_zones }}" + +# A firewalld zone to set as the default. Default is unset, in which case +# the default zone will not be changed. +# Predefined zones are listed here: +# https://firewalld.org/documentation/zone/predefined-zones.html +storage_firewalld_default_zone: trusted + +# A list of firewall rules to apply. Each item is a dict containing +# arguments to pass to the firewalld module. Arguments are omitted if not +# provided, with the following exceptions: +# - offline: true +# - permanent: true +# - state: enabled +storage_firewalld_rules: "{{ stackhpc_firewalld_rules }}" diff --git a/etc/kayobe/inventory/group_vars/all/firewall b/etc/kayobe/inventory/group_vars/all/firewall new file mode 100644 index 000000000..488e95b65 --- /dev/null +++ b/etc/kayobe/inventory/group_vars/all/firewall @@ -0,0 +1,330 @@ +--- +######################################### +# StackHPC default firewall configuration +######################################### +# This file contains the reference StackHPC firewalld rule implementation. It +# is designed to cover as many services and use cases as possible, however may +# not be compatible with all deployments. For more information, see the +# firewall page in the configuration section of the SKC docs. + +# A templated list of firewalld zones, according to the host's network +# interfaces. +# This variable can be used to set any *_firewalld_zones kayobe variable e.g. +# compute_firewalld_zones: "{{ stackhpc_firewalld_zones }}" in compute.yml +stackhpc_firewalld_zones: | + {% set network_zones = [] %} + {% for network in network_interfaces %} + {% if network | net_zone %} + {% set _ = network_zones.append({'zone': network | net_zone }) %} + {% endif %} + {% endfor %} + {{ network_zones | unique | list }} + +# A templated list of firewalld rules, according to the enabled services, +# host's group membership, and host's network configuration. +# This variable can be used to set any *_firewalld_rules kayobe variable e.g. +# compute_firewalld_rules: "{{ stackhpc_firewalld_rules }}" in compute.yml +stackhpc_firewalld_rules: | + {% set stackhpc_firewalld_rules_verified = stackhpc_firewalld_rules_extra %} + {% for rule in stackhpc_firewalld_rules_default | unique %} + {% if rule | ansible.utils.remove_keys('state') not in stackhpc_firewalld_rules_verified | map('ansible.utils.remove_keys', 'state') | default([]) %} + {% if rule.network is not defined %} + {% set _ = stackhpc_firewalld_rules_verified.append(rule) %} + {% elif rule.network in network_interfaces and rule.network | net_zone %} + {% set _ = stackhpc_firewalld_rules_verified.append(rule) %} + {% endif %} + {% endif %} + {% endfor %} + {{ stackhpc_firewalld_rules_verified | list }} + +# A single list of default firewall rules, combining the enabled rules from +# stackhpc_firewalld_rules_template. This variable is designed to fail to +# template if any conflicting rules are found. +stackhpc_firewalld_rules_default: | + {% set stackhpc_firewalld_rules_formatted = [] %} + {% for ruleset in stackhpc_firewalld_rules_template %} + {% if ruleset.enabled | bool %} + {% for rule in ruleset.rules %} + {% if rule.zone is not defined %} + {% set rule = rule | combine({'zone': rule.network | net_zone }) %} + {% endif %} + {% if rule not in stackhpc_firewalld_rules_formatted %} + {% if rule | ansible.utils.remove_keys('state') in stackhpc_firewalld_rules_formatted | map('ansible.utils.remove_keys', 'state') %} + {% set _ = stackhpc_firewalld_rules_formatted.append({'state':'failure'}) %} + {% elif rule.network is not defined %} + {% set _ = stackhpc_firewalld_rules_formatted.append(rule) %} + {% elif rule.network in network_interfaces and rule.network | net_zone %} + {% set _ = stackhpc_firewalld_rules_formatted.append(rule) %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {{ undef(hint='ERROR: Conflicting firewall rules found') if ({'state':'failure'} in stackhpc_firewalld_rules_formatted) else stackhpc_firewalld_rules_formatted }} + +stackhpc_firewalld_rules_template: | + {{ stackhpc_common_firewalld_rules_template + + (stackhpc_controller_firewalld_rules_template if 'controllers' in group_names else []) + + (stackhpc_compute_firewalld_rules_template if 'compute' in group_names else []) + + (stackhpc_ceph_firewalld_rules_template if 'ceph' in group_names else []) + + (stackhpc_monitoring_firewalld_rules_template if 'monitoring' in group_names else []) + + (stackhpc_seed_firewalld_rules_template if 'seed' in group_names else []) + + (stackhpc_seed_hypervisor_firewalld_rules_template if 'seed-hypervisor' in group_names else []) + + (stackhpc_wazuh_manager_infra_vm_firewalld_rules_template if 'wazuh-manager' in group_names else []) + + (stackhpc_ansible_control_infra_vm_firewalld_rules_template if inventory_hostname == 'localhost' else []) }} + +############################################################################### +# Debug Vars + +# This variable is not applied anywhere. It exists for debugging purpouses +# only. Print it with: +# kayobe configuration dump --var-name stackhpc_firewalld_rules_debug +stackhpc_firewalld_rules_debug: | + {% set stackhpc_firewalld_services_debug = [] %} + {% for rule in stackhpc_firewalld_rules %} + {% if rule.service is defined %} + {% set _ = stackhpc_firewalld_services_debug.append(rule.service + ' ' + rule.state + ' ' + rule.zone | default()) %} + {% else %} + {% set _ = stackhpc_firewalld_services_debug.append(rule.port + ' ' + rule.state + ' ' + rule.zone | default()) %} + {% endif %} + {% endfor %} + {{ stackhpc_firewalld_services_debug | list }} + +############################################################################### +# Extra firewalld rules + +# Extra firewalld rules. Each item is a dict containing arguments to pass to +# the firewalld module. +# These rules have higher precidence than the +# default rules and are not validated before being applied. Use with caution. +# NOTE: The format of this variable is NOT the same as the +# stackhpc_*_firewalld_rules_template variables found elsewhere in this file. +stackhpc_firewalld_rules_extra: [] + +############################################################################### +# Common firewalld rules + +stackhpc_common_firewalld_rules_template: + # Common + - rules: + - service: ssh + network: "{{ admin_oc_net_name }}" + state: enabled + enabled: true + # Cockpit, dhcpv6-client, and SSH are enabled by default in firewalld + - rules: + - service: cockpit + zone: public + state: disabled + - service: dhcpv6-client + zone: public + state: disabled + - service: ssh + zone: public + state: disabled + enabled: "{{ admin_oc_net_name | net_zone != 'public' }}" + +############################################################################### +# Controller firewalld rules + +stackhpc_controller_firewalld_rules_template: + # Overcloud Ironic + - rules: + # Ironic inspector API + - port: 5050/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + # Ironic API + - port: 6385/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + - port: 8089/tcp + network: "{{ provision_wl_net_name }}" + state: enabled + - service: dhcp + network: "{{ provision_wl_net_name }}" + state: enabled + - service: ntp + network: "{{ provision_wl_net_name }}" + state: enabled + - service: tftp + network: "{{ provision_wl_net_name }}" + state: enabled + enabled: "{{ kolla_enable_ironic | bool }}" + # Designate + - rules: + - port: 53/tcp + network: "{{ public_net_name }}" + state: enabled + - port: 53/udp + network: "{{ public_net_name }}" + state: enabled + - port: 5354/tcp + network: "{{ public_net_name }}" + state: enabled + - port: 5354/udp + network: "{{ public_net_name }}" + state: enabled + enabled: "{{ kolla_enable_designate | bool }}" + # GENEVE + - rules: + - port: 6081/udp + network: "{{ tunnel_net_name }}" + state: enabled + enabled: "{{ 'geneve' in (kolla_neutron_ml2_type_drivers + kolla_neutron_ml2_tenant_network_types) and 'network' in group_names }}" + # VXLAN + - rules: + - port: 4789/udp + network: "{{ tunnel_net_name }}" + state: enabled + enabled: "{{ 'vxlan' in (kolla_neutron_ml2_type_drivers + kolla_neutron_ml2_tenant_network_types) and 'network' in group_names }}" + # Octavia + - rules: + - port: 5555/udp + network: "{{ octavia_net_name | default() }}" + state: enabled + enabled: "{{ kolla_enable_octavia | bool and octavia_net_name is not none }}" + # DHCP, Was required to create VMs at a customer site, need to work out condition + - rules: + - port: 67/udp + network: "{{ provision_oc_net_name }}" + state: enabled + enabled: true + +############################################################################### +# Compute firewalld rules + +stackhpc_compute_firewalld_rules_template: + # GENEVE + - rules: + - port: 6081/udp + network: "{{ tunnel_net_name }}" + state: enabled + enabled: "{{ ('geneve' in (kolla_neutron_ml2_type_drivers + kolla_neutron_ml2_tenant_network_types)) | bool }}" + # VXLAN + - rules: + - port: 4789/udp + network: "{{ tunnel_net_name }}" + state: enabled + enabled: "{{ ('vxlan' in (kolla_neutron_ml2_type_drivers + kolla_neutron_ml2_tenant_network_types)) | bool }}" + +############################################################################### +# Ceph firewalld rules + +# Port on which radosgw is exposed. +# See: https://stackhpc-kayobe-config.readthedocs.io/en/stackhpc-2024.1/configuration/cephadm.html#rados-gateways +stackhpc_ceph_firewalld_radosgw_port: 8100 + +stackhpc_ceph_firewalld_rules_template: + # Ceph Prometheus exporter + - rules: + - port: 9283/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + enabled: "{{ kolla_enable_prometheus_ceph_mgr_exporter | default(false) | bool and 'mgrs' in group_names }}" + # Ceph + - rules: + - service: ceph + network: "{{ storage_net_name }}" + state: enabled + - service: ceph + network: "{{ storage_mgmt_net_name }}" + state: enabled + - service: ceph-mon + network: "{{ storage_net_name }}" + state: "{{ 'enabled' if 'mons' in group_names else 'disabled' }}" + - port: "{{ stackhpc_ceph_firewalld_radosgw_port }}/tcp" + network: "{{ storage_net_name }}" + state: "{{ 'enabled' if 'rgws' in group_names else 'disabled' }}" + enabled: "{{ 'ceph' in group_names }}" + +############################################################################### +# Monitoring firewalld rules + +stackhpc_monitoring_firewalld_rules_template: [] + +############################################################################### +# Infra VM firewalld rules (Wazuh Manager) + +stackhpc_wazuh_manager_infra_vm_firewalld_rules_template: + - rules: + - port: 1514/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + - port: 1514/udp + network: "{{ provision_oc_net_name }}" + state: enabled + - port: 1515/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + - port: 443/tcp + network: "{{ wazuh_dashboard_net_name | default(provision_oc_net_name) }}" + state: enabled + - port: 9200/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + - port: 9300-9400/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + - port: 55000/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + enabled: true + +############################################################################### +# Infra VM firewalld rules (Ansible Control) + +stackhpc_ansible_control_infra_vm_firewalld_rules_template: [] + +############################################################################### +# Seed firewalld rules + +stackhpc_seed_firewalld_rules_template: + # Pulp server + - rules: + - port: "{{ pulp_port }}/tcp" + network: "{{ provision_oc_net_name }}" + state: enabled + enabled: "{{ seed_pulp_container_enabled | bool }}" + # Squid proxy + - rules: + - service: squid + network: "{{ provision_oc_net_name }}" + state: enabled + enabled: "{{ seed_squid_container_enabled | bool }}" + # Ironic + - rules: + # nginx + - port: 8080/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + # Ironic inspector API + - port: 5050/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + # Ironic API + - port: 6385/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + - service: dhcp + network: "{{ provision_oc_net_name }}" + state: enabled + - service: tftp + network: "{{ provision_oc_net_name }}" + state: enabled + - service: ntp + network: "{{ provision_oc_net_name }}" + state: enabled + enabled: true #FIXME: Make rules conditional on Bifrost deployment + # Redfish exporter + - rules: + - port: 9610/tcp + network: "{{ provision_oc_net_name }}" + state: enabled + enabled: "{{ stackhpc_enable_redfish_exporter | default(false) }}" + # TODO: Rules if SNAT enabled on seed + +############################################################################### +# Seed Hypervisor firewalld rules + +stackhpc_seed_hypervisor_firewalld_rules_template: [] diff --git a/etc/kayobe/networks.yml b/etc/kayobe/networks.yml index e58ab44cf..10feb408c 100644 --- a/etc/kayobe/networks.yml +++ b/etc/kayobe/networks.yml @@ -59,6 +59,12 @@ # hosts #cleaning_net_name: +# Name of the network used to manage octavia loadbalancers +#octavia_net_name: + +# Name of the network where Wazuh manager is exposed +#wazuh_dashboard_net_name: + ############################################################################### # Network definitions. diff --git a/releasenotes/notes/automated-firewalld-a95e7322fd457259.yaml b/releasenotes/notes/automated-firewalld-a95e7322fd457259.yaml new file mode 100644 index 000000000..4a06e6705 --- /dev/null +++ b/releasenotes/notes/automated-firewalld-a95e7322fd457259.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + A default firewall configuration is now included on an opt-in basis. The + rules are defined under ``etc/kayobe/inventory/group_vars/all/firewall``. + More information can be found `here + `__