RBAC in Galaxy NG¶
Basics¶
Permissions¶
Every object in a GalaxyNG has at least four permissions created for it by default: - Add: grants the ability to add objects of that class - Delete: grants the ability to delete objects of that class - View: grants the ability to view objects of that class - Update: grants the ability to update objects of that class
Additional custom permissions can also be created for objects. For example, the namespace
object has the "Upload to namespace" custom permission that we have defined to allow users to upload collections to a specific namespace.
Roles¶
Roles are groups of permissions that can be assigned to groups. There are a set of predefined roles that ship with GalaxyNG, however users can also define their own roles with any set of permissions that they want.
Role Assignment¶
Roles can be assigned at two levels: model (global) and object.
Model roles are global, and grant the permission to all objects of the given class in the system. For example, granting model level namespace_owner role will allow a user to update all namespaces in the system.
Object level roles are for specific objects. They allow for a user in the system to be granted permissions for a specific object. For example, granting a user the namespace_owner role on namespace foo
will allow a user to update namespace foo
, but no other namespaces.
Roles can be assigned in one of two ways: on a per user level or on a per group level. At the moment, only group roles are supported. To grant permissions, an admin has to create a group with the desired set of roles and then add users who need those permissions to the group. For example an admin might create a "Content Managers" group that has global roles for creating and updating new collections, namespaces and EEs. This would allow the admin to grant new users all the permissions needed to manage content by adding them to the "Content Managers" group.
Unused Permissions¶
Not all permissions are enforced. Content types such as collections and execution environments don't require any special permissions to view, so the view permissions for collections and EEs aren't enforced.
Super users¶
Users with django super user permissions automatically have all permissions in the system and can do anything that the app allows.
Technical Details¶
To make all of this work, we use two external libraries that add some addition functionality to the existing Django RBAC system.
Pulp RBAC¶
Pulp RBAC allows us to create roles that group together sets of django permissions and assign them to users and groups globally or for specific objects.
DRF Access policy¶
DRF access policy (https://rsinger86.github.io/drf-access-policy/) allows us to create DRF permission classes that read a JSON or python object and return whether or not the user has permissions to perform some action. A DRF access policy statement looks something like this:
[
{
"action": ["list", "retrieve"],
"principal": "authenticated",
"effect": "allow",
},
{
"action": "destroy",
"principal": "*",
"effect": "deny",
},
{
"action": "create",
"principal": "authenticated",
"effect": "allow",
"condition": "has_model_perms:galaxy.add_namespace"
},
{
"action": "update",
"principal": "authenticated",
"effect": "allow",
"condition": "has_model_or_obj_perms:galaxy.change_namespace"
},
]
This access policy allows for authenticated users to view content, users with the galaxy.add_namespace
permissions to create new namespaces, users with the change_namespace
permissions to update namespaces and denies everyone from deleting namespaces.
Our access policy definitions can be found in galaxy_ng/galaxy_ng/app/access_control/statements
.
Note that we never reference roles directly in any of the access policies. Instead, access is granted based on what permissions a user has. Those permissions are checked by looking up the user's roles and verifying that they have a role with the necessary set of permissions to perform some action.
Loading DRF Access policies¶
Access policies are loaded in galaxy_ng/galaxy_ng/app/access_control/access_policy.py
. At the moment there are two sets of access policies, one for insights mode, which disables features that aren't allowed in insights mode and one for standalone mode, which enables features such as user management and collection syncing. When the app is loaded, the access policy base class checks if the app is running in insights mode or standalone mode and loads the corresponding access policy.
Pulp Access Policies¶
Access policies for pulp api endpoints can be defined in our access policies by setting up an access policy that has the same url pattern as a pulp viewset. This access policy will apply to the group roles API.
'groups/roles': [
{
"action": ["list", "retrieve"],
"principal": "authenticated",
"effect": "allow",
"condition": "has_model_perms:galaxy.view_group"
},
{
"action": "create",
"principal": "authenticated",
"effect": "allow",
"condition": "has_model_perms:galaxy.change_group"
},
{
"action": "*",
"principal": "admin",
"effect": "allow"
}
],
Pulp viewset url patterns are loosely based on their api path, but this isn't always the case. The best way to figure out which viewset name applies to an API endpoint is to throw a print statement here https://github.com/ansible/galaxy_ng/blob/63803c3c8f40450b7e9e5abcc63121487f80ab33/galaxy_ng/app/access_control/access_policy.py#L81 and see what the value for viewname
is.