From d97af33c0639b548f8a66ab14019259e9b4210be Mon Sep 17 00:00:00 2001 From: Ghanshyam Mann Date: Wed, 30 Nov 2022 14:57:51 -0600 Subject: [PATCH] Enable new defaults and scope checks by default As discussed in PTG, we need to test the new RBAC in the integrated gate and accordingly enable the new defaults and scope check by default. A new integrated testing job has been added and results show that the new defaults and scope checks are working fine. During testing, we found a few bugs in neutron policies but all are fixed now. enforce_scope and enforce_new_defaults are oslo policy config options but they are per service level and the default value can be overridden. Oslo policy 3.11.0 version allows to override the default value for these config options[1] so upgrading the oslo policy version in requirements.txt Depends-On: https://review.opendev.org/c/openstack/devstack/+/869781 Depends-On: https://review.opendev.org/c/openstack/placement/+/869525 [1] https://github.com/openstack/oslo.policy/blob/3.11.0/oslo_policy/opts.py#L125 Change-Id: I977b2daedf880229c8d364ca011f2ea965b86e3a --- .zuul.yaml | 34 +++++++ nova/policy.py | 12 ++- .../openstack/compute/test_server_groups.py | 97 ++++++++++--------- nova/tests/unit/api/openstack/fakes.py | 14 ++- nova/tests/unit/cmd/test_policy.py | 13 ++- nova/tests/unit/policies/base.py | 10 ++ nova/tests/unit/test_policy.py | 10 +- ...ope-and-new-defaults-14db8c75b263b599.yaml | 23 +++++ requirements.txt | 2 +- 9 files changed, 152 insertions(+), 63 deletions(-) create mode 100644 releasenotes/notes/enable-enforce-scope-and-new-defaults-14db8c75b263b599.yaml diff --git a/.zuul.yaml b/.zuul.yaml index 1a35975d3aba..25d6cc6819b5 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -665,6 +665,36 @@ parent: tempest-integrated-compute nodeset: openstack-single-node-focal +# TODO(gmann): Remove this jobs once all the required services for intergrate +# compute gate (Cinder, Glance, Neutron) by default enable scope and new +# defaults which means all the nova jobs will be tested with new RBAC in +# integrated way and we do not need this separate job. +- job: + name: tempest-integrated-compute-enforce-scope-new-defaults + parent: tempest-integrated-compute + description: | + This job runs the Tempest tests with scope and new defaults enabled + for Nova, Neutron, Glance, and Cinder services. + # TODO (gmann): There were few fixes in neutron and neutron-lib for the + # RBAC but they are not yet released so we need to add both projcts as + # the required-projects. Those can be removed once new version of neutron + # and neutron-lib is released. + required-projects: + - openstack/neutron + - openstack/neutron-lib + vars: + devstack_localrc: + # Enabeling the scope and new defaults for services implemented it. + # NOTE (gmann): We need to keep keystone scope check disable as + # services (except ironic) does not support the system scope and + # they need keystone to continue working with project scope. Until + # Keystone policies are changed to work for project scoped also, we + # need to keep scope check disable for keystone. + NOVA_ENFORCE_SCOPE: true + CINDER_ENFORCE_SCOPE: true + GLANCE_ENFORCE_SCOPE: true + NEUTRON_ENFORCE_SCOPE: true + - project: # Please try to keep the list of job names sorted alphabetically. templates: @@ -723,6 +753,8 @@ - ^tox.ini$ - tempest-integrated-compute-ubuntu-focal: irrelevant-files: *policies-irrelevant-files + - tempest-integrated-compute-enforce-scope-new-defaults: + irrelevant-files: *policies-irrelevant-files - grenade-skip-level: irrelevant-files: *policies-irrelevant-files - nova-grenade-multinode: @@ -758,6 +790,8 @@ irrelevant-files: *policies-irrelevant-files - tempest-integrated-compute-ubuntu-focal: irrelevant-files: *policies-irrelevant-files + - tempest-integrated-compute-enforce-scope-new-defaults: + irrelevant-files: *policies-irrelevant-files - nova-grenade-multinode: irrelevant-files: *policies-irrelevant-files - tempest-ipv6-only: diff --git a/nova/policy.py b/nova/policy.py index 55455a9271dc..c66489cc8d20 100644 --- a/nova/policy.py +++ b/nova/policy.py @@ -41,11 +41,15 @@ USER_BASED_RESOURCES = ['os-keypairs'] saved_file_rules = [] KEY_EXPR = re.compile(r'%\((\w+)\)s') -# TODO(gmann): Remove setting the default value of config policy_file -# once oslo_policy change the default value to 'policy.yaml'. -# https://github.com/openstack/oslo.policy/blob/a626ad12fe5a3abd49d70e3e5b95589d279ab578/oslo_policy/opts.py#L49 +# TODO(gmann): Remove overriding the default value of config options +# 'policy_file', 'enforce_scope', and 'enforce_new_defaults' once +# oslo_policy change their default value to what is overridden here. DEFAULT_POLICY_FILE = 'policy.yaml' -opts.set_defaults(cfg.CONF, DEFAULT_POLICY_FILE) +opts.set_defaults( + cfg.CONF, + DEFAULT_POLICY_FILE, + enforce_scope=True, + enforce_new_defaults=True) def reset(): diff --git a/nova/tests/unit/api/openstack/compute/test_server_groups.py b/nova/tests/unit/api/openstack/compute/test_server_groups.py index 636682a6b7bb..9d99c3ae6de8 100644 --- a/nova/tests/unit/api/openstack/compute/test_server_groups.py +++ b/nova/tests/unit/api/openstack/compute/test_server_groups.py @@ -87,7 +87,8 @@ class ServerGroupTestV21(test.NoDBTestCase): def setUp(self): super(ServerGroupTestV21, self).setUp() self._setup_controller() - self.req = fakes.HTTPRequest.blank('') + self.member_req = fakes.HTTPRequest.member_req('') + self.reader_req = fakes.HTTPRequest.reader_req('') self.admin_req = fakes.HTTPRequest.blank('', use_admin_context=True) self.foo_req = fakes.HTTPRequest.blank('', project_id='foo') self.policy = self.useFixture(fixtures.RealPolicyFixture()) @@ -114,20 +115,20 @@ class ServerGroupTestV21(test.NoDBTestCase): def test_create_server_group_with_no_policies(self): sgroup = server_group_template() self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) def _create_server_group_normal(self, policies=None, policy=None, rules=None): sgroup = server_group_template() sgroup['policies'] = policies - res_dict = self.controller.create(self.req, + res_dict = self.controller.create(self.member_req, body={'server_group': sgroup}) self.assertEqual(res_dict['server_group']['name'], 'test') self.assertTrue(uuidutils.is_uuid_like(res_dict['server_group']['id'])) self.assertEqual(res_dict['server_group']['policies'], policies) def test_create_server_group_with_new_policy_before_264(self): - req = fakes.HTTPRequest.blank('', version='2.63') + req = fakes.HTTPRequest.member_req('', version='2.63') policy = 'anti-affinity' rules = {'max_server_per_host': 3} # 'policy' isn't an acceptable request key before 2.64 @@ -162,7 +163,7 @@ class ServerGroupTestV21(test.NoDBTestCase): self.controller.create(self.admin_req, body={'server_group': sgroup}) # test as non-admin - self.controller.create(self.req, body={'server_group': sgroup}) + self.controller.create(self.member_req, body={'server_group': sgroup}) def _create_instance(self, ctx, cell): with context.target_cell(ctx, cell) as cctx: @@ -289,7 +290,7 @@ class ServerGroupTestV21(test.NoDBTestCase): path = path or '/os-server-groups?all_projects=True' if limited: path += limited - req = fakes.HTTPRequest.blank(path, version=api_version) + reader_req = fakes.HTTPRequest.reader_req(path, version=api_version) admin_req = fakes.HTTPRequest.blank(path, use_admin_context=True, version=api_version) @@ -298,7 +299,7 @@ class ServerGroupTestV21(test.NoDBTestCase): self.assertEqual(all, res_dict) # test as non-admin - res_dict = self.controller.index(req) + res_dict = self.controller.index(reader_req) self.assertEqual(tenant_specific, res_dict) @mock.patch('nova.objects.InstanceGroupList.get_by_project_id') @@ -347,25 +348,27 @@ class ServerGroupTestV21(test.NoDBTestCase): return_get_by_project = return_server_groups() mock_get_by_project.return_value = return_get_by_project path = '/os-server-groups' - req = fakes.HTTPRequest.blank(path, version=api_version) + req = fakes.HTTPRequest.reader_req(path, version=api_version) res_dict = self.controller.index(req) self.assertEqual(expected, res_dict) def test_display_members(self): ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID) (ig_uuid, instances, members) = self._create_groups_and_instances(ctx) - res_dict = self.controller.show(self.req, ig_uuid) + res_dict = self.controller.show(self.reader_req, ig_uuid) result_members = res_dict['server_group']['members'] self.assertEqual(3, len(result_members)) for member in members: self.assertIn(member, result_members) def test_display_members_with_nonexistent_group(self): - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.show, self.req, uuidsentinel.group) + self.assertRaises( + webob.exc.HTTPNotFound, + self.controller.show, self.reader_req, uuidsentinel.group) def test_display_active_members_only(self): - ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID) + ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID, + roles=['member', 'reader']) (ig_uuid, instances, members) = self._create_groups_and_instances(ctx) # delete an instance @@ -379,7 +382,7 @@ class ServerGroupTestV21(test.NoDBTestCase): self.assertRaises(exception.InstanceNotFound, objects.Instance.get_by_uuid, ctx, instances[1].uuid) - res_dict = self.controller.show(self.req, ig_uuid) + res_dict = self.controller.show(self.reader_req, ig_uuid) result_members = res_dict['server_group']['members'] # check that only the active instance is displayed self.assertEqual(2, len(result_members)) @@ -393,7 +396,7 @@ class ServerGroupTestV21(test.NoDBTestCase): self.controller.show(self.admin_req, ig_uuid) # test as non-admin, same project - self.controller.show(self.req, ig_uuid) + self.controller.show(self.reader_req, ig_uuid) # test as non-admin, different project self.assertRaises(webob.exc.HTTPNotFound, @@ -406,7 +409,7 @@ class ServerGroupTestV21(test.NoDBTestCase): sgroup = server_group_template(name='good* $%name', policies=['affinity']) - res_dict = self.controller.create(self.req, + res_dict = self.controller.create(self.member_req, body={'server_group': sgroup}) self.assertEqual(res_dict['server_group']['name'], 'good* $%name') @@ -414,99 +417,99 @@ class ServerGroupTestV21(test.NoDBTestCase): # blank name sgroup = server_group_template(name='', policies=['test_policy']) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # name with length 256 sgroup = server_group_template(name='1234567890' * 26, policies=['test_policy']) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # non-string name sgroup = server_group_template(name=12, policies=['test_policy']) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # name with leading spaces sgroup = server_group_template(name=' leading spaces', policies=['test_policy']) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # name with trailing spaces sgroup = server_group_template(name='trailing space ', policies=['test_policy']) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # name with all spaces sgroup = server_group_template(name=' ', policies=['test_policy']) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # name with unprintable character sgroup = server_group_template(name='bad\x00name', policies=['test_policy']) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # name with out of range char U0001F4A9 sgroup = server_group_template(name=u"\U0001F4A9", policies=['affinity']) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) def test_create_server_group_with_illegal_policies(self): # blank policy sgroup = server_group_template(name='fake-name', policies='') self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # policy as integer sgroup = server_group_template(name='fake-name', policies=7) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # policy as string sgroup = server_group_template(name='fake-name', policies='invalid') self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) # policy as None sgroup = server_group_template(name='fake-name', policies=None) self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) def test_create_server_group_conflicting_policies(self): sgroup = server_group_template() policies = ['anti-affinity', 'affinity'] sgroup['policies'] = policies self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) def test_create_server_group_with_duplicate_policies(self): sgroup = server_group_template() policies = ['affinity', 'affinity'] sgroup['policies'] = policies self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) def test_create_server_group_not_supported(self): sgroup = server_group_template() policies = ['storage-affinity', 'anti-affinity', 'rack-affinity'] sgroup['policies'] = policies self.assertRaises(self.validation_error, self.controller.create, - self.req, body={'server_group': sgroup}) + self.member_req, body={'server_group': sgroup}) def test_create_server_group_with_no_body(self): self.assertRaises(self.validation_error, - self.controller.create, self.req, body=None) + self.controller.create, self.member_req, body=None) def test_create_server_group_with_no_server_group(self): body = {'no-instanceGroup': None} self.assertRaises(self.validation_error, - self.controller.create, self.req, body=body) + self.controller.create, self.member_req, body=body) def test_list_server_group_by_tenant(self): self._test_list_server_group_by_tenant( @@ -528,7 +531,7 @@ class ServerGroupTestV21(test.NoDBTestCase): self.controller.index(self.admin_req) # test as non-admin - self.controller.index(self.req) + self.controller.index(self.reader_req) def test_list_server_group_multiple_param(self): self._test_list_server_group(api_version=self.wsgi_api_version, @@ -598,7 +601,7 @@ class ServerGroupTestV21(test.NoDBTestCase): self.stub_out('nova.objects.InstanceGroup.get_by_uuid', return_server_group) - resp = self.controller.delete(self.req, uuidsentinel.sg1_id) + resp = self.controller.delete(self.member_req, uuidsentinel.sg1_id) mock_destroy.assert_called_once_with() # NOTE: on v2.1, http status code is set as wsgi_code of API @@ -611,7 +614,7 @@ class ServerGroupTestV21(test.NoDBTestCase): def test_delete_non_existing_server_group(self): self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, - self.req, 'invalid') + self.member_req, 'invalid') def test_delete_server_group_rbac_default(self): ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID) @@ -622,7 +625,7 @@ class ServerGroupTestV21(test.NoDBTestCase): # test as non-admin ig_uuid = self._create_groups_and_instances(ctx)[0] - self.controller.delete(self.req, ig_uuid) + self.controller.delete(self.member_req, ig_uuid) class ServerGroupTestV213(ServerGroupTestV21): @@ -649,7 +652,7 @@ class ServerGroupTestV264(ServerGroupTestV213): def _create_server_group_normal(self, policies=None, policy=None, rules=None): - req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version) sgroup = server_group_template() sgroup['rules'] = rules or {} sgroup['policy'] = policy @@ -674,7 +677,7 @@ class ServerGroupTestV264(ServerGroupTestV213): self.assertEqual(res_dict['server_group']['rules'], {}) def _display_server_group(self, uuid): - req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + req = fakes.HTTPRequest.reader_req('', version=self.wsgi_api_version) group = self.controller.show(req, uuid) return group @@ -690,7 +693,7 @@ class ServerGroupTestV264(ServerGroupTestV213): self.assertEqual(res_dict['server_group']['rules'], rules) def test_create_affinity_server_group_with_invalid_policy(self): - req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version) sgroup = server_group_template(policy='affinity', rules={'max_server_per_host': 3}) result = self.assertRaises(webob.exc.HTTPBadRequest, @@ -698,7 +701,7 @@ class ServerGroupTestV264(ServerGroupTestV213): self.assertIn("Only anti-affinity policy supports rules", str(result)) def test_create_anti_affinity_server_group_with_invalid_rules(self): - req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version) # A negative test for key is unknown, the value is not positive # and not integer invalid_rules = [{'unknown_key': '3'}, @@ -718,7 +721,7 @@ class ServerGroupTestV264(ServerGroupTestV213): return_value=32) def test_create_server_group_with_low_version_compute_service(self, mock_get_v): - req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version) sgroup = server_group_template(policy='anti-affinity', rules={'max_server_per_host': 3}) result = self.assertRaises( @@ -734,7 +737,7 @@ class ServerGroupTestV264(ServerGroupTestV213): self._create_server_group_normal(policy=policy) def test_policies_since_264(self): - req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version) # 'policies' isn't allowed in request >= 2.64 sgroup = server_group_template(policies=['anti-affinity']) self.assertRaises( @@ -742,14 +745,14 @@ class ServerGroupTestV264(ServerGroupTestV213): req, body={'server_group': sgroup}) def test_create_server_group_without_policy(self): - req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version) # 'policy' is required request key in request >= 2.64 sgroup = server_group_template() self.assertRaises(self.validation_error, self.controller.create, req, body={'server_group': sgroup}) def test_create_server_group_with_illegal_policies(self): - req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version) # blank policy sgroup = server_group_template(policy='') self.assertRaises(self.validation_error, self.controller.create, @@ -771,7 +774,7 @@ class ServerGroupTestV264(ServerGroupTestV213): req, body={'server_group': sgroup}) def test_additional_params(self): - req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version) sgroup = server_group_template(unknown='unknown') self.assertRaises(self.validation_error, self.controller.create, req, body={'server_group': sgroup}) @@ -786,7 +789,7 @@ class ServerGroupTestV275(ServerGroupTestV264): path='/os-server-groups?dummy=False&all_projects=True') def test_list_server_group_additional_param(self): - req = fakes.HTTPRequest.blank('/os-server-groups?dummy=False', - version=self.wsgi_api_version) + req = fakes.HTTPRequest.reader_req('/os-server-groups?dummy=False', + version=self.wsgi_api_version) self.assertRaises(self.validation_error, self.controller.index, req) diff --git a/nova/tests/unit/api/openstack/fakes.py b/nova/tests/unit/api/openstack/fakes.py index 8cf90ddebe20..9ac970f7875f 100644 --- a/nova/tests/unit/api/openstack/fakes.py +++ b/nova/tests/unit/api/openstack/fakes.py @@ -240,6 +240,9 @@ class HTTPRequest(os_wsgi.Request): def blank(cls, *args, **kwargs): defaults = {'base_url': 'http://localhost/v2'} use_admin_context = kwargs.pop('use_admin_context', False) + roles = kwargs.pop('roles', []) + if use_admin_context: + roles.append('admin') project_id = kwargs.pop('project_id', FAKE_PROJECT_ID) version = kwargs.pop('version', os_wsgi.DEFAULT_API_VERSION) defaults.update(kwargs) @@ -247,10 +250,19 @@ class HTTPRequest(os_wsgi.Request): out.environ['nova.context'] = FakeRequestContext( user_id='fake_user', project_id=project_id, - is_admin=use_admin_context) + is_admin=use_admin_context, + roles=roles) out.api_version_request = api_version.APIVersionRequest(version) return out + @classmethod + def member_req(cls, *args, **kwargs): + return cls.blank(*args, roles=['member', 'reader'], **kwargs) + + @classmethod + def reader_req(cls, *args, **kwargs): + return cls.blank(*args, roles=['reader'], **kwargs) + class HTTPRequestV21(HTTPRequest): pass diff --git a/nova/tests/unit/cmd/test_policy.py b/nova/tests/unit/cmd/test_policy.py index df51665959f4..29dd5610f674 100644 --- a/nova/tests/unit/cmd/test_policy.py +++ b/nova/tests/unit/cmd/test_policy.py @@ -128,20 +128,21 @@ class TestPolicyCheck(test.NoDBTestCase): self.assertEqual(set(expected_rules), set(passing_rules)) def test_filter_rules_non_admin(self): - context = nova_context.RequestContext() + context = nova_context.RequestContext(roles=['reader']) rule_conditions = [base_policies.PROJECT_READER_OR_ADMIN] expected_rules = [r.name for r in ia_policies.list_rules() if r.check_str in rule_conditions] self._check_filter_rules(context, expected_rules=expected_rules) def test_filter_rules_admin(self): - self._check_filter_rules() + context = nova_context.RequestContext(roles=['admin']) + self._check_filter_rules(context) def test_filter_rules_instance_non_admin(self): db_context = nova_context.RequestContext(user_id='fake-user', project_id='fake-project') instance = fake_instance.fake_instance_obj(db_context) - context = nova_context.RequestContext() + context = nova_context.RequestContext(roles=['reader']) expected_rules = [r.name for r in ia_policies.list_rules() if r.check_str == base_policies.RULE_ANY] self._check_filter_rules(context, instance, expected_rules) @@ -150,11 +151,13 @@ class TestPolicyCheck(test.NoDBTestCase): db_context = nova_context.RequestContext(user_id='fake-user', project_id='fake-project') instance = fake_instance.fake_instance_obj(db_context) - self._check_filter_rules(target=instance) + context = nova_context.RequestContext(roles=['admin']) + self._check_filter_rules(context, target=instance) def test_filter_rules_instance_owner(self): db_context = nova_context.RequestContext(user_id='fake-user', - project_id='fake-project') + project_id='fake-project', + roles=['reader']) instance = fake_instance.fake_instance_obj(db_context) rule_conditions = [base_policies.PROJECT_READER_OR_ADMIN] expected_rules = [r.name for r in ia_policies.list_rules() if diff --git a/nova/tests/unit/policies/base.py b/nova/tests/unit/policies/base.py index 68a051b26c4e..7490441d9260 100644 --- a/nova/tests/unit/policies/base.py +++ b/nova/tests/unit/policies/base.py @@ -58,6 +58,16 @@ class BasePolicyTest(test.TestCase): def setUp(self): super(BasePolicyTest, self).setUp() + # TODO(gmann): enforce_scope and enforce_new_defaults are enabled + # by default in the code so disable them in base test class until + # we have deprecated rules and their tests. We have enforce_scope + # and no-legacy tests which are explicitly enabling scope and new + # defaults to test the new defaults and scope. In future, once + # we remove the deprecated rules, along with refactoring the unit + # tests we can remove overriding the oslo policy flags. + self.flags(enforce_scope=False, group="oslo_policy") + if not self.without_deprecated_rules: + self.flags(enforce_new_defaults=False, group="oslo_policy") self.useFixture(fixtures.NeutronFixture(self)) self.policy = self.useFixture(fixtures.RealPolicyFixture()) diff --git a/nova/tests/unit/test_policy.py b/nova/tests/unit/test_policy.py index 871e836d877b..752b8723810b 100644 --- a/nova/tests/unit/test_policy.py +++ b/nova/tests/unit/test_policy.py @@ -303,10 +303,10 @@ class RealRolePolicyTestCase(test.NoDBTestCase): def setUp(self): super(RealRolePolicyTestCase, self).setUp() self.policy = self.useFixture(nova_fixtures.RealPolicyFixture()) - self.non_admin_context = context.RequestContext('fake', 'fake', - roles=['member']) - self.admin_context = context.RequestContext('fake', 'fake', True, - roles=['admin', 'member']) + self.non_admin_context = context.RequestContext( + 'fake', 'fake', roles=['member', 'reader']) + self.admin_context = context.RequestContext( + 'fake', 'fake', True, roles=['admin', 'member', 'reader']) self.target = {} self.fake_policy = jsonutils.loads(fake_policy.policy_data) @@ -387,6 +387,7 @@ class RealRolePolicyTestCase(test.NoDBTestCase): "os_compute_api:os-hypervisors:search", "os_compute_api:os-hypervisors:servers", "os_compute_api:limits:other_project", +"os_compute_api:os-flavor-access", ) self.admin_or_owner_rules = ( @@ -440,7 +441,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase): "os_compute_api:os-remote-consoles", "os_compute_api:os-deferred-delete:restore", "os_compute_api:os-deferred-delete:force", -"os_compute_api:os-flavor-access", "os_compute_api:os-flavor-extra-specs:index", "os_compute_api:os-flavor-extra-specs:show", "os_compute_api:os-floating-ips:add", diff --git a/releasenotes/notes/enable-enforce-scope-and-new-defaults-14db8c75b263b599.yaml b/releasenotes/notes/enable-enforce-scope-and-new-defaults-14db8c75b263b599.yaml new file mode 100644 index 000000000000..72a6f861b6fa --- /dev/null +++ b/releasenotes/notes/enable-enforce-scope-and-new-defaults-14db8c75b263b599.yaml @@ -0,0 +1,23 @@ +--- +upgrade: + - | + The Nova service enable the API policies (RBAC) new defaults and scope by + default. The Default value of config options ``[oslo_policy] enforce_scope`` + and ``[oslo_policy] oslo_policy.enforce_new_defaults`` have been changed + to ``True``. + + This means if you are using system scope token to access Nova API then + the request will be failed with 403 error code. Also, new defaults will be + enforced by default. To know about the new defaults of each policy + rule, refer to the `Policy New Defaults`_. For more detail about the Nova + API policies changes, refer to `Policy Concepts`_. + + If you want to disable them then modify the below config options value in + ``nova.conf`` file:: + + [oslo_policy] + enforce_new_defaults=False + enforce_scope=False + + .. _`Policy New Defaults`: https://docs.openstack.org/nova/latest/configuration/policy.html + .. _`Policy Concepts`: https://docs.openstack.org/nova/latest/configuration/policy-concepts.html diff --git a/requirements.txt b/requirements.txt index dc1c414aba44..5301b7cf0579 100644 --- a/requirements.txt +++ b/requirements.txt @@ -43,7 +43,7 @@ oslo.utils>=4.12.1 # Apache-2.0 oslo.db>=10.0.0 # Apache-2.0 oslo.rootwrap>=5.15.0 # Apache-2.0 oslo.messaging>=10.3.0 # Apache-2.0 -oslo.policy>=3.7.0 # Apache-2.0 +oslo.policy>=3.11.0 # Apache-2.0 oslo.privsep>=2.6.2 # Apache-2.0 oslo.i18n>=5.1.0 # Apache-2.0 oslo.service>=2.8.0 # Apache-2.0