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',
|
cfg.IntOpt('num_engine_workers',
|
||||||
help=_('Number of heat-engine processes to fork and run. '
|
help=_('Number of heat-engine processes to fork and run. '
|
||||||
'Will default to either to 4 or number of CPUs on '
|
'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 = [
|
engine_opts = [
|
||||||
cfg.ListOpt('plugin_dirs',
|
cfg.ListOpt('plugin_dirs',
|
||||||
|
|
|
@ -121,3 +121,6 @@ class FakeKeystoneClient(object):
|
||||||
|
|
||||||
def stack_domain_user_token(self, user_id, project_id, password):
|
def stack_domain_user_token(self, user_id, project_id, password):
|
||||||
return 'adomainusertoken'
|
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._check_stack_domain_user(user_id, project_id, 'enable')
|
||||||
self.domain_admin_client.users.update(user=user_id, enabled=True)
|
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):
|
class KeystoneClient(object):
|
||||||
"""Keystone Auth Client.
|
"""Keystone Auth Client.
|
||||||
|
|
|
@ -84,7 +84,8 @@ class BaseServer(stack_user.StackUser):
|
||||||
occ.update({'heat': {
|
occ.update({'heat': {
|
||||||
'user_id': self._get_user_id(),
|
'user_id': self._get_user_id(),
|
||||||
'password': self.password,
|
'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,
|
'project_id': self.stack.stack_user_project_id,
|
||||||
'stack_id': self.stack.identifier().stack_path(),
|
'stack_id': self.stack.identifier().stack_path(),
|
||||||
'resource_name': self.name,
|
'resource_name': self.name,
|
||||||
|
@ -96,7 +97,8 @@ class BaseServer(stack_user.StackUser):
|
||||||
occ.update({'zaqar': {
|
occ.update({'zaqar': {
|
||||||
'user_id': self._get_user_id(),
|
'user_id': self._get_user_id(),
|
||||||
'password': self.password,
|
'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,
|
'project_id': self.stack.stack_user_project_id,
|
||||||
'queue_id': queue_id,
|
'queue_id': queue_id,
|
||||||
'region_name': region_name}})
|
'region_name': region_name}})
|
||||||
|
|
|
@ -103,7 +103,8 @@ class SignalResponder(stack_user.StackUser):
|
||||||
if self.password is None:
|
if self.password is None:
|
||||||
self.password = password_gen.generate_openstack_password()
|
self.password = password_gen.generate_openstack_password()
|
||||||
self._create_user()
|
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(),
|
'username': self.physical_resource_name(),
|
||||||
'user_id': self._get_user_id(),
|
'user_id': self._get_user_id(),
|
||||||
'password': self.password,
|
'password': self.password,
|
||||||
|
|
|
@ -1449,6 +1449,52 @@ class KeystoneClientTest(common.HeatTestCase):
|
||||||
self.assertIsNone(heat_ks_client.delete_stack_domain_project(
|
self.assertIsNone(heat_ks_client.delete_stack_domain_project(
|
||||||
project_id='aprojectid'))
|
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):
|
class KeystoneClientTestDomainName(KeystoneClientTest):
|
||||||
def setUp(self):
|
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