Agreed - there's not a great reason to limit to a single project manager. On Aug 6, 2010, at 1:35 PM, Vishvananda Ishaya wrote:
> We also have the oddness of the project manager being a part of role checking > but not actually being stored in ldap as a separate role. Perhaps we should > deprecate the ProjectManager item in ldap and turn it into an actual role. > > On Fri, Aug 6, 2010 at 11:58 AM, Jay Pipes <[email protected]> wrote: > Hi all (especially Vish and Devin)! > > I've been going through the code in /nova/auth/* and have a few > comments/suggestions on the implementation of authorization (not > authentication) in Nova. Love to get some feedback from y'all. > > Currently, Nova's authorization is handled via role-based access > control (RBAC). Nothing wrong with this at all; it's very common and > well-understood. > > However, the current RBAC implementation, while quite elegant, isn't > very flexible and is not configurable because: > > 1) All the roles are hard-coded strings (netadmin, projectmanager, etc..) > 2) All the permissions are hard-coded using the decorators in /nova/rbac.py. > > As an example, here is the cloud controller's get_console_output() method: > > @rbac.allow('projectmanager', 'sysadmin') > def get_console_output(self, context, instance_id, **kwargs): > # instance_id is passed in as a list of instances > instance = self._get_instance(context, instance_id[0]) > return rpc.call('%s.%s' % (FLAGS.compute_topic, instance['node_name']), > {"method": "get_console_output", > "args" : {"instance_id": instance_id[0]}}) > > The rbac.allow decorator establishes if the request context's user is > in either the "projectmanager" or "sysadmin" roles. This decorator > pattern is very elegant and declarative. > > Unfortunately, what this implementation means is that a user > installing Nova has no say in: > > 1) The names and number of roles > 2) The access permissions for the hard-coded roles > > without modifying the Nova source code, which of course isn't > particularly friendly! :) > > I propose changing the authorization code to allow a flexible RBAC > configuration file (possibly XML?) that would allow installing users > to implement their own security groups and permissions. Of course, > Nova would ship with a configuration file that matches the current > hard-coded names and permissions... > > Consider this possible configuration file: > > ?xml version="1.0"?> > <rbac> > <roles> > <role id="all" desc="Anyone" /> > <role id="projectmanager" desc="Project Manager" /> > <role id="sysadmin" desc="Sys Admin" /> > <role id="netadmin" desc="Network Admin" /> > .... > </roles> > <resourcegroups> > <resourcegroup id="cloud"> > <resource id="create_key_pair" allow="all" /> > <resource id="delete_key_pair" allow="all" /> > <resource id="describe_security_groups" allow="all" /> > <resource id="create_security_group" allow="netadmin" /> > <resource id="delete_security_group" allow="netadmin" /> > ... > </resourcegroup> > </resources> > </rbac> > > On controller initialization, the controller would call some interface > that would parse this configuration file into an in-memory > representation. Imagine something like this: > > // in /nova/auth/acl.py > class ACL: > def __init__(self): > # Read config file and populate a dict of roles and resources... > def allowed_roles(self, resource_id): > # Takes a resource id and returns a set of allowed roles... > > The elegant decorator pattern could, of course, still be used, but in > a slightly different manner. Something like this might work: > > class CloudController(object): > ... > @rbac.check > def create_security_group(self, context, group_name, **kwargs): > ... > > // in /nova/auth/rbac.py: > from nova.auth import acl > > acl = acl.ACL() > > def check(): > def wrap(f): > def wrapped_f(self, context, *args, **kwargs): > if context.user.is_superuser(): > return f(self, context, *args, **kwargs) > f_name = f.__name__ > roles = acl.get_allowed_roles(f_name) > for role in roles: > if __matches_role(context, role): > return f(self, context, *args, **kwargs) > raise exception.NotAuthorized() > return wrapped_f > return wrap > > def __matches_role(context, role): > if role == 'all': > return True > if role == 'none': > return False > return context.project.has_role(context.user.id, role) > > Thoughts? > > -jay > > _______________________________________________ > Mailing list: https://launchpad.net/~nova > Post to : [email protected] > Unsubscribe : https://launchpad.net/~nova > More help : https://help.launchpad.net/ListHelp > > _______________________________________________ > Mailing list: https://launchpad.net/~nova > Post to : [email protected] > Unsubscribe : https://launchpad.net/~nova > More help : https://help.launchpad.net/ListHelp
_______________________________________________ Mailing list: https://launchpad.net/~nova Post to : [email protected] Unsubscribe : https://launchpad.net/~nova More help : https://help.launchpad.net/ListHelp

