blob: 51940d7feebec833e97a431f39061cb9fb08b1d7 [file] [log] [blame]
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +01001========
2Overview
3========
DavidPurcell663aedf2017-01-03 10:01:14 -05004
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +01005Patrole is a tool for verifying that Role-Based Access Control is being
6correctly enforced.
DavidPurcell663aedf2017-01-03 10:01:14 -05007
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +01008Patrole allows users to run API tests using specified RBAC roles. This allows
DavidPurcell663aedf2017-01-03 10:01:14 -05009deployments to verify that only intended roles have access to those APIs.
10This is critical to ensure security, especially in large deployments with
11custom roles.
12
13* Free software: Apache license
Van Hung Pham31b968d2017-06-05 18:45:16 +070014* Documentation: https://docs.openstack.org/developer/patrole
15* Source: https://git.openstack.org/cgit/openstack/patrole
16* Bugs: https://bugs.launchpad.net/patrole
DavidPurcell663aedf2017-01-03 10:01:14 -050017
18Features
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +010019========
20Patrole offers RBAC testing for various OpenStack RBAC policies. It includes
DavidPurcell45bc1a62017-01-19 17:21:27 -050021a decorator that wraps around tests which verifies that when the test calls the
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +010022corresponding API endpoint, access is only granted for correct roles.
23
24Currently, Patrole supports policies contained in code and in policy.json files.
25If both exist, the policy actions in the policy.json are prioritized.
26
Samantha Blancobbde0222017-05-04 15:29:56 -040027Stable Interface
28----------------
29Patrole offers a stable interface that is guaranteed to be backwards compatible and
30can be directly consumed by other projects. Currently, rbac_exceptions.py and
31rbac_policy_parser.py are guaranteed to be stable.
32
33Release Versioning
34------------------
35`Patrole Release Notes <https://docs.openstack.org/releasenotes/patrole/>`_ show
36what changes have been released.
37
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +010038.. _test-flows:
39
40Test Flows
41----------
DavidPurcell45bc1a62017-01-19 17:21:27 -050042There are several possible test flows.
43
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +010044If the ``rbac_test_role`` is allowed to access the endpoint:
DavidPurcell45bc1a62017-01-19 17:21:27 -050045
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +010046* The test passes if no 403 ``Forbidden`` or ``RbacActionFailed`` exception is raised.
47
48If the ``rbac_test_role`` is not allowed to access the endpoint:
49
50* If the endpoint returns a 403 `Forbidden` exception the test will pass.
51* If the endpoint returns successfully, then the test will fail with an
52 ``RbacOverPermission`` exception.
53* If the endpoint returns something other than a 403 ``Forbidden`` to indicate
54 that the role is not allowed, the test will raise an ``RbacActionFailed`` exception.
55
56.. note::
57
58 Certain services like Neutron *intentionally* raise a 404 instead of a 403
59 for security concerns. Patrole accomodates this behavior by anticipating
Samantha Blancobbde0222017-05-04 15:29:56 -040060 a 404 instead of a 403, using the ``expected_exception`` argument. For more
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +010061 information about Neutron's policy enforcement, see:
62 `<https://docs.openstack.org/developer/neutron/devref/policy.html#request-authorization>`__.
63
64How It Works
65============
66Patrole leverages oslo_policy (OpenStack's policy enforcement engine) to
67determine whether a given role is allowed to perform a policy action given a
68specific rule and OpenStack service. This is done before test execution inside
69the ``rbac_rule_validation.action`` decorator. Then, inside the test, the API
70that does policy enforcement for the same rule is called. The outcome is
71compared against the result from oslo_policy and a pass or fail is determined
72as outlined above: :ref:`test-flows`.
73
74.. note::
75
76 Currently, Patrole does not support checking multiple rules against a single
77 API call. Even though some APIs enforce multiple rules (some indirectly),
78 it is increasingly difficult to maintain the tests if multiple policy
79 actions are expected to be called.
80
81Test Execution Workflow
82-----------------------
Felipe Monteiro7bc35dc2017-04-19 21:11:46 +010083The workflow is as follows:
84
85#. Each test uses the ``rbac_rule_validation.action`` decorator, like below: ::
86
87 @rbac_rule_validation.action(
88 service="nova",
89 rule="os_compute_api:servers:stop")
90 @decorators.idempotent_id('ab4a17d2-166f-4a6d-9944-f17baa576cf2')
91 def test_stop_server(self):
92 # Set the primary credential's role to "rbac_test_role".
93 self.rbac_utils.switch_role(self, toggle_rbac_role=True)
94 # Call the API that enforces the policy action specified by "rule".
95 self._test_stop_server()
96
97 The ``service`` attribute accepts an OpenStack service and the ``rule`` attribute
98 accepts a valid OpenStack policy action, like "os_compute_api:servers:stop".
99
100#. The ``rbac_rule_validation.action`` decorator passes these attributes,
101 along with user_id and project_id information derived from the primary
102 Tempest credential (``self.os.credentials.user_id`` and ``self.os.credentials.project_id``),
103 to the ``rbac_policy_parser``.
104
105#. The logic in ``rbac_policy_parser`` then passes all this information along
106 and the role in ``CONF.rbac.rbac_test_role`` to oslo_policy to determine whether
107 the ``rbac_test_role`` is authorized to perform the policy action for the given
108 service.
109
110#. After all of the logic above has executed inside the rbac decorator, the
111 test is executed. The test then sets up test-level resources, if necessary,
112 with **admin** credentials implicitly. This is accomplished through
113 ``rbac_utils.switch_role(toggle_rbac_role=False)``: ::
114
115 @classmethod
116 def setup_clients(cls):
117 super(BaseV2ComputeRbacTest, cls).setup_clients()
118 cls.auth_provider = cls.os.auth_provider
119 cls.rbac_utils = rbac_utils()
120 cls.rbac_utils.switch_role(cls, toggle_rbac_role=False)
121
122 This code has *already* executed when the test class is instantiated, because
123 it is located in the base rbac test class. Whenever ``cls.rbac_utils.switch_role``
124 is called, one of two behaviors are possible:
125
126 #. The primary credential's role is changed to admin if ``toggle_rbac_role=False``
127 #. The primary credential's role is changed to ``rbac_test_role`` if
128 ``toggle_rbac_role=True``
129
130 Thus, at the *beginning* of every test and during ``resource_setup`` and
131 ``resource_cleanup``, the primary credential has the admin role.
132
133#. After preliminary test-level setup is performed, like creating a server, a
134 second call to ``self.rbac_utils.switch_role`` is done: ::
135
136 self.rbac_utils.switch_role(cls, toggle_rbac_role=True)
137
138 Now the primary credential has the role specified by ``rbac_test_role``.
139
140#. The API endpoint in which policy enforcement of "os_compute_api:servers:stop"
141 is performed can now be called.
142
143 .. note:
144
145 To determine whether a policy action is enforced, refer to the relevant
146 controller code to make sure that the policy action is indeed enforced.
147
148#. Now that a call is made to "stop_server" with the primary credentials having
149 the role specified by ``rbac_test_role``, either the nova contoller will allow
150 or disallow the action to be performed. Since the "stop_server" policy action in
151 nova is defined as "base.RULE_ADMIN_OR_OWNER", the API will most likely
152 return a successful status code. For more information about this policy action,
153 see `<https://github.com/openstack/nova/blob/master/nova/policies/servers.py>`__.
154
155#. As mentioned above, the result from the API call and the result from oslo_policy
156 are compared for consistency.
157
158#. Finally, after the test has executed, but before ``tearDown`` or ``resource_cleanup``
159 is called, ``self.rbac_utils.switch_role(cls, toggle_rbac_role=False)`` is
160 called, so that the primary credential yet again has admin permissions for
161 test clean up. This call is always performed in the "finally" block inside
162 the ``rbac_rule_validation`` decorator.
163
164.. warning::
165
166 Failure to call ``self.rbac_utils.switch_role(cls, toggle_rbac_role=True)``
167 inside a test with the ``rbac_rule_validation`` decorator applied results
168 in a ``RbacResourceSetupFailed`` being raised, causing the test to fail.