Merge "Add dedicated auth endpoint config for servers"
This commit is contained in:
commit
54005a2a9f
|
@ -88,7 +88,14 @@ service_opts = [
|
|||
cfg.IntOpt('num_engine_workers',
|
||||
help=_('Number of heat-engine processes to fork and run. '
|
||||
'Will default to either to 4 or number of CPUs on '
|
||||
'the host, whichever is greater.'))]
|
||||
'the host, whichever is greater.')),
|
||||
cfg.StrOpt('server_keystone_endpoint_type',
|
||||
choices=['', 'public', 'internal', 'admin'],
|
||||
default='',
|
||||
help=_('If set, is used to control which authentication '
|
||||
'endpoint is used by user-controlled servers to make '
|
||||
'calls back to Heat. '
|
||||
'If unset www_authenticate_uri is used.'))]
|
||||
|
||||
engine_opts = [
|
||||
cfg.ListOpt('plugin_dirs',
|
||||
|
|
|
@ -121,3 +121,6 @@ class FakeKeystoneClient(object):
|
|||
|
||||
def stack_domain_user_token(self, user_id, project_id, password):
|
||||
return 'adomainusertoken'
|
||||
|
||||
def server_keystone_endpoint_url(self, fallback_endpoint):
|
||||
return fallback_endpoint
|
||||
|
|
|
@ -563,6 +563,29 @@ class KsClientWrapper(object):
|
|||
self._check_stack_domain_user(user_id, project_id, 'enable')
|
||||
self.domain_admin_client.users.update(user=user_id, enabled=True)
|
||||
|
||||
def server_keystone_endpoint_url(self, fallback_endpoint):
|
||||
ks_endpoint_type = cfg.CONF.server_keystone_endpoint_type
|
||||
if ((ks_endpoint_type == 'public') or (
|
||||
ks_endpoint_type == 'internal') or
|
||||
(ks_endpoint_type == 'admin')):
|
||||
if (hasattr(self.context, 'auth_plugin') and
|
||||
hasattr(self.context.auth_plugin, 'get_access')):
|
||||
try:
|
||||
auth_ref = self.context.auth_plugin.get_access(
|
||||
self.session)
|
||||
if hasattr(auth_ref, "service_catalog"):
|
||||
unversioned_sc_auth_uri = (
|
||||
auth_ref.service_catalog.get_urls(
|
||||
service_type='identity',
|
||||
interface=ks_endpoint_type))
|
||||
if len(unversioned_sc_auth_uri) > 0:
|
||||
sc_auth_uri = (
|
||||
unversioned_sc_auth_uri[0] + "/v3")
|
||||
return sc_auth_uri
|
||||
except ks_exception.Unauthorized:
|
||||
LOG.error("Keystone client authentication failed")
|
||||
return fallback_endpoint
|
||||
|
||||
|
||||
class KeystoneClient(object):
|
||||
"""Keystone Auth Client.
|
||||
|
|
|
@ -84,7 +84,8 @@ class BaseServer(stack_user.StackUser):
|
|||
occ.update({'heat': {
|
||||
'user_id': self._get_user_id(),
|
||||
'password': self.password,
|
||||
'auth_url': self.context.auth_url,
|
||||
'auth_url': self.keystone().server_keystone_endpoint_url(
|
||||
fallback_endpoint=self.context.auth_url),
|
||||
'project_id': self.stack.stack_user_project_id,
|
||||
'stack_id': self.stack.identifier().stack_path(),
|
||||
'resource_name': self.name,
|
||||
|
@ -96,7 +97,8 @@ class BaseServer(stack_user.StackUser):
|
|||
occ.update({'zaqar': {
|
||||
'user_id': self._get_user_id(),
|
||||
'password': self.password,
|
||||
'auth_url': self.context.auth_url,
|
||||
'auth_url': self.keystone().server_keystone_endpoint_url(
|
||||
fallback_endpoint=self.context.auth_url),
|
||||
'project_id': self.stack.stack_user_project_id,
|
||||
'queue_id': queue_id,
|
||||
'region_name': region_name}})
|
||||
|
|
|
@ -103,7 +103,8 @@ class SignalResponder(stack_user.StackUser):
|
|||
if self.password is None:
|
||||
self.password = password_gen.generate_openstack_password()
|
||||
self._create_user()
|
||||
return {'auth_url': self.keystone().v3_endpoint,
|
||||
return {'auth_url': self.keystone().server_keystone_endpoint_url(
|
||||
fallback_endpoint=self.keystone().v3_endpoint),
|
||||
'username': self.physical_resource_name(),
|
||||
'user_id': self._get_user_id(),
|
||||
'password': self.password,
|
||||
|
|
|
@ -1449,6 +1449,52 @@ class KeystoneClientTest(common.HeatTestCase):
|
|||
self.assertIsNone(heat_ks_client.delete_stack_domain_project(
|
||||
project_id='aprojectid'))
|
||||
|
||||
def test_server_keystone_endpoint_url_config(self):
|
||||
"""Return non fallback url path."""
|
||||
cfg.CONF.set_override('server_keystone_endpoint_type', 'public')
|
||||
ctx = utils.dummy_context()
|
||||
ctx.trust_id = None
|
||||
heat_ks_client = heat_keystoneclient.KeystoneClient(ctx)
|
||||
fallback_url = 'http://server.fallback.test:5000/v3'
|
||||
auth_ref = heat_ks_client.context.auth_plugin.get_access(
|
||||
heat_ks_client.session)
|
||||
auth_ref.service_catalog.get_urls = mock.MagicMock()
|
||||
auth_ref.service_catalog.get_urls.return_value = [
|
||||
'http://server.public.test:5000']
|
||||
self.assertEqual(
|
||||
heat_ks_client.server_keystone_endpoint_url(fallback_url),
|
||||
'http://server.public.test:5000/v3')
|
||||
cfg.CONF.clear_override('server_keystone_endpoint_type')
|
||||
|
||||
def test_server_keystone_endpoint_url_no_config(self):
|
||||
"""Return fallback as no config option specified."""
|
||||
ctx = utils.dummy_context()
|
||||
ctx.trust_id = None
|
||||
heat_ks_client = heat_keystoneclient.KeystoneClient(ctx)
|
||||
cfg.CONF.clear_override('server_keystone_endpoint_type')
|
||||
fallback_url = 'http://server.fallback.test:5000/v3'
|
||||
self.assertEqual(heat_ks_client.server_keystone_endpoint_url(
|
||||
fallback_url), fallback_url)
|
||||
|
||||
def test_server_keystone_endpoint_url_auth_exception(self):
|
||||
"""Authorization call fails, return fallback."""
|
||||
cfg.CONF.set_override('server_keystone_endpoint_type', 'public')
|
||||
ctx = utils.dummy_context()
|
||||
ctx.trust_id = None
|
||||
heat_ks_client = heat_keystoneclient.KeystoneClient(ctx)
|
||||
auth_ref = heat_ks_client.context.auth_plugin.get_access(
|
||||
heat_ks_client.session)
|
||||
auth_ref.service_catalog.get_urls = mock.MagicMock()
|
||||
auth_ref.service_catalog.get_urls.return_value = [
|
||||
'http://server.public.test:5000']
|
||||
heat_ks_client.context.auth_plugin.get_access = mock.MagicMock()
|
||||
heat_ks_client.context.auth_plugin.get_access.side_effect = (
|
||||
kc_exception.Unauthorized)
|
||||
fallback_url = 'http://server.fallback.test:5000/v3'
|
||||
self.assertEqual(heat_ks_client.server_keystone_endpoint_url(
|
||||
fallback_url), fallback_url)
|
||||
cfg.CONF.clear_override('server_keystone_endpoint_type')
|
||||
|
||||
|
||||
class KeystoneClientTestDomainName(KeystoneClientTest):
|
||||
def setUp(self):
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Added a new config option server_keystone_endpoint_type to specify
|
||||
the keystone authentication endpoint (public/internal/admin)
|
||||
to pass into cloud-init data.
|
||||
If left unset the original behavior should remain unchanged.
|
||||
|
||||
This feature allows the deployer to unambiguously specify the
|
||||
keystone endpoint passed to user provisioned servers, and is particularly
|
||||
useful where the deployment network architecture requires the heat
|
||||
service to interact with the internal endpoint,
|
||||
but user provisioned servers only have access to the external network.
|
||||
|
||||
For more information see
|
||||
http://lists.openstack.org/pipermail/openstack-discuss/2019-February/002925.html
|
Loading…
Reference in New Issue