Enable SSL for EC2Tokens.

When keystone is deployed behind SSL, the ec2_authtoken options doesn't
have a way to include the same SSL options that the various clients use,
so it's not possible to authenticate tokens.

Capability to handle SSL options is added. ec2token makes use of HTTP
request object from httplib. Config options to specify CA file, client
side certificate, key file and "verify server certificate option" will
be listed under "ec2authtoken" group in conf file.

Change-Id: Ibede73a17ae951cff00a7d9629a4c08f82208139
Closes-Bug: #1415223
This commit is contained in:
Anant Patil 2015-01-29 13:08:46 +05:30
parent fb32508af5
commit 11d04c8d6a
2 changed files with 63 additions and 4 deletions

View File

@ -39,7 +39,21 @@ opts = [
default=[],
help=_('Allowed keystone endpoints for auth_uri when '
'multi_cloud is enabled. At least one endpoint needs '
'to be specified.'))
'to be specified.')),
cfg.StrOpt('cert_file',
default=None,
help=_('Optional PEM-formatted certificate chain file.')),
cfg.StrOpt('key_file',
default=None,
help=_('Optional PEM-formatted file that contains the '
'private key.')),
cfg.StrOpt('ca_file',
default=None,
help=_('Optional CA cert file to use in SSL connections.')),
cfg.BoolOpt('insecure',
default=False,
help=_('If set, then the server\'s certificate will not '
'be verified.')),
]
cfg.CONF.register_opts(opts, group='ec2authtoken')
@ -50,6 +64,7 @@ class EC2Token(wsgi.Middleware):
def __init__(self, app, conf):
self.conf = conf
self.application = app
self._ssl_options = None
def _conf_get(self, name):
# try config from paste-deploy first
@ -131,6 +146,19 @@ class EC2Token(wsgi.Middleware):
last_failure = e
raise last_failure or exception.HeatAccessDeniedError()
@property
def ssl_options(self):
if not self._ssl_options:
cacert = self._conf_get('ca_file')
insecure = self._conf_get('insecure')
cert = self._conf_get('cert_file')
key = self._conf_get('key_file')
self._ssl_options = {
'verify': cacert if cacert else not insecure,
'cert': (cert, key) if cert else None
}
return self._ssl_options
def _authorize(self, req, auth_uri):
# Read request signature and access id.
# If we find X-Auth-User in the headers we ignore a key error
@ -185,7 +213,9 @@ class EC2Token(wsgi.Middleware):
keystone_ec2_uri = self._conf_get_keystone_ec2_uri(auth_uri)
LOG.info(_LI('Authenticating with %s'), keystone_ec2_uri)
response = requests.post(keystone_ec2_uri, data=creds_json,
headers=headers)
headers=headers,
verify=self.ssl_options['verify'],
cert=self.ssl_options['cert'])
result = response.json()
try:
token_id = result['access']['token']['id']

View File

@ -60,6 +60,34 @@ class Ec2TokenTest(common.HeatTestCase):
'http://192.0.2.9/v2.0/ec2tokens',
ec2._conf_get_keystone_ec2_uri('http://192.0.2.9/v2.0/'))
def test_conf_get_ssl_default_options(self):
ec2 = ec2token.EC2Token(app=None, conf={})
self.assertTrue(ec2.ssl_options['verify'],
"SSL verify should be True by default")
self.assertIsNone(ec2.ssl_options['cert'],
"SSL client cert should be None by default")
def test_conf_ssl_insecure_option(self):
ec2 = ec2token.EC2Token(app=None, conf={})
cfg.CONF.set_default('insecure', 'True', group='ec2authtoken')
cfg.CONF.set_default('ca_file', None, group='ec2authtoken')
self.assertFalse(ec2.ssl_options['verify'])
def test_conf_get_ssl_opts(self):
cfg.CONF.set_default('auth_uri', 'https://192.0.2.9/v2.0/',
group='ec2authtoken')
cfg.CONF.set_default('ca_file', '/home/user/cacert.pem',
group='ec2authtoken')
cfg.CONF.set_default('insecure', 'false', group='ec2authtoken')
cfg.CONF.set_default('cert_file', '/home/user/mycert',
group='ec2authtoken')
cfg.CONF.set_default('key_file', '/home/user/mykey',
group='ec2authtoken')
ec2 = ec2token.EC2Token(app=None, conf={})
self.assertEqual('/home/user/cacert.pem', ec2.ssl_options['verify'])
self.assertEqual(('/home/user/mycert', '/home/user/mykey'),
ec2.ssl_options['cert'])
def test_get_signature_param_old(self):
params = {'Signature': 'foo'}
dummy_req = self._dummy_GET_request(params)
@ -183,7 +211,8 @@ class Ec2TokenTest(common.HeatTestCase):
self.assertEqual('xyz', ec2.__call__(dummy_req))
def _stub_http_connection(self, headers=None, params=None, response=None,
req_url='http://123:5000/v2.0/ec2tokens'):
req_url='http://123:5000/v2.0/ec2tokens',
verify=True, cert=None):
headers = headers or {}
params = params or {}
@ -206,7 +235,7 @@ class Ec2TokenTest(common.HeatTestCase):
"path": "/v1",
"body_hash": body_hash}})
req_headers = {'Content-Type': 'application/json'}
requests.post(req_url, data=req_creds,
requests.post(req_url, data=req_creds, verify=verify, cert=cert,
headers=req_headers).AndReturn(DummyHTTPResponse())
def test_call_ok(self):