Merge "adds firewalld configuration based on enabled services"
This commit is contained in:
commit
fc1404861d
@ -531,6 +531,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
|
||||
####################
|
||||
|
6
ansible/roles/haproxy-config/handlers/main.yml
Normal file
6
ansible/roles/haproxy-config/handlers/main.yml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
- name: Reload firewalld
|
||||
become: True
|
||||
service:
|
||||
name: "firewalld"
|
||||
state: reloaded
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -196,18 +196,21 @@ file. Example:
|
||||
}
|
||||
|
||||
|
||||
Disabling firewalls
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
Enabling/Disabling firewalls
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Kolla Ansible does not support configuration of host firewalls, and instead
|
||||
attempts to disable them.
|
||||
Kolla Ansible supports configuration of host firewalls.
|
||||
|
||||
On Debian family systems where the UFW firewall is enabled, a default policy
|
||||
will be added to allow all traffic.
|
||||
Currently only Firewalld is supported.
|
||||
|
||||
On Red Hat family systems where firewalld is installed, it will be disabled.
|
||||
On Debian family systems Firewalld will need to be installed beforehand.
|
||||
|
||||
This behaviour can be avoided by setting ``disable_firewall`` to ``false``.
|
||||
On Red Hat family systems firewalld should be installed by default.
|
||||
|
||||
To enable configuration of the system firewall set ``disable_firewall``
|
||||
to ``false`` and set ``enable_external_api_firewalld`` to ``true``.
|
||||
|
||||
For further information. See :doc:`../../user/security`
|
||||
|
||||
Creation of Python virtual environment
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -34,6 +34,28 @@ def service_enabled(context, service):
|
||||
return _call_bool_filter(context, enabled)
|
||||
|
||||
|
||||
@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": (
|
||||
|
@ -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,
|
||||
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user