]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
heat engine : add template-defined users to keystone role
authorSteven Hardy <shardy@redhat.com>
Thu, 25 Oct 2012 10:33:20 +0000 (11:33 +0100)
committerSteven Hardy <shardy@redhat.com>
Thu, 25 Oct 2012 12:59:49 +0000 (13:59 +0100)
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 <shardy@redhat.com>
etc/heat/heat-engine.conf
heat/common/config.py
heat/engine/user.py
heat/tests/test_user.py

index b84b0533d112717d8e0931b8e2683bd3e0ae751c..1a99585040d6e14ab6d50600755d07c5b86c2195 100644 (file)
@@ -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
index f782e44450729c23a365804cc6f170d182a4851a..4af919c64103400d748184f5761429ffc13f7bea 100644 (file)
@@ -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',
index 3890373a0a251fa1d3ed8ce2779285d306deeef1..83c827cb3dbbc65dc48bb984dfeb70f30e6b05a2 100644 (file)
@@ -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
 
index d6afe44463c81ef62bae10467897e6af5714e2c7..f26e2811f31c9d464a708db215b5ebbae320eb59 100644 (file)
@@ -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'))