From 86792054277232e72526bb9a315a823ba4d94033 Mon Sep 17 00:00:00 2001 From: Jakub Libosvar Date: Mon, 17 Mar 2014 15:02:58 +0100 Subject: [PATCH] Add support for https requests on nova metadata Adds new config value for accessing nova metadata api with SSL. In case nova api requires client certificate other config values were added providing client certificate and client private key. DocImpact Closes-bug: #1293587 Change-Id: I782a12eb77553f4369b782071b4ad19efb82e5e2 --- etc/metadata_agent.ini | 14 +++++++++++ neutron/agent/metadata/agent.py | 30 +++++++++++++++++++---- neutron/tests/unit/test_metadata_agent.py | 12 +++++++++ 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/etc/metadata_agent.ini b/etc/metadata_agent.ini index c2f59cd283..2cd429aba0 100644 --- a/etc/metadata_agent.ini +++ b/etc/metadata_agent.ini @@ -22,6 +22,20 @@ admin_password = %SERVICE_PASSWORD% # TCP Port used by Nova metadata server # nova_metadata_port = 8775 +# Which protocol to use for requests to Nova metadata server, http or https +# nova_metadata_protocol = http + +# Whether insecure SSL connection should be accepted for Nova metadata server +# requests +# nova_metadata_insecure = False + +# Client certificate for nova api, needed when nova api requires client +# certificates +# nova_client_cert = + +# Private key for nova client certificate +# nova_client_priv_key = + # When proxying metadata requests, Neutron signs the Instance-ID header with a # shared secret to prevent spoofing. You may select any string for a secret, # but it must match here and in the configuration used by the Nova Metadata diff --git a/neutron/agent/metadata/agent.py b/neutron/agent/metadata/agent.py index 23f4f27937..dd54a59959 100644 --- a/neutron/agent/metadata/agent.py +++ b/neutron/agent/metadata/agent.py @@ -79,7 +79,20 @@ class MetadataProxyHandler(object): cfg.StrOpt('metadata_proxy_shared_secret', default='', help=_('Shared secret to sign instance-id request'), - secret=True) + secret=True), + cfg.StrOpt('nova_metadata_protocol', + default='http', + choices=['http', 'https'], + help=_("Protocol to access nova metadata, http or https")), + cfg.BoolOpt('nova_metadata_insecure', default=False, + help=_("Allow to perform insecure SSL (https) requests to " + "nova metadata")), + cfg.StrOpt('nova_client_cert', + default='', + help=_("Client certificate for nova metadata api server.")), + cfg.StrOpt('nova_client_priv_key', + default='', + help=_("Private key of client certificate.")) ] def __init__(self, conf): @@ -152,15 +165,22 @@ class MetadataProxyHandler(object): 'X-Instance-ID-Signature': self._sign_instance_id(instance_id) } + nova_ip_port = '%s:%s' % (self.conf.nova_metadata_ip, + self.conf.nova_metadata_port) url = urlparse.urlunsplit(( - 'http', - '%s:%s' % (self.conf.nova_metadata_ip, - self.conf.nova_metadata_port), + self.conf.nova_metadata_protocol, + nova_ip_port, req.path_info, req.query_string, '')) - h = httplib2.Http() + h = httplib2.Http(ca_certs=self.conf.auth_ca_cert, + disable_ssl_certificate_validation= + self.conf.nova_metadata_insecure) + if self.conf.nova_client_cert and self.conf.nova_client_priv_key: + h.add_certificate(self.conf.nova_client_priv_key, + self.conf.nova_client_cert, + nova_ip_port) resp, content = h.request(url, method=req.method, headers=headers, body=req.body) diff --git a/neutron/tests/unit/test_metadata_agent.py b/neutron/tests/unit/test_metadata_agent.py index a87cdfd3f9..d7fab34a21 100644 --- a/neutron/tests/unit/test_metadata_agent.py +++ b/neutron/tests/unit/test_metadata_agent.py @@ -41,6 +41,10 @@ class FakeConf(object): nova_metadata_ip = '9.9.9.9' nova_metadata_port = 8775 metadata_proxy_shared_secret = 'secret' + nova_metadata_protocol = 'http' + nova_metadata_insecure = True + nova_client_cert = 'nova_cert' + nova_client_priv_key = 'nova_priv_key' class TestMetadataProxyHandler(base.BaseTestCase): @@ -211,7 +215,15 @@ class TestMetadataProxyHandler(base.BaseTestCase): retval = self.handler._proxy_request('the_id', 'tenant_id', req) + mock_http.assert_called_once_with( + ca_certs=None, disable_ssl_certificate_validation=True) mock_http.assert_has_calls([ + mock.call().add_certificate( + FakeConf.nova_client_priv_key, + FakeConf.nova_client_cert, + "%s:%s" % (FakeConf.nova_metadata_ip, + FakeConf.nova_metadata_port) + ), mock.call().request( 'http://9.9.9.9:8775/the_path', method=method,