blob: d0fe27e970405885c44695e2dacea9f6fa4d6e09 [file] [log] [blame]
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +00001.. _rbac-utils:
2
Felipe Monteiro144ec1e2017-12-26 17:38:11 +00003RBAC Utils Module
4=================
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +00005
6Overview
7--------
8
9Patrole manipulates the ``os_primary`` `Tempest credentials`_, which are the
10primary set of Tempest credentials. It is necessary to use the same credentials
11across the entire test setup/test execution/test teardown workflow
12because otherwise 400-level errors will be thrown by OpenStack services.
13
14This is because many services check the request context's project scope -- and
15in very rare cases, user scope. However, each set of Tempest credentials (via
16`dynamic credentials`_) is allocated its own distinct project. For example, the
17``os_admin`` and ``os_primary`` credentials each have a distinct project,
18meaning that it is not always possible for the ``os_primary`` credentials to
19access resources created by the ``os_admin`` credentials.
20
21The only foolproof solution is to manipulate the role for the same set of
22credentials, rather than using distinct credentials for setup/teardown
23and test execution, respectively. This is especially true when considering
24custom policy rule definitions, which can be arbitrarily complex.
25
Felipe Monteiro543f7b92018-06-10 13:38:31 -040026.. _role-overriding:
27
28Role Overriding
29^^^^^^^^^^^^^^^
30
31Role overriding is the way Patrole is able to create resources and delete
32resources -- including those that require admin credentials -- while still
33being able to exercise the same set of Tempest credentials to perform the API
34action that authorizes the policy under test, by manipulating the role of
35the Tempest credentials.
36
37Patrole implicitly splits up each test into 3 stages: set up, test execution,
38and teardown.
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +000039
40The role workflow is as follows:
41
42#. Setup: Admin role is used automatically. The primary credentials are
43 overridden with the admin role.
Felipe Monteiro144ec1e2017-12-26 17:38:11 +000044#. Test execution: ``[patrole] rbac_test_role`` is used manually via the
45 call to ``with rbac_utils.override_role(self)``. Everything that
46 is executed within this contextmanager uses the primary
47 credentials overridden with the ``[patrole] rbac_test_role``.
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +000048#. Teardown: Admin role is used automatically. The primary credentials have
49 been overridden with the admin role.
50
51.. _Tempest credentials: https://docs.openstack.org/tempest/latest/library/credential_providers.html
52.. _dynamic credentials: https://docs.openstack.org/tempest/latest/configuration.html#dynamic-credentials
53
54Test Setup
55----------
56
Felipe Monteiro543f7b92018-06-10 13:38:31 -040057Automatic role override in background.
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +000058
59Resources can be set up inside the ``resource_setup`` class method that Tempest
60provides. These resources are typically reserved for "expensive" resources
61in terms of memory or storage requirements, like volumes and VMs. These
62resources are **always** created via the admin role; Patrole automatically
63handles this.
64
65Like Tempest, however, Patrole must also create resources inside tests
66themselves. At the beginning of each test, the primary credentials have already
67been overridden with the admin role. One can create whatever test-level
68resources one needs, without having to worry about permissions.
69
70Test Execution
71--------------
72
Felipe Monteiro543f7b92018-06-10 13:38:31 -040073Manual role override required.
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +000074
75"Test execution" here means calling the API endpoint that enforces the policy
76action expected by the ``rbac_rule_validation`` decorator. Test execution
77should be performed *only after* calling
Felipe Monteiro144ec1e2017-12-26 17:38:11 +000078``with rbac_utils.override_role(self)``.
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +000079
80Immediately after that call, the API endpoint that enforces the policy should
81be called.
82
Felipe Monteiro144ec1e2017-12-26 17:38:11 +000083Examples
84^^^^^^^^
85
86Always use the contextmanager before calling the API that enforces the
87expected policy action.
88
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +000089Example::
90
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +000091 @rbac_rule_validation.action(
92 service="nova",
93 rule="os_compute_api:os-aggregates:show")
94 def test_show_aggregate_rbac(self):
Felipe Monteiro144ec1e2017-12-26 17:38:11 +000095 # Do test setup before the ``override_role`` call.
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +000096 aggregate_id = self._create_aggregate()
Felipe Monteiro144ec1e2017-12-26 17:38:11 +000097 # Call the ``override_role`` method so that the primary credentials
98 # have the test role needed for test execution.
99 with self.rbac_utils.override_role(self):
100 self.aggregates_client.show_aggregate(aggregate_id)
101
102When using a waiter, do the wait outside the contextmanager. "Waiting" always
103entails executing a ``GET`` request to the server, until the state of the
104returned resource matches a desired state. These ``GET`` requests enforce
105a different policy than the one expected. This is undesirable because
106Patrole should only test policies in isolation from one another.
107
108Otherwise, the test result will be tainted, because instead of only the
109expected policy getting enforced with the ``os_primary`` role, at least
110two policies get enforced.
111
112Example using waiter::
113
114 @rbac_rule_validation.action(
115 service="nova",
116 rule="os_compute_api:os-admin-password")
117 def test_change_server_password(self):
118 original_password = self.servers_client.show_password(
119 self.server['id'])
120 self.addCleanup(self.servers_client.change_password, self.server['id'],
121 adminPass=original_password)
122
123 with self.rbac_utils.override_role(self):
124 self.servers_client.change_password(
125 self.server['id'], adminPass=data_utils.rand_password())
126 # Call the waiter outside the ``override_role`` contextmanager, so that
127 # it is executed with admin role.
128 waiters.wait_for_server_status(
129 self.servers_client, self.server['id'], 'ACTIVE')
130
131Below is an example of a method that enforces multiple policies getting
132called inside the contextmanager. The ``_complex_setup_method`` below
133performs the correct API that enforces the expected policy -- in this
134case ``self.resources_client.create_resource`` -- but then proceeds to
135use a waiter.
136
137Incorrect::
138
139 def _complex_setup_method(self):
140 resource = self.resources_client.create_resource(
141 **kwargs)['resource']
142 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
143 self._delete_resource, resource)
144 waiters.wait_for_resource_status(
145 self.resources_client, resource['id'], 'available')
146 return resource
147
148 @rbac_rule_validation.action(
149 service="example-service",
150 rule="example-rule")
151 def test_change_server_password(self):
152 # Never call a helper function inside the contextmanager that calls a
153 # bunch of APIs. Only call the API that enforces the policy action
154 # contained in the decorator above.
155 with self.rbac_utils.override_role(self):
156 self._complex_setup_method()
157
158To fix this test, see the "Example using waiter" section above. It is
159recommended to re-implement the logic in a helper method inside a test such
160that only the relevant API is called inside the contextmanager, with
161everything extraneous outside.
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +0000162
163Test Cleanup
164------------
165
Felipe Monteiro543f7b92018-06-10 13:38:31 -0400166Automatic role override in background.
Felipe Monteiroc8ec1f62017-11-15 08:32:56 +0000167
168After the test -- no matter whether it ended successfully or in failure --
169the credentials are overridden with the admin role by the Patrole framework,
170*before* ``tearDown`` or ``tearDownClass`` are called. This means that
171resources are always cleaned up using the admin role.
172
173Implementation
174--------------
175
176.. automodule:: patrole_tempest_plugin.rbac_utils
177 :members:
178 :private-members:
Felipe Monteiro9358f742018-09-12 14:49:43 -0600179 :special-members: