From 384738a92d1d840bec762086ec10523c52f7497b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Beraud?= Date: Thu, 24 Jun 2021 12:53:55 +0200 Subject: Add a new option to enforce the OpenSSL FIPS mode This option ``ssl_enforce_fips_mode`` allow us to enforce the FIPS mode if supported by the version of python in use. https://en.wikipedia.org/wiki/Federal_Information_Processing_Standards Change-Id: I50c7de71bfd38137eb83d23e910298946507ce9f --- doc/source/admin/rabbit.rst | 1 + oslo_messaging/_drivers/impl_rabbit.py | 23 +++++++++ oslo_messaging/exceptions.py | 4 ++ oslo_messaging/tests/drivers/test_impl_rabbit.py | 60 ++++++++++++++++++++++ .../notes/enforce_fips_mode-07dd259eb8a73c2b.yaml | 10 ++++ 5 files changed, 98 insertions(+) create mode 100644 releasenotes/notes/enforce_fips_mode-07dd259eb8a73c2b.yaml diff --git a/doc/source/admin/rabbit.rst b/doc/source/admin/rabbit.rst index 142bdf7..9fee0d1 100644 --- a/doc/source/admin/rabbit.rst +++ b/doc/source/admin/rabbit.rst @@ -266,3 +266,4 @@ Security Options - :oslo.config:option:`oslo_messaging_rabbit.ssl_key_file` - :oslo.config:option:`oslo_messaging_rabbit.ssl_cert_file` - :oslo.config:option:`oslo_messaging_rabbit.rabbit_login_method` +- :oslo.config:option:`oslo_messaging_rabbit.ssl_enforce_fips_mode` diff --git a/oslo_messaging/_drivers/impl_rabbit.py b/oslo_messaging/_drivers/impl_rabbit.py index 9d99822..aa66b68 100644 --- a/oslo_messaging/_drivers/impl_rabbit.py +++ b/oslo_messaging/_drivers/impl_rabbit.py @@ -87,6 +87,15 @@ rabbit_opts = [ deprecated_name='kombu_ssl_ca_certs', help='SSL certification authority file ' '(valid only if SSL enabled).'), + cfg.BoolOpt('ssl_enforce_fips_mode', + default=False, + help='Global toggle for enforcing the OpenSSL FIPS mode. ' + 'This feature requires Python support. ' + 'This is available in Python 3.9 in all ' + 'environments and may have been backported to older ' + 'Python versions on select environments. If the Python ' + 'executable used does not support OpenSSL FIPS mode, ' + 'an exception will be raised.'), cfg.BoolOpt('heartbeat_in_pthread', default=True, help="Run the health check heartbeat thread " @@ -490,6 +499,7 @@ class Connection(object): self.kombu_failover_strategy = driver_conf.kombu_failover_strategy self.kombu_compression = driver_conf.kombu_compression self.heartbeat_in_pthread = driver_conf.heartbeat_in_pthread + self.ssl_enforce_fips_mode = driver_conf.ssl_enforce_fips_mode self.enable_cancel_on_failover = driver_conf.enable_cancel_on_failover if self.heartbeat_in_pthread: @@ -527,6 +537,19 @@ class Connection(object): self.ssl_cert_file = driver_conf.ssl_cert_file self.ssl_ca_file = driver_conf.ssl_ca_file + if self.ssl_enforce_fips_mode: + if hasattr(ssl, 'FIPS_mode'): + LOG.info("Enforcing the use of the OpenSSL FIPS mode") + ssl.FIPS_mode_set(1) + else: + raise exceptions.ConfigurationError( + "OpenSSL FIPS mode is not supported by your Python " + "version. You must either change the Python " + "executable used to a version with FIPS mode " + "support or disable FIPS mode by setting the " + "'[oslo_messaging_rabbit] ssl_enforce_fips_mode' " + "configuration option to 'False'.") + self._url = '' if url.hosts: if url.transport.startswith('kombu+'): diff --git a/oslo_messaging/exceptions.py b/oslo_messaging/exceptions.py index 48645b3..391fe46 100644 --- a/oslo_messaging/exceptions.py +++ b/oslo_messaging/exceptions.py @@ -47,3 +47,7 @@ class MessageUndeliverable(Exception): self.exchange = exchange self.routing_key = routing_key self.message = message + + +class ConfigurationError(Exception): + """Raised when messaging isn't configured correctly.""" diff --git a/oslo_messaging/tests/drivers/test_impl_rabbit.py b/oslo_messaging/tests/drivers/test_impl_rabbit.py index e035150..c2ffbc6 100644 --- a/oslo_messaging/tests/drivers/test_impl_rabbit.py +++ b/oslo_messaging/tests/drivers/test_impl_rabbit.py @@ -31,6 +31,7 @@ import oslo_messaging from oslo_messaging._drivers import amqpdriver from oslo_messaging._drivers import common as driver_common from oslo_messaging._drivers import impl_rabbit as rabbit_driver +from oslo_messaging.exceptions import ConfigurationError from oslo_messaging.exceptions import MessageDeliveryFailure from oslo_messaging.tests import utils as test_utils from oslo_messaging.transport import DriverLoadFailure @@ -205,6 +206,65 @@ class TestRabbitDriverLoadSSL(test_utils.BaseTestCase): ) +class TestRabbitDriverLoadSSLWithFIPS(test_utils.BaseTestCase): + scenarios = [ + ('ssl_fips_mode', dict(options=dict(ssl=True, + ssl_enforce_fips_mode=True), + expected=True)), + ] + + @mock.patch('oslo_messaging._drivers.impl_rabbit.Connection' + '.ensure_connection') + @mock.patch('kombu.connection.Connection') + def test_driver_load_with_fips_supported(self, + connection_klass, fake_ensure): + self.config(ssl=True, ssl_enforce_fips_mode=True, + group="oslo_messaging_rabbit") + transport = oslo_messaging.get_transport(self.conf, + 'kombu+memory:////') + self.addCleanup(transport.cleanup) + + with mock.patch.object(ssl, 'FIPS_mode', + create=True, return_value=True): + with mock.patch.object(ssl, 'FIPS_mode_set', create=True): + + connection = transport._driver._get_connection() + connection_klass.assert_called_once_with( + 'memory:///', transport_options={ + 'client_properties': { + 'capabilities': { + 'connection.blocked': True, + 'consumer_cancel_notify': True, + 'authentication_failure_close': True, + }, + 'connection_name': connection.name}, + 'confirm_publish': True, + 'on_blocked': mock.ANY, + 'on_unblocked': mock.ANY}, + ssl=self.expected, login_method='AMQPLAIN', + heartbeat=60, failover_strategy='round-robin' + ) + + @mock.patch('oslo_messaging._drivers.impl_rabbit.Connection' + '.ensure_connection') + @mock.patch('oslo_messaging._drivers.impl_rabbit.ssl') + @mock.patch('kombu.connection.Connection') + def test_fips_unsupported(self, connection_klass, fake_ssl, fake_ensure): + self.config(ssl=True, ssl_enforce_fips_mode=True, + group="oslo_messaging_rabbit") + transport = oslo_messaging.get_transport(self.conf, + 'kombu+memory:////') + self.addCleanup(transport.cleanup) + + del fake_ssl.FIPS_mode + + # We do this test only if FIPS mode is not supported to + # ensure that we hard fail. + self.assertRaises( + ConfigurationError, + transport._driver._get_connection) + + class TestRabbitPublisher(test_utils.BaseTestCase): @mock.patch('kombu.messaging.Producer.publish') def test_send_with_timeout(self, fake_publish): diff --git a/releasenotes/notes/enforce_fips_mode-07dd259eb8a73c2b.yaml b/releasenotes/notes/enforce_fips_mode-07dd259eb8a73c2b.yaml new file mode 100644 index 0000000..ba6ac7f --- /dev/null +++ b/releasenotes/notes/enforce_fips_mode-07dd259eb8a73c2b.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Adding a new option, ``[oslo_messaging_rabbit] ssl_enforce_fips_mode``, to + the rabbitmq driver to enforce the OpenSSL FIPS mode if supported by the + version of Python. +security: + - | + We are now able to enforce the OpenSSL FIPS mode by using + ``[oslo_messaging_rabbit] ssl_enforce_fips_mode``. -- cgit v1.2.1