Expand Designate RBAC testing - zones
This patch adds RBAC testing for allowed and disallowed credentials.
This is one of a series of patches adding testing. This patch covers the
zones API.
Change-Id: I2312e0e4293b60d9644f8c0d3a41e0b5f330c20d
diff --git a/designate_tempest_plugin/tests/api/v2/test_blacklists.py b/designate_tempest_plugin/tests/api/v2/test_blacklists.py
index 6dea9ad..cd859af 100644
--- a/designate_tempest_plugin/tests/api/v2/test_blacklists.py
+++ b/designate_tempest_plugin/tests/api/v2/test_blacklists.py
@@ -63,7 +63,7 @@
expected_allowed = ['os_system_admin']
self.check_CUD_RBAC_enforcement('BlacklistsClient', 'create_blacklist',
- expected_allowed)
+ expected_allowed, False)
@decorators.idempotent_id('ea608152-da3c-11eb-b8b8-74e5f9e2a801')
@decorators.skip_because(bug="1934252")
@@ -106,7 +106,7 @@
expected_allowed = ['os_system_admin', 'os_system_reader']
self.check_list_show_RBAC_enforcement(
- 'BlacklistsClient', 'show_blacklist', expected_allowed,
+ 'BlacklistsClient', 'show_blacklist', expected_allowed, False,
blacklist['id'])
@decorators.idempotent_id('dcea40d9-8d36-43cb-8440-4a842faaef0d')
@@ -126,8 +126,9 @@
if CONF.dns_feature_enabled.enforce_new_defaults:
expected_allowed = ['os_system_admin']
- self.check_CUD_RBAC_enforcement('BlacklistsClient', 'delete_blacklist',
- expected_allowed, blacklist['id'])
+ self.check_CUD_RBAC_enforcement(
+ 'BlacklistsClient', 'delete_blacklist', expected_allowed, False,
+ blacklist['id'])
@decorators.idempotent_id('3a2a1e6c-8176-428c-b5dd-d85217c0209d')
def test_list_blacklists(self):
@@ -173,7 +174,7 @@
expected_allowed = ['os_system_admin']
self.check_CUD_RBAC_enforcement(
- 'BlacklistsClient', 'update_blacklist', expected_allowed,
+ 'BlacklistsClient', 'update_blacklist', expected_allowed, False,
uuid=blacklist['id'], pattern=pattern, description=description)
diff --git a/designate_tempest_plugin/tests/api/v2/test_zones.py b/designate_tempest_plugin/tests/api/v2/test_zones.py
index aac3bda..3555c51 100644
--- a/designate_tempest_plugin/tests/api/v2/test_zones.py
+++ b/designate_tempest_plugin/tests/api/v2/test_zones.py
@@ -57,7 +57,6 @@
class ZonesTest(BaseZonesTest):
- credentials = ["admin", "system_admin", "primary"]
@classmethod
def setup_credentials(cls):
@@ -105,6 +104,24 @@
self.assertEqual(const.CREATE, zone['action'])
self.assertEqual(const.PENDING, zone['status'])
+ # Test with no extra header overrides (sudo-project-id)
+ expected_allowed = ['os_admin', 'os_primary', 'os_alt']
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed.append('os_system_admin')
+ expected_allowed.append('os_project_member')
+
+ self.check_CUD_RBAC_enforcement('ZonesClient', 'create_zone',
+ expected_allowed, False)
+
+ # Test with x-auth-sudo-project-id header
+ expected_allowed = ['os_admin']
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed.append('os_system_admin')
+
+ self.check_CUD_RBAC_enforcement(
+ 'ZonesClient', 'create_zone', expected_allowed, False,
+ project_id=self.client.project_id)
+
@decorators.idempotent_id('ec150c22-f52e-11eb-b09b-74e5f9e2a801')
def test_create_zone_validate_recordsets_created(self):
# Create a PRIMARY zone and wait till it's Active
@@ -144,6 +161,27 @@
LOG.info('Ensure the fetched response matches the created zone')
self.assertExpected(zone, body, self.excluded_keys)
+ # TODO(johnsom) Test reader roles once this bug is fixed.
+ # https://bugs.launchpad.net/tempest/+bug/1964509
+ # Test with no extra header overrides (all_projects, sudo-project-id)
+ expected_allowed = ['os_primary']
+
+ self.check_list_show_RBAC_enforcement(
+ 'ZonesClient', 'show_zone', expected_allowed, True, zone['id'])
+
+ # Test with x-auth-all-projects and x-auth-sudo-project-id header
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed = ['os_system_admin']
+ else:
+ expected_allowed = ['os_admin']
+
+ self.check_list_show_RBAC_enforcement(
+ 'ZonesClient', 'show_zone', expected_allowed, False, zone['id'],
+ headers=self.all_projects_header)
+ self.check_list_show_RBAC_enforcement(
+ 'ZonesClient', 'show_zone', expected_allowed, False, zone['id'],
+ headers={'x-auth-sudo-project-id': self.client.project_id})
+
@decorators.idempotent_id('49268b24-92de-11eb-9d02-74e5f9e2a801')
def test_show_not_existing_zone(self):
LOG.info('Fetch non existing zone')
@@ -166,6 +204,26 @@
self.addCleanup(self.wait_zone_delete, self.client, zone['id'],
ignore_errors=lib_exc.NotFound)
+ # Test RBAC
+ expected_allowed = ['os_admin', 'os_primary']
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed.append('os_system_admin')
+
+ self.check_CUD_RBAC_enforcement('ZonesClient', 'delete_zone',
+ expected_allowed, True, zone['id'])
+
+ # Test RBAC with x-auth-all-projects and x-auth-sudo-project-id header
+ expected_allowed = ['os_admin', 'os_primary']
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed.append('os_system_admin')
+
+ self.check_CUD_RBAC_enforcement('ZonesClient', 'delete_zone',
+ expected_allowed, False, zone['id'],
+ headers=self.all_projects_header)
+ self.check_CUD_RBAC_enforcement(
+ 'ZonesClient', 'delete_zone', expected_allowed, False, zone['id'],
+ headers={'x-auth-sudo-project-id': self.client.project_id})
+
LOG.info('Delete the zone')
body = self.client.delete_zone(zone['id'])[1]
@@ -194,6 +252,39 @@
# present in the response.
self.assertGreater(len(body['zones']), 0)
+ # TODO(johnsom) Test reader role once this bug is fixed:
+ # https://bugs.launchpad.net/tempest/+bug/1964509
+ # Test RBAC - Users that are allowed to call list, but should get
+ # zero zones.
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed = ['os_system_admin', 'os_system_reader',
+ 'os_admin', 'os_project_member',
+ 'os_project_reader']
+ else:
+ expected_allowed = ['os_alt']
+
+ self.check_list_RBAC_enforcement_count(
+ 'ZonesClient', 'list_zones', expected_allowed, 0)
+
+ # Test that users who should see the zone, can see it.
+ expected_allowed = ['os_primary']
+
+ self.check_list_IDs_RBAC_enforcement(
+ 'ZonesClient', 'list_zones', expected_allowed, [zone['id']])
+
+ # Test RBAC with x-auth-all-projects and x-auth-sudo-project-id header
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed = ['os_system_admin']
+ else:
+ expected_allowed = ['os_admin']
+
+ self.check_list_IDs_RBAC_enforcement(
+ 'ZonesClient', 'list_zones', expected_allowed, [zone['id']],
+ headers=self.all_projects_header)
+ self.check_list_IDs_RBAC_enforcement(
+ 'ZonesClient', 'list_zones', expected_allowed, [zone['id']],
+ headers={'x-auth-sudo-project-id': self.client.project_id})
+
@decorators.idempotent_id('123f51cb-19d5-48a9-aacc-476742c02141')
def test_update_zone(self):
LOG.info('Create a zone')
@@ -216,6 +307,29 @@
LOG.info('Ensure we respond with updated values')
self.assertEqual(description, zone['description'])
+ # Test RBAC
+ expected_allowed = ['os_admin', 'os_primary']
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed.append('os_system_admin')
+
+ self.check_CUD_RBAC_enforcement(
+ 'ZonesClient', 'update_zone', expected_allowed, True,
+ zone['id'], description=description)
+
+ # Test RBAC with x-auth-all-projects and x-auth-sudo-project-id header
+ expected_allowed = ['os_admin', 'os_primary']
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed.append('os_system_admin')
+
+ self.check_CUD_RBAC_enforcement(
+ 'ZonesClient', 'update_zone', expected_allowed, False,
+ zone['id'], description=description,
+ headers=self.all_projects_header)
+ self.check_CUD_RBAC_enforcement(
+ 'ZonesClient', 'update_zone', expected_allowed, False,
+ zone['id'], description=description,
+ headers={'x-auth-sudo-project-id': self.client.project_id})
+
@decorators.idempotent_id('3acddc86-62cc-4bfa-8589-b99e5d239bf2')
@decorators.skip_because(bug="1960487")
def test_serial_changes_on_update(self):
@@ -302,6 +416,29 @@
pool_nameservers, zone_nameservers,
'Failed - Pool and Zone nameservers should be the same')
+ # TODO(johnsom) Test reader role once this bug is fixed:
+ # https://bugs.launchpad.net/tempest/+bug/1964509
+ # Test RBAC
+ expected_allowed = ['os_primary']
+
+ self.check_list_show_RBAC_enforcement(
+ 'ZonesClient', 'show_zone_nameservers', expected_allowed,
+ True, zone['id'])
+
+ # Test with x-auth-all-projects and x-auth-sudo-project-id header
+ if CONF.dns_feature_enabled.enforce_new_defaults:
+ expected_allowed = ['os_system_admin']
+ else:
+ expected_allowed = ['os_admin']
+
+ self.check_list_show_RBAC_enforcement(
+ 'ZonesClient', 'show_zone_nameservers', expected_allowed,
+ False, zone['id'], headers=self.all_projects_header)
+ self.check_list_show_RBAC_enforcement(
+ 'ZonesClient', 'show_zone_nameservers', expected_allowed,
+ False, zone['id'],
+ headers={'x-auth-sudo-project-id': self.client.project_id})
+
class ZonesAdminTest(BaseZonesTest):
credentials = ["primary", "admin", "system_admin", "alt"]
diff --git a/designate_tempest_plugin/tests/base.py b/designate_tempest_plugin/tests/base.py
index 9035c83..e581e0a 100644
--- a/designate_tempest_plugin/tests/base.py
+++ b/designate_tempest_plugin/tests/base.py
@@ -67,9 +67,10 @@
# have cls.os_alt, and admin will have cls.os_admin.
# NOTE(johnsom) We will allocate most credentials here so that each test
# can test for allowed and disallowed RBAC policies.
- credentials = ['admin', 'primary']
+ credentials = ['admin', 'primary', 'alt']
if CONF.dns_feature_enabled.enforce_new_defaults:
- credentials.extend(['system_admin', 'system_reader', 'project_reader'])
+ credentials.extend(['system_admin', 'system_reader',
+ 'project_member', 'project_reader'])
# A tuple of credentials that will be allocated by tempest using the
# 'credentials' list above. These are used to build RBAC test lists.
diff --git a/designate_tempest_plugin/tests/rbac_utils.py b/designate_tempest_plugin/tests/rbac_utils.py
index e02fdf1..a0148bb 100644
--- a/designate_tempest_plugin/tests/rbac_utils.py
+++ b/designate_tempest_plugin/tests/rbac_utils.py
@@ -75,9 +75,13 @@
self.fail('Method {}.{} failed to allow access via RBAC using '
'credential {}. Error: {}'.format(
client_str, method_str, cred, str(e)))
+ except exceptions.NotFound as e:
+ self.fail('Method {}.{} failed to allow access via RBAC using '
+ 'credential {}. Error: {}'.format(
+ client_str, method_str, cred, str(e)))
def _check_disallowed(self, client_str, method_str, allowed_list,
- *args, **kwargs):
+ expect_404, *args, **kwargs):
"""Test an API call disallowed RBAC enforcement.
:param client_str: The service client to use for the test, without the
@@ -86,6 +90,7 @@
Example: 'list_zones'
:param allowed_list: The list of credentials expected to be
allowed. Example: ['primary'].
+ :param expect_404: When True, 404 responses are considered ok.
:param args: Any positional parameters needed by the method.
:param kwargs: Any named parameters needed by the method.
:raises AssertionError: Raised if the RBAC tests fail.
@@ -118,11 +123,18 @@
method(*args, **kwargs)
except exceptions.Forbidden:
continue
+ except exceptions.NotFound:
+ # Some APIs hide that the resource exists by returning 404
+ # on permission denied.
+ if expect_404:
+ continue
+ raise
self.fail('Method {}.{} failed to deny access via RBAC using '
'credential {}.'.format(client_str, method_str, cred))
def check_list_show_RBAC_enforcement(self, client_str, method_str,
- expected_allowed, *args, **kwargs):
+ expected_allowed, expect_404,
+ *args, **kwargs):
"""Test list or show API call RBAC enforcement.
:param client_str: The service client to use for the test, without the
@@ -131,6 +143,7 @@
Example: 'list_zones'
:param expected_allowed: The list of credentials expected to be
allowed. Example: ['primary'].
+ :param expect_404: When True, 404 responses are considered ok.
:param args: Any positional parameters needed by the method.
:param kwargs: Any named parameters needed by the method.
:raises AssertionError: Raised if the RBAC tests fail.
@@ -145,7 +158,7 @@
# #### Test that disallowed credentials cannot access the API.
self._check_disallowed(client_str, method_str, allowed_list,
- *args, **kwargs)
+ expect_404, *args, **kwargs)
# #### Test that allowed credentials can access the API.
self._check_allowed(client_str, method_str, allowed_list,