← Back to team overview

nova team mailing list archive

Re: Thoughts on RBAC implementation

 

Hooray for WSGI!  There's an app for that:

http://pypi.python.org/pypi/AuthKit/0.4.5

<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