Adds TLS/SSL Version Support to Murano Agent.
Already implemented for Murano, but need Murano Agent support as well. Currently, Murano supports enabling SSL in Murano Engine [0], but does not have a param for the user to specify the desired SSL version. This is important because some versions of SSL are less secure than others [1]. This patch adds ssl_version support to Murano Agent. [0] https://docs.openstack.org/developer/murano/administrator-guide/deploy_murano/configure_ssl.html [1] https://www.wolfssl.com/wolfSSL/Blog/Entries/2010/10/7_Differences_between_SSL_and_TLS_Protocol_Versions.html Change-Id: I410a38d3c8294ce63c15ae98f627fa5c69a3d118 Partially-Implements: blueprint add-tls-support Depends-On: I71c36c455cde658f402a19c59d7966cee8544cf1
This commit is contained in:
parent
e34c93fc17
commit
20213e0061
|
@ -118,6 +118,7 @@ class MuranoAgent(service.Service):
|
|||
'port': rabbitmq.port,
|
||||
'virtual_host': rabbitmq.virtual_host,
|
||||
'ssl': rabbitmq.ssl,
|
||||
'ssl_version': rabbitmq.ssl_version,
|
||||
'ca_certs': rabbitmq.ca_certs.strip() or None,
|
||||
'insecure': rabbitmq.insecure
|
||||
}
|
||||
|
|
|
@ -56,6 +56,12 @@ rabbit_opts = [
|
|||
help='Boolean flag to enable SSL communication through the '
|
||||
'RabbitMQ broker between murano-engine and guest agents.',
|
||||
default=False),
|
||||
cfg.StrOpt('ssl_version',
|
||||
default='',
|
||||
help='SSL version to use (valid only if SSL enabled). '
|
||||
'Valid values are TLSv1 and SSLv23. SSLv2, SSLv3, '
|
||||
'TLSv1_1, and TLSv1_2 may be available on some '
|
||||
'distributions.'),
|
||||
cfg.StrOpt('ca_certs',
|
||||
help='SSL cert file (valid only if SSL enabled).',
|
||||
default=''),
|
||||
|
|
|
@ -19,13 +19,14 @@ import ssl as ssl_module
|
|||
import anyjson
|
||||
import eventlet
|
||||
import kombu
|
||||
from oslo_service import sslutils
|
||||
|
||||
from muranoagent.common.messaging import subscription
|
||||
|
||||
|
||||
class MqClient(object):
|
||||
def __init__(self, login, password, host, port, virtual_host,
|
||||
ssl=False, ca_certs=None, insecure=False):
|
||||
ssl=False, ssl_version=None, ca_certs=None, insecure=False):
|
||||
ssl_params = None
|
||||
|
||||
if ssl:
|
||||
|
@ -35,11 +36,19 @@ class MqClient(object):
|
|||
cert_reqs = ssl_module.CERT_OPTIONAL
|
||||
else:
|
||||
cert_reqs = ssl_module.CERT_NONE
|
||||
|
||||
ssl_params = {
|
||||
'ca_certs': ca_certs,
|
||||
'cert_reqs': cert_reqs
|
||||
}
|
||||
|
||||
if ssl_version:
|
||||
key = ssl_version.lower()
|
||||
try:
|
||||
ssl_params['ssl_version'] = sslutils._SSL_PROTOCOLS[key]
|
||||
except KeyError:
|
||||
raise RuntimeError("Invalid SSL version: %s" % ssl_version)
|
||||
|
||||
# Time interval after which RabbitMQ will disconnect client if no
|
||||
# heartbeats were received. Usually client sends 2 heartbeats during
|
||||
# this interval. Using random to make it less lucky that many agents
|
||||
|
|
|
@ -14,10 +14,14 @@
|
|||
|
||||
import fixtures
|
||||
import mock
|
||||
import ssl as ssl_module
|
||||
|
||||
from oslo_service import sslutils
|
||||
|
||||
from muranoagent import app
|
||||
from muranoagent import bunch
|
||||
from muranoagent.common import config as cfg
|
||||
from muranoagent.common.messaging import mqclient
|
||||
from muranoagent import exceptions as exc
|
||||
from muranoagent.tests.unit import base
|
||||
from muranoagent.tests.unit import execution_plan as ep
|
||||
|
@ -32,7 +36,8 @@ class TestApp(base.MuranoAgentTestCase, fixtures.FunctionFixture):
|
|||
super(TestApp, self).setUp()
|
||||
mock_path.return_value = True
|
||||
self.agent = app.MuranoAgent()
|
||||
CONF.set_override('storage', 'cache')
|
||||
CONF.set_override('storage', 'cache', enforce_type=True)
|
||||
self.addCleanup(CONF.clear_override, 'storage')
|
||||
|
||||
def test_verify_execution_plan_downloable(self):
|
||||
template = self.useFixture(ep.ExPlanDownloable()).execution_plan
|
||||
|
@ -80,3 +85,63 @@ class TestApp(base.MuranoAgentTestCase, fixtures.FunctionFixture):
|
|||
template = self.useFixture(ep.ExPlanBerkWrongVersion()).execution_plan
|
||||
self.assertRaises(exc.IncorrectFormat,
|
||||
self.agent._verify_plan, template)
|
||||
|
||||
@mock.patch.object(mqclient, 'random', autospec=True)
|
||||
@mock.patch.object(mqclient, 'kombu', autospec=True)
|
||||
def test_rmq_client_initialization_with_ssl_version(self, mock_kombu,
|
||||
mock_random):
|
||||
expected_heartbeat = 20 # 20 = 20 + 20 * 0, due to mocked value below.
|
||||
mock_random.random.return_value = 0
|
||||
|
||||
ssl_versions = (
|
||||
('tlsv1', getattr(ssl_module, 'PROTOCOL_TLSv1', None)),
|
||||
('tlsv1_1', getattr(ssl_module, 'PROTOCOL_TLSv1_1', None)),
|
||||
('tlsv1_2', getattr(ssl_module, 'PROTOCOL_TLSv1_2', None)),
|
||||
('sslv2', getattr(ssl_module, 'PROTOCOL_SSLv2', None)),
|
||||
('sslv23', getattr(ssl_module, 'PROTOCOL_SSLv23', None)),
|
||||
('sslv3', getattr(ssl_module, 'PROTOCOL_SSLv3', None)))
|
||||
exception_count = 0
|
||||
|
||||
for ssl_name, ssl_version in ssl_versions:
|
||||
ssl_kwargs = {
|
||||
'login': 'test_login',
|
||||
'password': 'test_password',
|
||||
'host': 'test_host',
|
||||
'port': 'test_port',
|
||||
'virtual_host': 'test_virtual_host',
|
||||
'ssl': True,
|
||||
'ssl_version': ssl_name,
|
||||
'ca_certs': ['cert1'],
|
||||
'insecure': False
|
||||
}
|
||||
|
||||
# If a ssl_version is not valid, a RuntimeError is thrown.
|
||||
# According to the ssl_version docs in config.py, certain versions
|
||||
# of TLS may be available depending on the system. So, just
|
||||
# check that at least 1 ssl_version works.
|
||||
if ssl_version is None:
|
||||
e = self.assertRaises(RuntimeError, mqclient.MqClient,
|
||||
**ssl_kwargs)
|
||||
self.assertEqual('Invalid SSL version: %s' % ssl_name,
|
||||
e.__str__())
|
||||
exception_count += 1
|
||||
continue
|
||||
|
||||
self.ssl_client = mqclient.MqClient(**ssl_kwargs)
|
||||
|
||||
mock_kombu.Connection.assert_called_once_with(
|
||||
'amqp://{0}:{1}@{2}:{3}/{4}'.format(
|
||||
'test_login', 'test_password', 'test_host', 'test_port',
|
||||
'test_virtual_host'),
|
||||
heartbeat=expected_heartbeat,
|
||||
ssl={'ca_certs': ['cert1'],
|
||||
'cert_reqs': ssl_module.CERT_REQUIRED,
|
||||
'ssl_version': ssl_version})
|
||||
self.assertEqual(
|
||||
mock_kombu.Connection(), self.ssl_client._connection)
|
||||
self.assertIsNone(self.ssl_client._channel)
|
||||
self.assertFalse(self.ssl_client._connected)
|
||||
mock_kombu.Connection.reset_mock()
|
||||
|
||||
# Check that at least one ssl_version worked.
|
||||
self.assertGreater(len(ssl_versions), exception_count)
|
||||
|
|
Loading…
Reference in New Issue