aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ansible/group_vars/all.yml6
-rw-r--r--ansible/roles/haproxy-config/handlers/main.yml6
-rw-r--r--ansible/roles/haproxy-config/tasks/main.yml18
-rw-r--r--ansible/roles/loadbalancer/tasks/precheck.yml20
-rw-r--r--doc/source/reference/deployment-and-bootstrapping/bootstrap-servers.rst19
-rw-r--r--doc/source/user/security.rst81
-rw-r--r--etc/kolla/globals.yml9
-rw-r--r--kolla_ansible/filters.py23
-rw-r--r--kolla_ansible/tests/unit/test_filters.py405
-rw-r--r--releasenotes/notes/add-firewalld-rules-based-on-enabled-services-96dd418219953a05.yaml10
10 files changed, 589 insertions, 8 deletions
diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 09360bc87..e639537f2 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -528,6 +528,12 @@ internal_protocol: "{{ 'https' if kolla_enable_tls_internal | bool else 'http' }
# TODO(yoctozepto): Remove after Zed. Kept for compatibility only.
admin_protocol: "{{ internal_protocol }}"
+##################
+# Firewall options
+##################
+enable_external_api_firewalld: "false"
+external_api_firewalld_zone: "public"
+
####################
# OpenStack options
####################
diff --git a/ansible/roles/haproxy-config/handlers/main.yml b/ansible/roles/haproxy-config/handlers/main.yml
new file mode 100644
index 000000000..0f57dca44
--- /dev/null
+++ b/ansible/roles/haproxy-config/handlers/main.yml
@@ -0,0 +1,6 @@
+---
+- name: Reload firewalld
+ become: True
+ service:
+ name: "firewalld"
+ state: reloaded
diff --git a/ansible/roles/haproxy-config/tasks/main.yml b/ansible/roles/haproxy-config/tasks/main.yml
index 19920d463..ee1b2ef37 100644
--- a/ansible/roles/haproxy-config/tasks/main.yml
+++ b/ansible/roles/haproxy-config/tasks/main.yml
@@ -21,3 +21,21 @@
with_dict: "{{ project_services }}"
notify:
- Restart haproxy container
+
+- name: "Configuring firewall for {{ project_name }}"
+ firewalld:
+ offline: "yes"
+ permanent: "yes"
+ port: "{{ item.value.port }}/tcp"
+ state: "enabled"
+ zone: "{{ external_api_firewalld_zone }}"
+ become: true
+ when:
+ - enable_haproxy | bool
+ - item.value.enabled | bool
+ - item.value.port is defined
+ - item.value.external | default('false') | bool
+ - enable_external_api_firewalld | bool
+ with_dict: "{{ project_services | extract_haproxy_services }}"
+ notify:
+ - "Reload firewalld"
diff --git a/ansible/roles/loadbalancer/tasks/precheck.yml b/ansible/roles/loadbalancer/tasks/precheck.yml
index b81dcf28e..8aa85ff6e 100644
--- a/ansible/roles/loadbalancer/tasks/precheck.yml
+++ b/ansible/roles/loadbalancer/tasks/precheck.yml
@@ -838,3 +838,23 @@
- inventory_hostname in groups['loadbalancer']
- haproxy_stat.find('vitrage_api') == -1
- haproxy_vip_prechecks
+
+- name: Firewalld checks
+ block:
+ - name: Check if firewalld is running # noqa command-instead-of-module
+ become: true
+ command:
+ cmd: "systemctl is-active firewalld"
+ register: firewalld_is_active
+ changed_when: false
+ failed_when: false
+
+ - name: Fail if firewalld is not running
+ fail:
+ msg: >-
+ firewalld is not running.
+ Please install and configure firewalld.
+ when:
+ - firewalld_is_active.rc != 0
+ when:
+ - enable_external_api_firewalld | bool
diff --git a/doc/source/reference/deployment-and-bootstrapping/bootstrap-servers.rst b/doc/source/reference/deployment-and-bootstrapping/bootstrap-servers.rst
index 9a396a327..d433bdaab 100644
--- a/doc/source/reference/deployment-and-bootstrapping/bootstrap-servers.rst
+++ b/doc/source/reference/deployment-and-bootstrapping/bootstrap-servers.rst
@@ -196,18 +196,21 @@ file. Example:
}
-Disabling firewalls
-~~~~~~~~~~~~~~~~~~~
+Enabling/Disabling firewalls
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Kolla Ansible supports configuration of host firewalls.
+
+Currently only Firewalld is supported.
-Kolla Ansible does not support configuration of host firewalls, and instead
-attempts to disable them.
+On Debian family systems Firewalld will need to be installed beforehand.
-On Debian family systems where the UFW firewall is enabled, a default policy
-will be added to allow all traffic.
+On Red Hat family systems firewalld should be installed by default.
-On Red Hat family systems where firewalld is installed, it will be disabled.
+To enable configuration of the system firewall set ``disable_firewall``
+to ``false`` and set ``enable_external_api_firewalld`` to ``true``.
-This behaviour can be avoided by setting ``disable_firewall`` to ``false``.
+For further information. See :doc:`../../user/security`
Creation of Python virtual environment
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/doc/source/user/security.rst b/doc/source/user/security.rst
index e61b2410b..d0e185bce 100644
--- a/doc/source/user/security.rst
+++ b/doc/source/user/security.rst
@@ -76,3 +76,84 @@ via SSH) is default configuration owner and group in target nodes.
From Rocky release, Kolla support connection using any user which has
passwordless sudo capability. For setting custom owner user and group, user
can set ``config_owner_user`` and ``config_owner_group`` in ``globals.yml``.
+
+FirewallD
+~~~~~~~~~
+Prior to Zed, Kolla Ansible would disable any system firewall leaving
+configuration up to the end users. Firewalld is now supported and will
+configure external api ports for each enabled OpenStack service.
+
+The following variables should be configured in Kolla Ansible's
+``globals.yml``
+
+* external_api_firewalld_zone
+ * The default zone to configure ports on for external API Access
+ * String - defaults to the public zone
+* enable_external_api_firewalld
+ * Setting to true will enable external API ports configuration
+ * Bool - set to true or false
+* disable_firewall
+ * Setting to false will stop Kolla Ansible
+ from disabling the systems firewall
+ * Bool - set to true or false
+
+
+Prerequsites
+============
+Firewalld needs to be installed beforehand.
+
+Kayobe can be used to automate the installation and configuration of firewalld
+before running Kolla Ansible. If you do not use Kayobe you must ensure that
+that firewalld has been installed and setup correctly.
+
+You can check the current active zones by running the command below.
+If the output of the command is blank then no zones are configured as active.
+
+.. code-block:: console
+
+ sudo firewall-cmd --get-active-zones
+
+You should ensure that the system is reachable via SSH to avoid lockout,
+to add ssh to a particular zone run the following command.
+
+.. code-block:: console
+
+ sudo firewall-cmd --permanent --zone=<zone> --add-service=ssh
+
+You should also set the required interface on a particular zone by running the
+below command. This will mark the zone as active on the specified interface.
+
+.. code-block:: console
+
+ sudo firewall-cmd --permanent --zone=<zone> --change-interface=<interface>
+
+if more than one interface is required on a specific zone this can be achieved
+by running
+
+.. code-block:: console
+
+ sudo firewall-cmd --permanent --zone=public --add-interface=<additional interface>
+
+Any other ports that need to be opened on the system should be done
+before hand. The following command will add additional ports to a zone
+
+.. code-block:: console
+
+ sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
+
+Dependent on your infrastructure security policy you may wish to add a policy
+of drop on the public zone this can be achieved by running the following
+command.
+
+.. code-block:: console
+
+ sudo firewall-cmd --permanent --set-target=DROP --zone=public
+
+To apply changes to the system firewall run
+
+.. code-block:: console
+
+ sudo firewalld-cmd --reload
+
+For additional information and configuration please see:
+https://firewalld.org/documentation/man-pages/firewall-cmd.html
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index f80dc13c2..c92548711 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -206,6 +206,15 @@ workaround_ansible_issue_8743: yes
#default_container_healthcheck_retries: 3
#default_container_healthcheck_start_period: 5
+##################
+# Firewall options
+##################
+# Configures firewalld on both ubuntu and centos systems
+# for enabled services.
+# firewalld should be installed beforehand.
+# disable_firewall: "true"
+# enable_external_api_firewalld: "false"
+# external_api_firewalld_zone: "public"
#############
# TLS options
diff --git a/kolla_ansible/filters.py b/kolla_ansible/filters.py
index 7eb826b7c..88dcff5e9 100644
--- a/kolla_ansible/filters.py
+++ b/kolla_ansible/filters.py
@@ -35,6 +35,28 @@ def service_enabled(context, service):
@jinja2.pass_context
+def extract_haproxy_services(context, services):
+ """Return a Dict of haproxy services
+
+ :param context: Jinja2 Context object.
+ :param service: Services definition, dict.
+ :returns: A Dict.
+ """
+ haproxy = {}
+ for key in services:
+ service = services.get(key)
+ if service_enabled(context, service):
+ service_haproxy = service.get('haproxy')
+ if service_haproxy:
+ if not set(haproxy).isdisjoint(set(service_haproxy)):
+ raise exception.FilterError(
+ "haproxy service names should be unique")
+ haproxy.update(service_haproxy)
+
+ return haproxy
+
+
+@jinja2.pass_context
def service_mapped_to_host(context, service):
"""Return whether a service is mapped to this host.
@@ -89,6 +111,7 @@ def select_services_enabled_and_mapped_to_host(context, services):
def get_filters():
return {
+ "extract_haproxy_services": extract_haproxy_services,
"service_enabled": service_enabled,
"service_mapped_to_host": service_mapped_to_host,
"service_enabled_and_mapped_to_host": (
diff --git a/kolla_ansible/tests/unit/test_filters.py b/kolla_ansible/tests/unit/test_filters.py
index 859cfd7aa..c6c6adf75 100644
--- a/kolla_ansible/tests/unit/test_filters.py
+++ b/kolla_ansible/tests/unit/test_filters.py
@@ -110,6 +110,411 @@ class TestFilters(unittest.TestCase):
filters.service_mapped_to_host, self.context,
service)
+ def test_extract_haproxy_services_empty_dict(self):
+ example_service = {}
+ actual = filters.extract_haproxy_services(
+ self.context, example_service)
+ # No change
+ self.assertDictEqual({}, actual)
+
+ def test_extract_haproxy_services_no_haproxy_dict(self):
+ example_service = {
+ "keystone-ssh": {
+ "container_name": "keystone_ssh",
+ "dimensions": {},
+ "enabled": True,
+ "group": "keystone",
+ "healthcheck": {
+ "interval": "30",
+ "retries": "3",
+ "start_period": "5",
+ "test": [
+ "CMD-SHELL",
+ "healthcheck_listen sshd 8023"
+ ],
+ "timeout": "30"
+ },
+ "image": "keystone-ssh:latest",
+ "volumes": [
+ "/etc/kolla/keystone-ssh/:/var/lib/kolla/config_files/:ro",
+ "/etc/localtime:/etc/localtime:ro",
+ "",
+ "kolla_logs:/var/log/kolla/",
+ "keystone_fernet_tokens:/etc/keystone/fernet-keys"
+ ]
+ }
+ }
+ actual = filters.extract_haproxy_services(self.context,
+ example_service)
+ self.assertDictEqual({}, actual)
+
+ def test_extract_haproxy_services_haproxy_dict(self):
+ example_service = {
+ "keystone": {
+ "container_name": "keystone",
+ "dimensions": {},
+ "enabled": True,
+ "group": "keystone",
+ "haproxy": {
+ "keystone_admin": {
+ "enabled": True,
+ "external": False,
+ "listen_port": "35357",
+ "mode": "http",
+ "port": "35357",
+ "tls_backend": True
+ },
+ "keystone_external": {
+ "backend_http_extra": [],
+ "enabled": True,
+ "external": True,
+ "listen_port": "5000",
+ "mode": "http",
+ "port": "5000",
+ "tls_backend": True
+ },
+ "keystone_internal": {
+ "backend_http_extra": [],
+ "enabled": True,
+ "external": False,
+ "listen_port": "5000",
+ "mode": "http",
+ "port": "5000",
+ "tls_backend": True
+ }
+ },
+ "healthcheck": {
+ "interval": "30",
+ "retries": "3",
+ "start_period": "5",
+ "test": [
+ "CMD-SHELL",
+ "healthcheck_curl https://1.2.3.4:5000"
+ ],
+ "timeout": "30"
+ },
+ "image": "keystone:latest",
+ "volumes": [
+ "/etc/kolla/keystone/:/var/lib/kolla/config_files/:ro",
+ "/etc/localtime:/etc/localtime:ro",
+ "",
+ "",
+ "kolla_logs:/var/log/kolla/",
+ "keystone_fernet_tokens:/etc/keystone/fernet-keys"
+ ]
+ }
+ }
+ expected = {
+ 'keystone_admin': {
+ 'enabled': True,
+ 'external': False,
+ 'listen_port': '35357',
+ 'mode': 'http',
+ 'port': '35357',
+ 'tls_backend': True
+ },
+ 'keystone_external': {
+ 'backend_http_extra': [],
+ 'enabled': True,
+ 'external': True,
+ 'listen_port': '5000',
+ 'mode': 'http',
+ 'port': '5000',
+ 'tls_backend': True
+ },
+ 'keystone_internal': {
+ 'backend_http_extra': [],
+ 'enabled': True,
+ 'external': False,
+ 'listen_port': '5000',
+ 'mode': 'http',
+ 'port': '5000',
+ 'tls_backend': True
+ }
+ }
+ actual = filters.extract_haproxy_services(self.context,
+ example_service)
+ self.assertDictEqual(expected, actual)
+
+ def test_extract_two_services_with_haproxy_dict(self):
+ example_service = {
+ "glance-api": {
+ "container_name": "glance_api",
+ "dimensions": {},
+ "enabled": True,
+ "environment": {
+ "http_proxy": "",
+ "https_proxy": "",
+ "no_proxy": "127.0.0.1,localhost,1.2.3.4,1.2.3.4"
+ },
+ "group": "glance-api",
+ "haproxy": {
+ "glance_api": {
+ "backend_http_extra": [
+ "timeout server 6h"
+ ],
+ "custom_member_list": [
+ "server someserver 1.2.3.4:9292 "
+ "check inter 2000 rise 2 fall 5",
+ ""
+ ],
+ "enabled": False,
+ "external": False,
+ "frontend_http_extra": [
+ "timeout client 6h"
+ ],
+ "mode": "http",
+ "port": "9292"
+ },
+ "glance_api_external": {
+ "backend_http_extra": [
+ "timeout server 6h"
+ ],
+ "custom_member_list": [
+ "server someserver 1.2.3.4:9292 "
+ "check inter 2000 rise 2 fall 5",
+ ""
+ ],
+ "enabled": False,
+ "external": True,
+ "frontend_http_extra": [
+ "timeout client 6h"
+ ],
+ "mode": "http",
+ "port": "9292"
+ }
+ },
+ "healthcheck": {
+ "interval": "30",
+ "retries": "3",
+ "start_period": "5",
+ "test": [
+ "CMD-SHELL",
+ "healthcheck_curl http://localhost:9292"
+ ],
+ "timeout": "30"
+ },
+ "host_in_groups": True,
+ "image": "centos-source-glance-api:latest",
+ "privileged": False,
+ "volumes": [
+ "/etc/localtime:/etc/localtime:ro",
+ "",
+ "glance:/var/lib/glance/",
+ "",
+ "kolla_logs:/var/log/kolla/",
+ "",
+ ""
+ ]
+ },
+ "glance-tls-proxy": {
+ "container_name": "glance_tls_proxy",
+ "dimensions": {},
+ "enabled": True,
+ "group": "glance-api",
+ "haproxy": {
+ "glance_tls_proxy": {
+ "backend_http_extra": [
+ "timeout server 6h"
+ ],
+ "custom_member_list": [
+ "server someserver 1.2.3.4:9292 "
+ "check inter 2000 rise 2 fall 5 ssl verify "
+ "required ca-file ca-bundle.trust.crt",
+ ""
+ ],
+ "enabled": True,
+ "external": False,
+ "frontend_http_extra": [
+ "timeout client 6h"
+ ],
+ "mode": "http",
+ "port": "9292",
+ "tls_backend": "yes"
+ },
+ "glance_tls_proxy_external": {
+ "backend_http_extra": [
+ "timeout server 6h"
+ ],
+ "custom_member_list": [
+ "server someserver 1.2.3.4:9292 "
+ "check inter 2000 rise 2 fall 5 ssl verify "
+ "required ca-file ca-bundle.trust.crt",
+ ""
+ ],
+ "enabled": True,
+ "external": True,
+ "frontend_http_extra": [
+ "timeout client 6h"
+ ],
+ "mode": "http",
+ "port": "9292",
+ "tls_backend": "yes"
+ }
+ },
+ "healthcheck": {
+ "interval": "30",
+ "retries": "3",
+ "start_period": "5",
+ "test": [
+ "CMD-SHELL",
+ "healthcheck_curl -u openstack:asdf 1.2.3.4:9293"
+ ],
+ "timeout": "30"
+ },
+ "host_in_groups": True,
+ "image": "centos-source-haproxy:latest",
+ "volumes": [
+ "/etc/localtime:/etc/localtime:ro",
+ "",
+ "kolla_logs:/var/log/kolla/"
+ ]
+ }
+ }
+ expected = {
+ "glance_api": {
+ "backend_http_extra": [
+ "timeout server 6h"
+ ],
+ 'custom_member_list': ['server someserver '
+ '1.2.3.4:9292 check inter 2000 '
+ 'rise 2 fall 5',
+ ''],
+ "enabled": False,
+ "external": False,
+ "frontend_http_extra": [
+ "timeout client 6h"
+ ],
+ "mode": "http",
+ "port": "9292"
+ },
+ "glance_api_external": {
+ "backend_http_extra": [
+ "timeout server 6h"
+ ],
+ 'custom_member_list': ['server someserver '
+ '1.2.3.4:9292 check inter 2000 '
+ 'rise 2 fall 5',
+ ''],
+ "enabled": False,
+ "external": True,
+ "frontend_http_extra": [
+ "timeout client 6h"
+ ],
+ "mode": "http",
+ "port": "9292"
+ },
+ "glance_tls_proxy": {
+ "backend_http_extra": [
+ "timeout server 6h"
+ ],
+ 'custom_member_list': ['server someserver 1.2.3.4:9292 '
+ 'check inter 2000 rise 2 fall 5 '
+ 'ssl verify required ca-file '
+ 'ca-bundle.trust.crt',
+ ''],
+ "enabled": True,
+ "external": False,
+ "frontend_http_extra": [
+ "timeout client 6h"
+ ],
+ "mode": "http",
+ "port": "9292",
+ "tls_backend": "yes"
+ },
+ "glance_tls_proxy_external": {
+ "backend_http_extra": [
+ "timeout server 6h"
+ ],
+ 'custom_member_list': ['server someserver 1.2.3.4:9292 '
+ 'check inter 2000 rise 2 fall 5 '
+ 'ssl verify required ca-file '
+ 'ca-bundle.trust.crt',
+ ''],
+
+ "enabled": True,
+ "external": True,
+ "frontend_http_extra": [
+ "timeout client 6h"
+ ],
+ "mode": "http",
+ "port": "9292",
+ "tls_backend": "yes"
+ }
+ }
+ actual = filters.extract_haproxy_services(self.context,
+ example_service)
+ self.assertDictEqual(expected, actual)
+
+ def test_extract_haproxy_services_haproxy_dict_duplicate(self):
+ example_service = {
+ "keystone": {
+ "container_name": "keystone",
+ "dimensions": {},
+ "enabled": True,
+ "group": "keystone",
+ "haproxy": {
+ "keystone_admin": {
+ "enabled": True,
+ "external": False,
+ "listen_port": "35357",
+ "mode": "http",
+ "port": "35357",
+ "tls_backend": True
+ },
+ },
+ "healthcheck": {
+ "interval": "30",
+ "retries": "3",
+ "start_period": "5",
+ "test": [
+ "CMD-SHELL",
+ "healthcheck_curl https://1.2.3.4:5000"
+ ],
+ "timeout": "30"
+ },
+ "image": "keystone:latest",
+ "volumes": [
+ "/etc/kolla/keystone/:/var/lib/kolla/config_files/:ro",
+ "kolla_logs:/var/log/kolla/"
+ ]
+ },
+ "keystone-ssh": {
+ "container_name": "keystone_ssh",
+ "dimensions": {},
+ "enabled": True,
+ "group": "keystone",
+ "haproxy": {
+ "keystone_admin": {
+ "enabled": True,
+ "external": False,
+ "listen_port": "35357",
+ "mode": "http",
+ "port": "35357",
+ "tls_backend": True
+ },
+ },
+ "healthcheck": {
+ "interval": "30",
+ "retries": "3",
+ "start_period": "5",
+ "test": [
+ "CMD-SHELL",
+ "healthcheck_listen sshd 8023"
+ ],
+ "timeout": "30"
+ },
+ "image": "keystone-ssh:latest",
+ "volumes": [
+ "/etc/kolla/keystone-ssh/:/var/lib/kolla/config_files/:ro",
+ "kolla_logs:/var/log/kolla/"
+ ]
+ }
+ }
+ self.assertRaises(exception.FilterError,
+ filters.extract_haproxy_services,
+ self.context, example_service)
+
@mock.patch.object(filters, 'service_enabled')
@mock.patch.object(filters, 'service_mapped_to_host')
def test_service_enabled_and_mapped_to_host(self, mock_mapped,
diff --git a/releasenotes/notes/add-firewalld-rules-based-on-enabled-services-96dd418219953a05.yaml b/releasenotes/notes/add-firewalld-rules-based-on-enabled-services-96dd418219953a05.yaml
new file mode 100644
index 000000000..5123b5f1a
--- /dev/null
+++ b/releasenotes/notes/add-firewalld-rules-based-on-enabled-services-96dd418219953a05.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ Enables configuring firewalld for external API services.
+ Extracts the required services and checks the external port,
+ then adds the ports to a firewalld zone.
+ Assumes that firewalld has been installed and configured beforehand.
+ The variable disable_firewall, is disabled by default to preserve
+ backwards compatibility.
+ But its good practice to have the system firewall configured.