summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2019-10-15 21:00:02 +0000
committerGerrit Code Review <review@openstack.org>2019-10-15 21:00:02 +0000
commitadac77a47ce1408e661e851e92a657ecfed3b911 (patch)
tree33ad7a6c0e6ef8644ca1d2961a558705eedcfb83
parent05bb44663745d5132f5f0db098bc699cc32be356 (diff)
parent35ef93d037baf4e704f23ee20f58d11b1d4ccbe7 (diff)
downloadheat-adac77a47ce1408e661e851e92a657ecfed3b911.tar.gz
Merge "Add dedicated auth endpoint config for servers" into stable/stein
-rw-r--r--heat/common/config.py9
-rw-r--r--heat/engine/clients/os/keystone/fake_keystoneclient.py3
-rw-r--r--heat/engine/clients/os/keystone/heat_keystoneclient.py23
-rw-r--r--heat/engine/resources/server_base.py6
-rw-r--r--heat/engine/resources/signal_responder.py3
-rw-r--r--heat/tests/clients/test_heat_client.py46
-rw-r--r--releasenotes/notes/add-dedicated-auth-endpoint-config-for-servers-b20f7eb351f619d0.yaml16
7 files changed, 102 insertions, 4 deletions
diff --git a/heat/common/config.py b/heat/common/config.py
index c4c9e1d2e..8e39719c8 100644
--- a/heat/common/config.py
+++ b/heat/common/config.py
@@ -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',
diff --git a/heat/engine/clients/os/keystone/fake_keystoneclient.py b/heat/engine/clients/os/keystone/fake_keystoneclient.py
index 6e594ecfb..524d09a8e 100644
--- a/heat/engine/clients/os/keystone/fake_keystoneclient.py
+++ b/heat/engine/clients/os/keystone/fake_keystoneclient.py
@@ -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
diff --git a/heat/engine/clients/os/keystone/heat_keystoneclient.py b/heat/engine/clients/os/keystone/heat_keystoneclient.py
index 2b3999dbb..edd05c768 100644
--- a/heat/engine/clients/os/keystone/heat_keystoneclient.py
+++ b/heat/engine/clients/os/keystone/heat_keystoneclient.py
@@ -552,6 +552,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.
diff --git a/heat/engine/resources/server_base.py b/heat/engine/resources/server_base.py
index 983efe298..5f0b5d00c 100644
--- a/heat/engine/resources/server_base.py
+++ b/heat/engine/resources/server_base.py
@@ -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}})
diff --git a/heat/engine/resources/signal_responder.py b/heat/engine/resources/signal_responder.py
index 23c1f9c76..b9127d9f1 100644
--- a/heat/engine/resources/signal_responder.py
+++ b/heat/engine/resources/signal_responder.py
@@ -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,
diff --git a/heat/tests/clients/test_heat_client.py b/heat/tests/clients/test_heat_client.py
index ffe017796..c5fb9f003 100644
--- a/heat/tests/clients/test_heat_client.py
+++ b/heat/tests/clients/test_heat_client.py
@@ -1435,6 +1435,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):
diff --git a/releasenotes/notes/add-dedicated-auth-endpoint-config-for-servers-b20f7eb351f619d0.yaml b/releasenotes/notes/add-dedicated-auth-endpoint-config-for-servers-b20f7eb351f619d0.yaml
new file mode 100644
index 000000000..52d93f8da
--- /dev/null
+++ b/releasenotes/notes/add-dedicated-auth-endpoint-config-for-servers-b20f7eb351f619d0.yaml
@@ -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