← Back to team overview

nova team mailing list archive

Re: Thoughts on RBAC implementation

 

Awesome find, Michael.  Checking into this now...hopefully it will
save us lots of time.

(Good quality) Code we don't have to write is the best kind of code :)

-jay

On Mon, Aug 9, 2010 at 10:00 AM, Michael Gundlach
<michael.gundlach@xxxxxxxxxxxxx> wrote:
> Hooray for WSGI!  There's an app for that:
>
> http://pypi.python.org/pypi/AuthKit/0.4.5
> May I propose that rather than reinventing the RBAC wheel, we just drop an
> existing RBAC wsgi app in front of our system?  And if it has any
> shortcomings, we contribute back to AuthKit.
> I've never used it -- I just searched for "wsgi rbac".  The summary mentions
> that it can work with LDAP, and that you can define your own roles.  It
> looks like AuthKit was written by the lead developer of the Pylons
> framework.
> Michael
>
> On Fri, Aug 6, 2010 at 2:58 PM, Jay Pipes <jaypipes@xxxxxxxxx> 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     : nova@xxxxxxxxxxxxxxxxxxx
>> Unsubscribe : https://launchpad.net/~nova
>> More help   : https://help.launchpad.net/ListHelp
>
> Confidentiality Notice: This e-mail message (including any attached or
> embedded documents) is intended for the exclusive and confidential use of
> the
> individual or entity to which this message is addressed, and unless
> otherwise
> expressly indicated, is confidential and privileged information of
> Rackspace.
> Any dissemination, distribution or copying of the enclosed material is
> prohibited.
> If you receive this transmission in error, please notify us immediately by
> e-mail
> at abuse@xxxxxxxxxxxxx, and delete the original message.
> Your cooperation is appreciated.
>



References