286 lines
11 KiB
ReStructuredText
286 lines
11 KiB
ReStructuredText
.. _rbac-overview:
|
|
|
|
==================================
|
|
Role-Based Access Control Overview
|
|
==================================
|
|
|
|
Introduction
|
|
------------
|
|
|
|
Role-Based Access Control (RBAC) is used by most OpenStack services to control
|
|
user access to resources. Authorization is granted if a user has the necessary
|
|
role to perform an action. Patrole is concerned with validating that each of
|
|
these resources *can* be accessed by authorized users and *cannot* be accessed
|
|
by unauthorized users.
|
|
|
|
OpenStack services use `oslo.policy`_ as the library for RBAC authorization.
|
|
Patrole relies on the same library for deriving expected test results.
|
|
|
|
.. _policy-in-code:
|
|
|
|
Policy in Code
|
|
--------------
|
|
|
|
Services publish their policy-to-API mapping via policy in code documentation.
|
|
This mapping includes the list of APIs that authorize a policy, for each
|
|
policy declared within a service.
|
|
|
|
For example, Nova's policy in code documentation is located in the
|
|
`Nova repository`_ under ``nova/policies``. Likewise, Keystone's policy in
|
|
code documentation is located in the `Keystone repository`_ under
|
|
``keystone/common/policies``. The other OpenStack services follow the same
|
|
directory layout pattern with respect to policy in code.
|
|
|
|
The policy in code `governance goal`_ enumerates many advantages with following
|
|
this RBAC design approach. A so-called library of in-code policies offers the
|
|
following advantages, with respect to facilitating validation:
|
|
|
|
* includes every policy enforced by an OpenStack service, enabling the
|
|
possibility of complete Patrole test coverage for that service (otherwise
|
|
one has to read the source code to discover all the policies)
|
|
* provides the policy-to-API mapping for each policy which can be used
|
|
to write correct Patrole tests (otherwise reading source code and
|
|
experimentation are required to derive this mapping)
|
|
* by extension, the policy-to-API mapping facilitates writing multi-policy
|
|
Patrole tests (otherwise even more experimentation and code reading is
|
|
required to arrive at all the policies enforced by an API)
|
|
* policy in code documentation includes additional information, like
|
|
descriptions and (in the case of some services, like Keystone)
|
|
`scope types`_, which help with understanding how to correctly write
|
|
Patrole tests
|
|
* by extension, such information helps to determine whether a Patrole test
|
|
should assume :term:`hard authorization` or :term:`soft authorization`
|
|
|
|
Policy in Code (Default) Validation
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
By default, Patrole validates default OpenStack policies. This is so that
|
|
the out-of-the-box defaults are sanity-checked, to ensure that OpenStack
|
|
services are secure, from an RBAC perspective, for each release.
|
|
|
|
Patrole strives to validate RBAC by using the policy in code documentation,
|
|
wherever possible. See :ref:`validation-workflow-overview` for more details.
|
|
|
|
.. _custom-policies:
|
|
|
|
Custom Policies
|
|
---------------
|
|
|
|
Operators can override policy in code defaults using `policy.yaml`_. While
|
|
this allows operators to offer more fine-grained RBAC control to their tenants,
|
|
it opens the door to misconfiguration and bugs. Patrole can be used to validate
|
|
that custom policy overrides don't break anything and work as expected.
|
|
|
|
Custom Policy Validation
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
While testing default policy behavior is a valid use case, oftentimes default
|
|
policies are modified with custom overrides in production. OpenStack's
|
|
`policy.yaml`_ documentation claims that "modifying policy can have unexpected
|
|
side effects", which is why Patrole was created: to ensure that custom
|
|
overrides allow the principle of least privilege to be tailor-made to exact
|
|
specifications via policy overrides, without:
|
|
|
|
* causing unintended side effects (breaking API endpoints, breaking
|
|
cross-service workflows, breaking the policy file itself); or
|
|
* resulting in poor RBAC configuration, promoting security vulnerabilities
|
|
|
|
This has implications on Patrole's :ref:`design-principles`: validating custom
|
|
overrides requires the ability to handle arbitrary roles, which requires logic
|
|
capable of dynamically determining expected test behavior.
|
|
|
|
Note that support for custom policies is limited. This is because custom
|
|
policies can be arbitrarily complex, requiring that tests be very robust
|
|
in order to handle all edge cases.
|
|
|
|
.. _multiple-policies:
|
|
|
|
Multiple Policies
|
|
-----------------
|
|
|
|
Behind the scenes, many APIs enforce multiple policies, for many reasons,
|
|
including:
|
|
|
|
* to control complex cross-service workflows;
|
|
* to control whether a server is booted from an image or booted from a volume
|
|
(for example);
|
|
* to control whether a response body should contain additional information
|
|
conditioned upon successful policy authorization.
|
|
|
|
This makes `policy in code`_ especially important for policy validation: it
|
|
is difficult to keep track of all the policies being enforced across all the
|
|
individual APIs, without policy in code documentation.
|
|
|
|
Multi-Policy Validation
|
|
^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Patrole offers support for validating APIs that enforce multiple policies.
|
|
Perhaps in an ideal world each API endpoint would enforce only one policy,
|
|
but in reality some API endpoints enforce multiple policies. Thus, to offer
|
|
accurate validation, Patrole handles multiple policies:
|
|
|
|
* for services *with* policy in code documentation: this documentation
|
|
indicates that a single API endpoint enforces multiple policy actions.
|
|
* for services *without* policy in code documentation: the API code clearly
|
|
shows multiple policy actions being validated. Note that in this case some
|
|
degree of log tracing is required by developers to confirm that the expected
|
|
policies are getting enforced, prior to the tests getting merged.
|
|
|
|
For more information, see :ref:`multi-policy-validation`.
|
|
|
|
.. _policy-error-codes:
|
|
|
|
Error Codes
|
|
-----------
|
|
|
|
Most OpenStack services raise a ``403 Forbidden`` following failed
|
|
:term:`hard authorization`. Neutron, however, can raise a ``404 NotFound``
|
|
as well. See Neutron's `authorization policy enforcement`_ documentation
|
|
for more details.
|
|
|
|
Admin Context Policy
|
|
--------------------
|
|
|
|
The so-called "admin context" policy refers to the following policy definition
|
|
(using the legacy policy file syntax):
|
|
|
|
.. code-block:: javascript
|
|
|
|
{
|
|
"context_is_admin": "role:admin"
|
|
...
|
|
}
|
|
|
|
Which is unfortunately used to bypass ``oslo.policy`` authorization checks,
|
|
for example:
|
|
|
|
.. code-block:: python
|
|
|
|
# This function is responsible for calling oslo.policy to check whether
|
|
# requests are authorized to perform an API action.
|
|
def enforce(context, action, target, [...]):
|
|
# Here this condition, if True, skips over the enforce call below which
|
|
# is what calls oslo.policy.
|
|
if context.is_admin:
|
|
return True
|
|
_ENFORCER.enforce([...]) # This is what can be skipped over.
|
|
[...]
|
|
|
|
This type of behavior is currently present in many services. Unless such
|
|
logic is removed in the future for services that implement it, Patrole
|
|
won't really be able to validate that admin role works from an ``oslo.policy``
|
|
perspective.
|
|
|
|
Glossary
|
|
--------
|
|
|
|
The following nomenclature is used throughout Patrole documentation so it is
|
|
important to understand what each term means in order to understand concepts
|
|
related to RBAC in Patrole.
|
|
|
|
.. glossary::
|
|
|
|
authorize
|
|
|
|
The act of ``oslo.policy`` determining whether a user can perform a
|
|
:term:`policy` given his or her :term:`role`.
|
|
|
|
enforce
|
|
|
|
See :term:`authorize`.
|
|
|
|
hard authorization
|
|
|
|
The `do_raise`_ flag controls whether policy authorization should result
|
|
in an exception getting raised or a boolean value getting returned.
|
|
Hard authorization results in an exception getting raised. Usually, this
|
|
results in a ``403 Forbidden`` getting returned for unauthorized requests.
|
|
(See :ref:`policy-error-codes` for further details.)
|
|
|
|
Related term: :term:`soft authorization`.
|
|
|
|
oslo.policy
|
|
|
|
The OpenStack library providing support for RBAC policy enforcement across
|
|
all OpenStack services. See the `official documentation`_ for more
|
|
information.
|
|
|
|
policy
|
|
|
|
Defines an RBAC rule. Each policy is defined by a one-line statement in
|
|
the form "<target>" : "<rule>". For more information, reference OpenStack's
|
|
`policy documentation`_.
|
|
|
|
policy action
|
|
|
|
See :term:`policy target`.
|
|
|
|
policy file
|
|
|
|
Prior to `governance goal`_ used by all OpenStack services to define
|
|
policy defaults. Still used by some services, which is why Patrole
|
|
needs to read the policy files to derive policy information for testing.
|
|
|
|
policy in code
|
|
|
|
Registers default OpenStack policies for a service in the service's code
|
|
base.
|
|
|
|
Beginning with the Queens release, policy in code became a
|
|
`governance goal`_.
|
|
|
|
policy rule
|
|
|
|
The policy rule determines under which circumstances the API call is
|
|
permitted.
|
|
|
|
policy target
|
|
|
|
The name of a policy.
|
|
|
|
requirements file
|
|
|
|
Requirements-driven approach to declaring the expected RBAC test results
|
|
referenced by Patrole. Uses a high-level YAML syntax to crystallize policy
|
|
requirements concisely and unambiguously. See :ref:`requirements-authority`
|
|
for more information.
|
|
|
|
role
|
|
|
|
A designation for the set of actions that describe what a user can do in
|
|
the system. Roles are managed through the `Keystone Roles API`_.
|
|
|
|
Role-Based Access Control (RBAC)
|
|
|
|
May be formally defined as "an approach to restricting system access to
|
|
authorized users."
|
|
|
|
rule
|
|
|
|
See :term:`policy rule`. Note that currently the Patrole code base
|
|
conflates "rule" with :term:`policy target` in some places.
|
|
|
|
soft authorization
|
|
|
|
The `do_raise`_ flag controls whether policy authorization should result
|
|
in an exception getting raised or a boolean value getting returned.
|
|
Soft authorization results in a boolean value getting returned. When policy
|
|
authorization evaluates to true, additional operations are performed as a
|
|
part of the API request or additional information is included in the
|
|
response body (see `response filtering`_ for an example).
|
|
|
|
Related term: :term:`hard authorization`.
|
|
|
|
.. _Nova repository: https://git.openstack.org/cgit/openstack/nova/tree/nova/policies
|
|
.. _Keystone repository: https://git.openstack.org/cgit/openstack/keystone/tree/keystone/common/policies
|
|
.. _governance goal: https://governance.openstack.org/tc/goals/queens/policy-in-code.html
|
|
.. _scope types: https://docs.openstack.org/keystone/latest/admin/tokens-overview.html#authorization-scopes
|
|
.. _policy.yaml: https://docs.openstack.org/ocata/config-reference/policy-yaml-file.html
|
|
.. _oslo.policy: https://docs.openstack.org/oslo.policy/latest/
|
|
.. _policy documentation: https://docs.openstack.org/kilo/config-reference/content/policy-json-file.html
|
|
.. _do_raise: https://docs.openstack.org/oslo.policy/latest/reference/api/oslo_policy.policy.html#oslo_policy.policy.Enforcer.enforce
|
|
.. _authorization policy enforcement: https://docs.openstack.org/neutron/latest/contributor/internals/policy.html
|
|
.. _official documentation: https://docs.openstack.org/oslo.policy/latest/
|
|
.. _Keystone Roles API: https://developer.openstack.org/api-ref/identity/v3/#roles
|
|
.. _response filtering: https://docs.openstack.org/neutron/latest/contributor/internals/policy.html#response-filtering
|