Merge "Adds TLS/SSL Version Support to Murano Agent."

This commit is contained in:
Jenkins 2017-03-23 01:32:45 +00:00 committed by Gerrit Code Review
commit d5dd8b3657
4 changed files with 83 additions and 2 deletions

View File

@ -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
}

View File

@ -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=''),

View File

@ -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

View File

@ -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)