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,