From d3fddec498c6cae8d15da72f62c5502dcbf2f4c4 Mon Sep 17 00:00:00 2001 From: Lance Bragstad Date: Tue, 16 Feb 2021 16:27:13 +0000 Subject: [PATCH] Implement basic protection testing jobs This commit lays down a basic structure for protection tests. These are useful for testing various secure RBAC personas, but leveraging all the dynamic credential work in tempest's authentication libraries to provision clients for testing. We're also adding a non-voting protection test job so that we can integrate protection testing into the cinder gate as we work through policy changes. This commit also adds some basic tests exercising the capabilities admin-only API. These tests ensure that only operators (e.g., system-administrators) or formally known as project-administrators, can access the capabilities API. Assertions and functionality in these tests may expand in the future to accomodate system-scope when cinder can properly consume system-scoped tokens from keystone. For now, the tests assume project-administrators are deployment operators, which is the legacy way of denoting "admin-ness" in OpenStack deployments. Depends-On: https://review.opendev.org/c/openstack/tempest/+/778753 Change-Id: I6d4ae6d516f4c2dda4dcb6b974857b34f2ef2254 --- .zuul.yaml | 23 ++++++ cinder_tempest_plugin/rbac/__init__.py | 0 cinder_tempest_plugin/rbac/v3/__init__.py | 0 cinder_tempest_plugin/rbac/v3/base.py | 42 ++++++++++ .../rbac/v3/test_capabilities.py | 80 +++++++++++++++++++ 5 files changed, 145 insertions(+) create mode 100644 cinder_tempest_plugin/rbac/__init__.py create mode 100644 cinder_tempest_plugin/rbac/v3/__init__.py create mode 100644 cinder_tempest_plugin/rbac/v3/base.py create mode 100644 cinder_tempest_plugin/rbac/v3/test_capabilities.py diff --git a/.zuul.yaml b/.zuul.yaml index 87f89f0..4c33fed 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -14,6 +14,9 @@ - cinder-tempest-plugin-basic-victoria - cinder-tempest-plugin-basic-ussuri - cinder-tempest-plugin-basic-train + # Set this job to voting once we have some actual tests to run + - cinder-tempest-plugin-protection-functional: + voting: false gate: jobs: - cinder-tempest-plugin-lvm-lio-barbican @@ -25,6 +28,26 @@ - cinder-tempest-plugin-cbak-ceph-ussuri - cinder-tempest-plugin-cbak-ceph-train +- job: + name: cinder-tempest-plugin-protection-functional + parent: devstack-tempest + required-projects: + - opendev.org/openstack/cinder-tempest-plugin + - opendev.org/openstack/cinder + vars: + tox_envlist: all + tempest_test_regex: 'cinder_tempest_plugin.rbac' + devstack_local_conf: + test-config: + $CINDER_CONF: + oslo_policy: + enforce_new_defaults: True + $TEMPEST_CONFIG: + enforce_scope: + cinder: True + tempest_plugins: + - cinder-tempest-plugin + - job: name: cinder-tempest-plugin-lvm-barbican-base-abstract description: | diff --git a/cinder_tempest_plugin/rbac/__init__.py b/cinder_tempest_plugin/rbac/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cinder_tempest_plugin/rbac/v3/__init__.py b/cinder_tempest_plugin/rbac/v3/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cinder_tempest_plugin/rbac/v3/base.py b/cinder_tempest_plugin/rbac/v3/base.py new file mode 100644 index 0000000..d1a11e5 --- /dev/null +++ b/cinder_tempest_plugin/rbac/v3/base.py @@ -0,0 +1,42 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from tempest import config + +CONF = config.CONF + + +class VolumeV3RbacBaseTests(object): + + identity_version = 'v3' + + @classmethod + def skip_checks(cls): + super(VolumeV3RbacBaseTests, cls).skip_checks() + if not CONF.enforce_scope.cinder: + raise cls.skipException( + "Tempest is not configured to enforce_scope for cinder, " + "skipping RBAC tests. To enable these tests set " + "`tempest.conf [enforce_scope] cinder=True`." + ) + + def do_request(self, method, expected_status=200, client=None, **payload): + if not client: + client = self.client + if isinstance(expected_status, type(Exception)): + self.assertRaises(expected_status, + getattr(client, method), + **payload) + else: + response = getattr(client, method)(**payload) + self.assertEqual(response.response.status, expected_status) + return response diff --git a/cinder_tempest_plugin/rbac/v3/test_capabilities.py b/cinder_tempest_plugin/rbac/v3/test_capabilities.py new file mode 100644 index 0000000..1fa542d --- /dev/null +++ b/cinder_tempest_plugin/rbac/v3/test_capabilities.py @@ -0,0 +1,80 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc + +from tempest.lib import exceptions + +from cinder_tempest_plugin.api.volume import base +from cinder_tempest_plugin.rbac.v3 import base as rbac_base + + +class VolumeV3RbacCapabilityTests(rbac_base.VolumeV3RbacBaseTests, + metaclass=abc.ABCMeta): + + @classmethod + def setup_clients(cls): + super().setup_clients() + cls.persona = getattr(cls, 'os_%s' % cls.credentials[0]) + cls.client = cls.persona.volume_capabilities_client_latest + # NOTE(lbragstad): This admin_client will be more useful later when + # cinder supports system-scope and we need it for administrative + # operations. For now, keep os_project_admin as the admin client until + # we have system-scope. + admin_client = cls.os_project_admin + cls.admin_capabilities_client = ( + admin_client.volume_capabilities_client_latest) + cls.admin_stats_client = ( + admin_client.volume_scheduler_stats_client_latest) + + @classmethod + def setup_credentials(cls): + super().setup_credentials() + cls.os_primary = getattr(cls, 'os_%s' % cls.credentials[0]) + + @abc.abstractmethod + def test_get_capabilities(self): + """Test volume_extension:capabilities policy. + + This test must check: + * whether the persona can fetch capabilities for a host. + + """ + pass + + +class ProjectAdminTests(VolumeV3RbacCapabilityTests, base.BaseVolumeTest): + + credentials = ['project_admin', 'system_admin'] + + def test_get_capabilities(self): + pools = self.admin_stats_client.list_pools()['pools'] + host_name = pools[0]['name'] + self.do_request('show_backend_capabilities', expected_status=200, + host=host_name) + + +class ProjectMemberTests(ProjectAdminTests, base.BaseVolumeTest): + + credentials = ['project_member', 'project_admin', 'system_admin'] + + def test_get_capabilities(self): + pools = self.admin_stats_client.list_pools()['pools'] + host_name = pools[0]['name'] + self.do_request('show_backend_capabilities', + expected_status=exceptions.Forbidden, + host=host_name) + + +class ProjectReaderTests(ProjectMemberTests, base.BaseVolumeTest): + + credentials = ['project_reader', 'project_admin', 'system_admin']