a20add27cf
Use admin creds for waiting for all RBAC tests that use waiters after rbac_utils has switched to RBAC role. It is not necessary (though not detrimental either) to do this during tearDown. The reason why this should be done is because "waiting" entails calling a "show" API action in a loop, until the resource reaches a desired status. In other words, a policy action related to the "show" API action is enforced -- which is problematic within the context of RBAC testing. Change-Id: Id4b896b3ad0dff33e70f46a8dda950f7c3b148bf |
||
---|---|---|
devstack | ||
doc/source | ||
patrole_tempest_plugin | ||
releasenotes | ||
.coveragerc | ||
.gitignore | ||
.gitreview | ||
.mailmap | ||
.testr.conf | ||
babel.cfg | ||
CONTRIBUTING.rst | ||
HACKING.rst | ||
LICENSE | ||
README.rst | ||
requirements.txt | ||
setup.cfg | ||
setup.py | ||
test-requirements.txt | ||
test-whitelist.txt | ||
tox.ini |
Team and repository tags
Patrole - RBAC Integration Tempest Plugin
Patrole is a tool for verifying that Role-Based Access Control is being correctly enforced.
Patrole allows users to run API tests using specified RBAC roles. This allows deployments to verify that only intended roles have access to those APIs. This is critical to ensure security, especially in large deployments with custom roles.
- Free software: Apache license
- Documentation: https://docs.openstack.org/developer/patrole
- Source: https://git.openstack.org/cgit/openstack/patrole
- Bugs: https://bugs.launchpad.net/patrole
Features
Patrole offers RBAC testing for various OpenStack RBAC policies. It includes a decorator that wraps around tests which verifies that when the test calls the corresponding API endpoint, access is only granted for correct roles.
Currently, Patrole supports policies contained in code and in policy.json files. If both exist, the policy actions in the policy.json are prioritized.
Stable Interface
Patrole offers a stable interface that is guaranteed to be backwards compatible and can be directly consumed by other projects. Currently, rbac_exceptions.py and rbac_policy_parser.py are guaranteed to be stable.
Release Versioning
Patrole Release Notes show what changes have been released.
Test Flows
There are several possible test flows.
If the rbac_test_role
is allowed to access the
endpoint:
- The test passes if no 403
Forbidden
orRbacActionFailed
exception is raised.
If the rbac_test_role
is not allowed to access the
endpoint:
- If the endpoint returns a 403 Forbidden exception the test will pass.
- If the endpoint returns successfully, then the test will fail with
an
RbacOverPermission
exception. - If the endpoint returns something other than a 403
Forbidden
to indicate that the role is not allowed, the test will raise anRbacActionFailed
exception.
Note
Certain services like Neutron intentionally raise a 404
instead of a 403 for security concerns. Patrole accomodates this
behavior by anticipating a 404 instead of a 403, using the
expected_exception
argument. For more information about
Neutron's policy enforcement, see: https://docs.openstack.org/developer/neutron/devref/policy.html#request-authorization.
How It Works
Patrole leverages oslo_policy (OpenStack's policy enforcement engine)
to determine whether a given role is allowed to perform a policy action
given a specific rule and OpenStack service. This is done before test
execution inside the rbac_rule_validation.action
decorator.
Then, inside the test, the API that does policy enforcement for the same
rule is called. The outcome is compared against the result from
oslo_policy and a pass or fail is determined as outlined above: Test Flows.
Note
Currently, Patrole does not support checking multiple rules against a single API call. Even though some APIs enforce multiple rules (some indirectly), it is increasingly difficult to maintain the tests if multiple policy actions are expected to be called.
Test Execution Workflow
The workflow is as follows:
Each test uses the
rbac_rule_validation.action
decorator, like below: :@rbac_rule_validation.action( service="nova", rule="os_compute_api:servers:stop") @decorators.idempotent_id('ab4a17d2-166f-4a6d-9944-f17baa576cf2') def test_stop_server(self): # Set the primary credential's role to "rbac_test_role". self.rbac_utils.switch_role(self, toggle_rbac_role=True) # Call the API that enforces the policy action specified by "rule". self._test_stop_server()
The
service
attribute accepts an OpenStack service and therule
attribute accepts a valid OpenStack policy action, like "os_compute_api:servers:stop".The
rbac_rule_validation.action
decorator passes these attributes, along with user_id and project_id information derived from the primary Tempest credential (self.os.credentials.user_id
andself.os.credentials.project_id
), to therbac_policy_parser
.The logic in
rbac_policy_parser
then passes all this information along and the role inCONF.rbac.rbac_test_role
to oslo_policy to determine whether therbac_test_role
is authorized to perform the policy action for the given service.After all of the logic above has executed inside the rbac decorator, the test is executed. The test then sets up test-level resources, if necessary, with admin credentials implicitly. This is accomplished through
rbac_utils.switch_role(toggle_rbac_role=False)
, which is done as part of client setup (inside the call torbac_utils.RbacUtils
): :@classmethod def setup_clients(cls): super(BaseV2ComputeRbacTest, cls).setup_clients() cls.auth_provider = cls.os_primary.auth_provider cls.rbac_utils = rbac_utils.RbacUtils(cls) ...
This code has already executed when the test class is instantiated, because it is located in the base rbac test class. Whenever
cls.rbac_utils.switch_role
is called, one of two behaviors are possible:- The primary credential's role is changed to admin if
toggle_rbac_role=False
- The primary credential's role is changed to
rbac_test_role
iftoggle_rbac_role=True
Thus, at the beginning of every test and during
resource_setup
andresource_cleanup
, the primary credential has the admin role.- The primary credential's role is changed to admin if
After preliminary test-level setup is performed, like creating a server, a second call to
self.rbac_utils.switch_role
is done: :self.rbac_utils.switch_role(cls, toggle_rbac_role=True)
Now the primary credential has the role specified by
rbac_test_role
.The API endpoint in which policy enforcement of "os_compute_api:servers:stop" is performed can now be called.
To determine whether a policy action is enforced, refer to the relevant controller code to make sure that the policy action is indeed enforced.
Now that a call is made to "stop_server" with the primary credentials having the role specified by
rbac_test_role
, either the nova contoller will allow or disallow the action to be performed. Since the "stop_server" policy action in nova is defined as "base.RULE_ADMIN_OR_OWNER", the API will most likely return a successful status code. For more information about this policy action, see https://github.com/openstack/nova/blob/master/nova/policies/servers.py.As mentioned above, the result from the API call and the result from oslo_policy are compared for consistency.
Finally, after the test has executed, but before
tearDown
orresource_cleanup
is called,self.rbac_utils.switch_role(cls, toggle_rbac_role=False)
is called, so that the primary credential yet again has admin permissions for test clean up. This call is always performed in the "finally" block inside therbac_rule_validation
decorator.
Warning
Failure to call
self.rbac_utils.switch_role(cls, toggle_rbac_role=True)
inside a test with the rbac_rule_validation
decorator
applied results in a RbacResourceSetupFailed
being raised,
causing the test to fail.