Merge "Specification for system roles"

This commit is contained in:
Zuul 2017-11-28 18:00:45 +00:00 committed by Gerrit Code Review
commit c7761acba2
1 changed files with 571 additions and 0 deletions

View File

@ -0,0 +1,571 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=======================
System Role Assignments
=======================
`bp system-scope <https://blueprints.launchpad.net/keystone/+spec/system-scope>`_
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.
After realizing this, it became apparent that *system* is a more appropriate
term than *global* for isolating infrastructure and project operations.
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 role or user doesn't exist
* 401 - If the operation isn't permitted to the user
**Response Body**
.. code:: json
{
"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 role or user doesn't exist
* 401 - If the operation isn't permitted to the user
**Response Body**
.. code:: json
{
"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 user 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
* 400 - Bad Request
* 404 - Not Found if a role or user doesn't exist
* 401 - If the operation isn't permitted to the user
**Response Body**
.. code:: json
{
"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 do 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 <https://etherpad.openstack.org/p/queens-PTG-keystone-policy-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.