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
This commit is contained in:
Jakub Libosvar 2014-03-17 15:02:58 +01:00
parent d1282b1eda
commit 8679205427
3 changed files with 51 additions and 5 deletions

View File

@ -22,6 +22,20 @@ admin_password = %SERVICE_PASSWORD%
# TCP Port used by Nova metadata server # TCP Port used by Nova metadata server
# nova_metadata_port = 8775 # 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 # 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, # 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 # but it must match here and in the configuration used by the Nova Metadata

View File

@ -79,7 +79,20 @@ class MetadataProxyHandler(object):
cfg.StrOpt('metadata_proxy_shared_secret', cfg.StrOpt('metadata_proxy_shared_secret',
default='', default='',
help=_('Shared secret to sign instance-id request'), 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): def __init__(self, conf):
@ -152,15 +165,22 @@ class MetadataProxyHandler(object):
'X-Instance-ID-Signature': self._sign_instance_id(instance_id) '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(( url = urlparse.urlunsplit((
'http', self.conf.nova_metadata_protocol,
'%s:%s' % (self.conf.nova_metadata_ip, nova_ip_port,
self.conf.nova_metadata_port),
req.path_info, req.path_info,
req.query_string, 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, resp, content = h.request(url, method=req.method, headers=headers,
body=req.body) body=req.body)

View File

@ -41,6 +41,10 @@ class FakeConf(object):
nova_metadata_ip = '9.9.9.9' nova_metadata_ip = '9.9.9.9'
nova_metadata_port = 8775 nova_metadata_port = 8775
metadata_proxy_shared_secret = 'secret' 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): class TestMetadataProxyHandler(base.BaseTestCase):
@ -211,7 +215,15 @@ class TestMetadataProxyHandler(base.BaseTestCase):
retval = self.handler._proxy_request('the_id', 'tenant_id', retval = self.handler._proxy_request('the_id', 'tenant_id',
req) req)
mock_http.assert_called_once_with(
ca_certs=None, disable_ssl_certificate_validation=True)
mock_http.assert_has_calls([ 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( mock.call().request(
'http://9.9.9.9:8775/the_path', 'http://9.9.9.9:8775/the_path',
method=method, method=method,