From: Steven Hardy Date: Thu, 25 Oct 2012 10:33:20 +0000 (+0100) Subject: heat engine : add template-defined users to keystone role X-Git-Tag: 2014.1~1269 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=cd9a3a7c95f560551214c10784590111537ff3f1;p=openstack-build%2Fheat-build.git heat engine : add template-defined users to keystone role Add all keystone users created by the User resource type to a special keystone role, which can be used later for defining RBAC policy for these users, and also works around a keystone bug (1060959) on Folsom Fixes #279 Change-Id: I94931e427ed51f4332bcb506220925b7ce8097bc Signed-off-by: Steven Hardy --- diff --git a/etc/heat/heat-engine.conf b/etc/heat/heat-engine.conf index b84b0533..1a995850 100644 --- a/etc/heat/heat-engine.conf +++ b/etc/heat/heat-engine.conf @@ -11,6 +11,9 @@ bind_host = 0.0.0.0 # Port the bind the server to bind_port = 8001 +# Keystone role for heat template-defined users +heat_stack_user_role = heat_stack_user + # Log to this file. Make sure the user running heat-engine has # permissions to write to this file! log_file = /var/log/heat/engine.log diff --git a/heat/common/config.py b/heat/common/config.py index f782e444..4af919c6 100644 --- a/heat/common/config.py +++ b/heat/common/config.py @@ -80,6 +80,9 @@ cfg.IntOpt('osapi_volume_listen_port', cfg.StrOpt('heat_metadata_server_url', default="", help='URL of the Heat metadata server'), +cfg.StrOpt('heat_stack_user_role', + default="heat_stack_user", + help='Keystone role for heat template-defined users'), ] db_opts = [ cfg.StrOpt('sql_connection', diff --git a/heat/engine/user.py b/heat/engine/user.py index 3890373a..83c827cb 100644 --- a/heat/engine/user.py +++ b/heat/engine/user.py @@ -15,6 +15,7 @@ import eventlet from heat.common import exception +from heat.openstack.common import cfg from heat.engine.resources import Resource from heat.openstack.common import log as logging @@ -60,6 +61,22 @@ class User(Resource): enabled=True) self.instance_id_set(user.id) + # We add the new user to a special keystone role + # This role is designed to allow easier differentiation of the + # heat-generated "stack users" which will generally have credentials + # deployed on an instance (hence are implicitly untrusted) + roles = self.keystone().roles.list() + stack_user_role = [r.id for r in roles + if r.name == cfg.CONF.heat_stack_user_role] + if len(stack_user_role) == 1: + role_id = stack_user_role[0] + logger.debug("Adding user %s to role %s" % (user.id, role_id)) + self.keystone().roles.add_user_role(user.id, role_id, tenant_id) + else: + logger.error("Failed to add user %s to role %s, check role exists!" + % (self.physical_resource_name(), + cfg.CONF.heat_stack_user_role)) + def handle_update(self): return self.UPDATE_REPLACE diff --git a/heat/tests/test_user.py b/heat/tests/test_user.py index d6afe444..f26e2811 100644 --- a/heat/tests/test_user.py +++ b/heat/tests/test_user.py @@ -25,11 +25,14 @@ import unittest from nose.plugins.attrib import attr from heat.common import exception +from heat.common import config from heat.engine import parser from heat.engine import user from heat.tests.v1_1 import fakes from keystoneclient.v2_0 import users +from keystoneclient.v2_0 import roles from keystoneclient.v2_0 import ec2 +from heat.openstack.common import cfg @attr(tag=['unit', 'resource']) @@ -39,6 +42,7 @@ class UserTest(unittest.TestCase): self.m = mox.Mox() self.fc = fakes.FakeClient() self.fc.users = users.UserManager(None) + self.fc.roles = roles.RoleManager(None) self.fc.ec2 = ec2.CredentialsManager(None) self.m.StubOutWithMock(user.User, 'keystone') self.m.StubOutWithMock(user.AccessKey, 'keystone') @@ -46,10 +50,14 @@ class UserTest(unittest.TestCase): self.m.StubOutWithMock(self.fc.users, 'get') self.m.StubOutWithMock(self.fc.users, 'delete') self.m.StubOutWithMock(self.fc.users, 'list') + self.m.StubOutWithMock(self.fc.roles, 'list') + self.m.StubOutWithMock(self.fc.roles, 'add_user_role') self.m.StubOutWithMock(self.fc.ec2, 'create') self.m.StubOutWithMock(self.fc.ec2, 'get') self.m.StubOutWithMock(self.fc.ec2, 'delete') self.m.StubOutWithMock(eventlet, 'sleep') + config.register_engine_opts() + cfg.CONF.set_default('heat_stack_user_role', 'stack_user_role') def tearDown(self): self.m.UnsetStubs() @@ -107,6 +115,14 @@ class UserTest(unittest.TestCase): enabled=True, tenant_id='test_tenant').AndReturn(fake_user) + fake_role = roles.Role(self.fc.roles, {'id': '123', + 'name': 'stack_user_role'}) + user.User.keystone().AndReturn(self.fc) + self.fc.roles.list().AndReturn([fake_role]) + + user.User.keystone().AndReturn(self.fc) + self.fc.roles.add_user_role('1', '123', 'test_tenant').AndReturn(None) + # delete script user.User.keystone().AndReturn(self.fc) self.fc.users.get(user.DummyId('1')).AndRaise(Exception('not found'))