..
 This work is licensed under a Creative Commons Attribution 3.0 Unported
 License.

 http://creativecommons.org/licenses/by/3.0/legalcode

==========================================
Role-based Access Control for QoS policies
==========================================

https://bugs.launchpad.net/neutron/+bug/1512587

Add a Role-based Access Control for QoS policies in Neutron.


Problem Description
===================

Currently, in neutron QoS policies cannot be shared across subsets of tenants. This proposal
talks about using RBAC [1]_ for QoS policies and making them shareable across tenants.


Proposed Change
===============

Introduce a new QosPolicyRBAC table that will control sharing of Neutron QoS policies between
tenants. The existing logic of shared policies will then be updated to leverage the new RBAC
code as the first implementation. The current ‘shared’ attribute on the qos-policy will be
presented as a wildcard entry in the new table to preserve backwards API compatibility
(more details below).

This specification only impacts which users are allowed to apply the qos-policies - not how
they apply or what happens afterwards. As this feature leverages the existing RBAC code, it
will be a whitelist-only model. i.e. the action column can’t be a negative that states a certain
tenant can’t do something. Tenants will be able to delete policies they own, however the
deletion will be forbidden in case the policy is shared and being used (e.g. attached to other
tenant's network).

Data Model Impact
-----------------

Add a model of RBAC for qos policy, Using the existing RBAC for Data model as reference [2]_.

QosPolicyRBAC Table structure:

+---------------+--------+--------+-----------+-------------+------------------+
| Attribute     | Type   | Access | Default   | Validation/ | Description      |
| Name          |        |        | Value     | Conversion  |                  |
+===============+========+========+===========+=============+==================+
| id            | string | R      | generated | N/A         | id of RBAC entry |
|               | (UUID) |        |           |             |                  |
+---------------+--------+--------+-----------+-------------+------------------+
| tenant_id     | string | R      | auto      | N/A         | owner of RBAC    |
|               | (UUID) |        |           |             | entry            |
+---------------+--------+--------+-----------+-------------+------------------+
| object_id     | string | RW     | N/A       | object      | object           |
|               | (UUID) |        |           | exists      | affected by RBAC |
+---------------+--------+--------+-----------+-------------+------------------+
| object_type   | string | RW     | N/A       | type has    | type of object   |
|               |        |        |           | RBAC table  |                  |
+---------------+--------+--------+-----------+-------------+------------------+
| target_tenant | string | RWU    | *         | string      | tenant ID the    |
|               |        |        |           |             | entry affects.   |
|               |        |        |           |             | * for all        |
+---------------+--------+--------+-----------+-------------+------------------+
| action        | string | RW     | N/A       | in actions  | allowed tenant   |
|               |        |        |           | for object  | action on object |
+---------------+--------+--------+-----------+-------------+------------------+


Example Entries
---------------

A legacy shared qos policy:

* object_id = <some_qos policy_id>
* target_tenant = '*'
* action = 'access_as_shared'
* id = <uuid>  # auto generated
* tenant_id = <uuid-of-policy-creator>  # generated by API

A qos policy shared to a specific tenant:

* object_id = <some_qos policy_id>
* target_tenant = <some_tenant_id>
* action = 'access_as_shared'
* id = <uuid>  # auto generated
* tenant_id = <uuid-of-policy-creator>  # generated by API

All entries are to allow the action they describe. There won’t be any ‘deny’ rules at this time.

The object ID is simply the UUID of the policies to which the RBAC entry will be applied.

The target_tenant will be the tenant (a.k.a. project) ID to which the RBAC entry is granting
permission to perform an action on the target object. This entry may also be an asterisk to
represent that it applies to all tenants.

The action will describe what the tenant can do with the object. This specification deals with
only one action - ‘access_as_shared’ to indicate that the tenant can access it like it would a
shared policy. This could then be extended in the future to include something like ‘deny’ to
provide RBAC for blacklisting as well. Supported actions are discoverable via the API.

Finally, each RBAC entry will also have a tenant ID that indicates the tenant that created the
policy itself. This will normally be the same tenant as the object being shared, but it might
not be in the case of admin-created policies for other tenants.

REST API Impact
---------------

Existing RBAC API's will be extended to take new parameter - a new 'object-type' option would be
added to the existing CLI.

::

    {
        'rbac_policy': {
            'action': 'access_as_shared',
            'tenant_id': 'cc4abd64f6e5409da3ae6c04124f6d37',
            'object_type': 'qos-policy',
            'target_tenant': '1b245fd28a13435bb075dadac5951f8d',
            'object_id': 'f60eb0dc-ce07-419c-aa80-1114aafd38a7',
        }
    }


Security Impact
---------------

Tenants will be able to share qos policies with each other. This shouldn’t be a major issue, since
the ownership will never change. Effectively, each tenant will be responsible for its policy
utilization.


Notifications Impact
--------------------

N/A


Other End User Impact
---------------------
The end user will be able to specify the qos policy as object-type.
A new 'object-type' option would be added to the existing CLI. No new CLI is required.

Attach a new RBAC to an existing qos-policy:

::

    neutron rbac-create <qos-policy-uuid|qos-policy-name> --type qos-policy --target-tenant \
        <tenant-uuid> --action access_as_shared <RBAC_OBJECT>

There should be no impact to the regular global shared qos policy workflow. The new API usage will
only be required for fine-grained entries.

From the perspective of a tenant that has a policy shared to it, the policy will show up as ‘shared’
just like a globally shared policy would.


Performance Impact
------------------

Checking the 'shared' attribute for the qos-policy will now involve a join to another table.
Same goes with respect to policy listing and updating.


IPv6 Impact
-----------

N/A


Developer Impact
----------------

N/A


Community Impact
----------------

This change shouldn't impact the community in any major way as the legacy API remains.

Work Items
----------
* Add the DB model.
* Adjust existing 'shared' attribute to use rbac and add migration script.
* Update the client to CRUD the new RBACs type.
* Add UTs to Neutron server.
* Add API tests.


Dependencies
============

N/A


Testing
=======

Tempest Tests
-------------

No tests are required. API tests should be sufficient.


Functional Tests
----------------

No functional test is likely necessary for this work. All of this is
at the API layer without impacting the dataplane.


API Tests
---------
* Excercise basic CRUD of RBAC entries.
* Make sure qos policies are revealed and hidden as RBAC entries are changed


Documentation Impact
====================

User Documentation
------------------

The workflow for adding RBAC for qos policy entries will need to be added to [3]_.


References
==========
.. [1] Role-based access control for networks,
   https://specs.openstack.org/openstack/neutron-specs/specs/liberty/rbac-networks.html
.. [2] RBAC Data model,
   https://specs.openstack.org/openstack/neutron-specs/specs/liberty/rbac-networks.html#data-model-impact
.. [3] Qos User Configuration guide,
   http://docs.openstack.org/liberty/networking-guide/adv_config_qos.html