System Role Assignments¶
This document describes the necessary changes in order to implement system role assignments.
Problem Description¶
Today, role assignments are built by giving an actor a role on a target. An actor can be a user or a group. A target is limited to a project or a domain. This works great for controlling access to things that map into a project or domain (e.g. instance ownership fits naturally within projects). This starts to get confusing with operations that don’t fit within that constraint. Performing operations on hypervisors (e.g. GET /os-hypervisors/) is a good example of an API that doesn’t map well to a project. Instead, it’s clearer to think about these types of operations at a system-wide perspective, instead of a project-specific one.
A system role assignment would be an assignment with the target being system instead of a project or a domain.
Global Scope vs. System Scope¶
Initial discussions around this proposal used the term global scope as a way to distinguish something other than project scope. For example, operations on instances are easy to associate to a project because instances are owned by projects. Endpoints or services were originally considered global in nature since they applied to the whole deployment. After several discussions, it became apparent that global still wasn’t the term we were looking for. Another example highlights the deficiency in the term global. Theoretically, if a user has a role assignment on the root domain, or project, in an deployment, shouldn’t they be able to view all instances in the deployment (e.g. the entire project tree under the root domain)? Is that not in some sense also global because the user would be viewing all instances across the entire deployment? After understanding that, it became apparent that global refers to the root of a tree, when we really needed it to refer to system operations.
Using the term system helps clarify which resources and APIs are specific to the function of the deployment, or system as a whole. For example, service and endpoints are entities required for the system to function properly. They clearly don’t pertain to a single project or domain. Hypervisor management in nova is also a system level resource that doesn’t make sense to associate to a single project. Multiple projects can have instances hosted on a single hypervisor due to multi-tenancy.
Proposed Change¶
List system role assignments for a user¶
Request: GET /v3/system/users/{user_id}/roles/
Parameters
user_id - The user ID.
Response
200 - OK
404 - Not Found if a user doesn’t exist
401 - If the operation isn’t permitted to the user
Response Body
{
"links": {
"self": "http://example.com/identity/v3/system/users/cf8e3ee7115b4a88897673ee61dd2919/roles",
"previous": null,
"next": null
},
"roles": [
{
"id": "46b213b41e7344cc8078ac5e7d161f17",
"links": {
"self": "http://example.com/identity/v3/roles/46b213b41e7344cc8078ac5e7d161f17"
},
"name": "admin"
}
]
}
Assign a system role to a user¶
Request: PUT /v3/system/users/{user_id}/roles/{role_id}
Parameters
user_id - The user ID.
role_id - The role ID.
Response
204 - No Content
404 - Not Found if a role or user doesn’t exist
401 - If the operation isn’t permitted to the user
Check if a user has a system role assignment¶
Request: HEAD /v3/system/users/{user_id}/roles/{role_id}
Request: GET /v3/system/users/{user_id}/roles/{role_id}
Parameters
user_id - The user ID.
role_id - The role ID.
Response
204 - No Content
404 - Not Found if a role or user doesn’t exist
401 - If the operation isn’t permitted to the user
Unassign a system role from a user¶
Request: DELETE /v3/system/users/{user_id}/roles/{role_id}
Parameters
user_id - The user ID.
role_id - The role ID.
Response
204 - No Content
404 - Not Found if a role or user doesn’t exist
401 - If the operation isn’t permitted to the user
List system role assignments for a group¶
Request: GET /v3/system/groups/{group_id}/roles/
Parameters
group_id - The group ID.
Response
200 - OK
404 - Not Found if a group doesn’t exist
401 - If the operation isn’t permitted to the user
Response Body
{
"links": {
"self": "http://example.com/identity/v3/system/groups/282051ffddcf4206a954ad838c86d39f/roles",
"previous": null,
"next": null
},
"roles": [
{
"id": "46b213b41e7344cc8078ac5e7d161f17",
"links": {
"self": "http://example.com/identity/v3/roles/46b213b41e7344cc8078ac5e7d161f17"
},
"name": "admin"
}
]
}
Assign a system role to a group¶
Request: PUT /v3/system/groups/{group_id}/roles/{role_id}
Parameters
group_id - The group ID.
role_id - The role ID.
Response
204 - No Content
404 - Not Found if a role or group doesn’t exist
401 - If the operation isn’t permitted to the user
Check if a group has a system role assignment¶
Request: HEAD /v3/system/groups/{group_id}/roles/{role_id}
Request: GET /v3/system/groups/{group_id}/roles/{role_id}
Parameters
group_id - The group ID.
role_id - The role ID.
Response
204 - No Content
404 - Not Found if a role or group doesn’t exist
401 - If the operation isn’t permitted to the user
Unassign a system role from a group¶
Request: DELETE /v3/system/groups/{group_id}/roles/{role_id}
Parameters
group_id - The group ID.
role_id - The role ID.
Response
204 - No Content
404 - Not Found if a role or group doesn’t exist
401 - If the operation isn’t permitted to the user
List role assignments¶
The existing API to list role assignment will have to be enhanced to return system role assignment, in addition to the project and domain role assignment information it returns today.
Request: GET /v3/role_assignments
Paramters
A filter will be added, called scope.system, to filter role assignments by system-specific role assignment. It will be a boolean value.
Response
200 - OK
401 - If the operation isn’t permitted to the user
Response Body
{
"role_assignments": [
{
"role": {
"id": "d6c89e9121304b6f87de57b0500b0526"
},
"user": {
"id": "3f0c5f11e792494ab5de347696fa1421"
},
"scope": {
"domain": {
"id": "6bfbd79b010e4405b92731479cbbe8e7"
}
},
"links": {
"assignment": "http://example.com/identity/v3/domains/6bfbd79b010e4405b92731479cbbe8e7/users/3f0c5f11e792494ab5de347696fa1421/roles/d6c89e9121304b6f87de57b0500b0526"
}
},
{
"role": {
"id": "2fb8d689a8744a42af926ea4f8f929c7"
},
"group": {
"id": "a806d9029db7403e9869632aee082e5c"
},
"scope": {
"project": {
"id": "2fae742cb86543af825471ea6b63ccea"
}
},
"links": {
"assignment": "http://example.com/identity/v3/projects/2fae742cb86543af825471ea6b63ccea/groups/a806d9029db7403e9869632aee082e5c/roles/2fb8d689a8744a42af926ea4f8f929c7"
}
},
{
"group": {
"id": "1d8d919f37d94f308d007e72737cf10a"
},
"links": {
"assignment": "http://example.com/identity/v3/system/groups/1d8d919f37d94f308d007e72737cf10a/roles/b29d6fff51c43478b00bb16bfb771fc"
},
"role": {
"id": "ab29d6fff51c43478b00bb16bfb771fc"
},
"scope": {
"system": true
}
}
],
"links": {
"self": "http://example.com/identity/v3/role_assignments",
"previous": null,
"next": null
}
}
Authenticating for a system-scoped token¶
The following is an example request for a system-scoped token:
{
"auth": {
"identity": {
"methods": [
"password"
],
"password": {
"user": {
"id": "8bbca32b850a4c22b64a1b7bc2c6bd13",
"password": "my-password"
}
}
},
"scope": {
"system": {
"all": true
}
}
}
}
An example response would be:
{
"token": {
"audit_ids": [
"doIh18J8RyW3jXF50FV26g"
],
"catalog": [
...
],
"expires_at": "2017-05-15T21:58:29.000000Z",
"issued_at": "2017-05-15T20:58:29.000000Z",
"methods": [
"password"
],
"system": {
"all": true
},
"roles": [
{
"id": "c2145c84a802413fbac71479250c9378",
"name": "observer"
},
{
"id": "fc2ec22e227941f8afd94a1587ac57d3",
"name": "admin"
}
],
"user": {
"domain": {
"id": "default",
"name": "Default"
},
"id": "8bbca32b850a4c22b64a1b7bc2c6bd13",
"name": "bob",
"password_expires_at": null
}
}
}
System scope can be consumed by existing policies:
"system_admin": "role:admin and system:True"
"system_reader": "role:reader and system:True"
"admin_required": "rule:system_admin"
The attributes of a system token response can also be consumed by oslo.context and exposed to services for scope checks using context.scope = ‘system’ or some other method. The process of relaying this information to the consuming service will contain follow on work to the oslo.context library to ensure it handles system-scoped tokens properly. The primary purpose of this specification is to allow for the scoping of roles at a system level and exposing that ability to end users. Work can be done in parallel to consume this information in policy files or shared libraries.
System Roles, Implied Roles, & Inherited Roles¶
Keystone supports other types of role behaviors. An administrator can have one
role imply another, or have roles be inherited according to the hierarchical
structure of projects. For example, if role Alpha
implies role Beta
, a
user with role Alpha
will automatically be given role Beta
on the
target, since it’s implied. Another example is if a role assignment is allowed
to be inherited through a tree of projects. For example, if project C
is
the parent of project D
and a user has role Echo
on project C
, the
user also has role Echo
on project D
via role inheritance. These
concepts are known respectively, as implied roles and inherited roles.
Part of introducing a system scoping mechanism is understanding how it applies to these concepts. It is possible to apply both of these concepts to system roles. A role assigned to a user on the system should be able to imply other roles. There have been discussions about making the system a hierarchy structure in the future. For example, what if a system was actually a tree of regions. That would introduce another level of scope that allows users to have role assignments on subsets of the entire system. This seems like a powerful idea, but it does need more thought and discussion. For the time being, system will be a single entity, but built to be refactored into a hierarchy later.
In conclusion, the initial implementation of system roles should support implied role assignment. It should be flexible enough to support inherited roles if the system entity ever evolves into a tree of regions or services.
Alternatives¶
An alternative to this approach would be to leverage the admin_project in order to achieve global scoping. The admin_project is a special project that allows for elevated privileges if role assignments are given to that project. Let’s consider the following example. Let’s say there is an observer role that allows users to perform read-only operations within a specific scope. If Bob has the observer role on project foo, he should be able to view things within that project. If Alice has the observer role on the admin_project, she should be able to view things across the deployment, like services and endpoints.
In this model, system scope is determined by a specific project and the role assignments that project has. Every user that requires a system role (i.e. admin, observer, support, etc) in a deployment will be required to have a role assignment on the admin_project.
Benefits:
Reuse of existing project scope mechanisms/tokens
Leveraging the is_admin_project attribute of tokens
Most of this work is already done
Not necessary to change how scope is stored
Drawbacks:
Automated tooling might have to handle this project separately (i.e. coding around an implementation detail of how policy is elevated) to ensure nothing happens to the admin_project
Operators may find it confusing to have a role on a super-special project in order to have elevated privileges, which seems like an anti-pattern
All users that require a system role of some kind must have a role assignment on the admin_project, this could result in a large number of role assignments on the admin_project
Develop some sort of recovery plan in the event the admin_project is accidentally deleted
Certain resources can’t belong in system scope today (i.e. instances must be tied to a project), this approach doesn’t stop users from creating resources within the admin_project, which would be the equivalent to a system-wide instance
How does the admin_project conform to project hierarchy? Is it suppose to be kept in it’s own subtree under the default domain or can it have child projects underneath it?
Roadmap¶
The is_admin_project implementation exists in OpenStack today, is relayed through keystone APIs, and present in some service policy files. It makes sense to have compatibility for both moving forward. The roadmap put together at the Queens PTG shows how we can improve admin-ness using both approaches but end up in a place where system scope is required.
Security Impact¶
This type of scoping will allow OpenStack services to separate system operations from project or domain scoped operations. The result will be an improved security model across OpenStack. Note that a system-scoped token is still a bearer token and allows the holder the ability to do things on the deployment system.
Notifications Impact¶
System scoping will be subject to the same notifications as project or domain scope requests.
Other End User Impact¶
This is highly dependent on how operators have configured their policy across OpenStack. Ideally, this will give operators more tools to provide better security in their deployments.
Performance Impact¶
None.
Other Deployer Impact¶
Deployers will now have the ability to control system operations by leveraging system role assignments. The ability will be available by default but a migration won’t be supplied to migrate existing policy workarounds since policy can vary wildly across deployments.
An upgrade document can be provided to help operators visualize the process and apply it to their specific policy scenario.
Developer Impact¶
This work will most-likely require some changes to testing both inside and outside of keystone, in order to guarantee isolation of system operations from project operations. Mitigating this will be a required work item of the implementation.
Implementation¶
Assignee(s)¶
- Primary assignee:
Lance Bragstad <lbragstad@gmail.com> lbragstad
- Other contributors:
None
Work Items¶
Add a new database table to support system assignments
Implement system role assignments
Implement scoping a token to a system context
Migrate tempest testing to leverage system roles
Clearly document possible upgrade paths for operators
Implement system context in oslo.policy and keystonemiddleware
Follow on work items should be done to ensure system role assignments are honored within policies across OpenStack:
Ensure default policies adhere to system scope
Ensure scope checks across projects enforce system scope
Dependencies¶
None.
Documentation Impact¶
We will need to provide a more consistent authentication document that clearly explains scope at the project and system level. A separate document that describes possible upgrade paths from the existing system will also be a requirement.
References¶
None.