diff --git a/neutron/conf/policies/port.py b/neutron/conf/policies/port.py index b64269a0116..7122a421623 100644 --- a/neutron/conf/policies/port.py +++ b/neutron/conf/policies/port.py @@ -81,6 +81,20 @@ rules = [ deprecated_reason=DEPRECATED_REASON, deprecated_since=versionutils.deprecated.WALLABY) ), + policy.DocumentedRuleDefault( + name='create_port:device_id', + check_str=neutron_policy.policy_or( + base.ADMIN_OR_PROJECT_MEMBER, + base.SERVICE), + scope_types=['project'], + description='Specify ``device_id`` attribute when creating a port', + operations=ACTION_POST, + deprecated_rule=policy.DeprecatedRule( + name='create_port:device_id', + check_str=neutron_policy.RULE_ANY, + deprecated_reason=DEPRECATED_REASON, + deprecated_since=versionutils.deprecated.WALLABY) + ), policy.DocumentedRuleDefault( name='create_port:device_owner', check_str=neutron_policy.policy_or( @@ -460,6 +474,20 @@ rules = [ deprecated_reason=DEPRECATED_REASON, deprecated_since=versionutils.deprecated.WALLABY) ), + policy.DocumentedRuleDefault( + name='update_port:device_id', + check_str=neutron_policy.policy_or( + base.ADMIN_OR_PROJECT_MEMBER, + base.SERVICE), + scope_types=['project'], + description='Update ``device_id`` attribute of a port', + operations=ACTION_PUT, + deprecated_rule=policy.DeprecatedRule( + name='update_port:device_id', + check_str=neutron_policy.RULE_ANY, + deprecated_reason=DEPRECATED_REASON, + deprecated_since=versionutils.deprecated.WALLABY) + ), policy.DocumentedRuleDefault( name='update_port:device_owner', check_str=neutron_policy.policy_or( diff --git a/neutron/tests/unit/conf/policies/test_port.py b/neutron/tests/unit/conf/policies/test_port.py index 827f689ccbf..48c63a36e8d 100644 --- a/neutron/tests/unit/conf/policies/test_port.py +++ b/neutron/tests/unit/conf/policies/test_port.py @@ -62,6 +62,16 @@ class SystemAdminTests(PortAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'create_port', self.alt_target) + def test_create_port_with_device_id(self): + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, self.context, 'create_port:device_id', + self.target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, self.context, 'create_port:device_id', + self.alt_target) + def test_create_port_with_device_owner(self): self.assertRaises( base_policy.InvalidScope, @@ -270,6 +280,16 @@ class SystemAdminTests(PortAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'update_port', self.alt_target) + def test_update_port_with_device_id(self): + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, self.context, 'update_port:device_id', + self.target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, self.context, 'update_port:device_id', + self.alt_target) + def test_update_port_with_device_owner(self): self.assertRaises( base_policy.InvalidScope, @@ -441,6 +461,14 @@ class AdminTests(PortAPITestCase): self.assertTrue( policy.enforce(self.context, 'create_port', self.alt_target)) + def test_create_port_with_device_id(self): + self.assertTrue( + policy.enforce(self.context, 'create_port:device_id', + self.target)) + self.assertTrue( + policy.enforce(self.context, 'create_port:device_id', + self.alt_target)) + def test_create_port_with_device_owner(self): target = self.target.copy() target['device_owner'] = 'network:test' @@ -650,6 +678,14 @@ class AdminTests(PortAPITestCase): self.assertTrue( policy.enforce(self.context, 'update_port', self.alt_target)) + def test_update_port_with_device_id(self): + self.assertTrue( + policy.enforce(self.context, 'update_port:device_id', + self.target)) + self.assertTrue( + policy.enforce(self.context, 'update_port:device_id', + self.alt_target)) + def test_update_port_with_device_owner(self): target = self.target.copy() target['device_owner'] = 'network:test' @@ -809,6 +845,15 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'create_port', self.alt_target) + def test_create_port_with_device_id(self): + self.assertTrue( + policy.enforce(self.context, 'create_port:device_id', + self.target)) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, self.context, 'create_port:device_id', + self.alt_target) + def test_create_port_with_device_owner(self): target = self.target.copy() target['device_owner'] = 'network:test' @@ -1051,6 +1096,14 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'update_port', self.alt_target) + def test_update_port_with_device_id(self): + self.assertTrue( + policy.enforce(self.context, 'update_port:device_id', self.target)) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, self.context, 'update_port:device_id', + self.alt_target) + def test_update_port_with_device_owner(self): target = self.target.copy() target['device_owner'] = 'network:test' @@ -1437,6 +1490,16 @@ class ProjectReaderTests(ProjectMemberTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'create_port', self.alt_target) + def test_create_port_with_device_id(self): + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, self.context, 'create_port:device_id', + self.target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, self.context, 'create_port:device_id', + self.alt_target) + def test_create_port_with_binding_vnic_type(self): self.assertRaises( base_policy.PolicyNotAuthorized, @@ -1463,6 +1526,16 @@ class ProjectReaderTests(ProjectMemberTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'update_port', self.alt_target) + def test_update_port_with_device_id(self): + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, self.context, 'update_port:device_id', + self.target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, self.context, 'update_port:device_id', + self.alt_target) + def test_update_port_with_binding_vnic_type(self): self.assertRaises( base_policy.PolicyNotAuthorized, @@ -1500,6 +1573,14 @@ class ServiceRoleTests(PortAPITestCase): self.assertTrue( policy.enforce(self.context, 'create_port', self.target)) + def test_create_port_with_device_id(self): + self.assertTrue( + policy.enforce(self.context, 'create_port:device_id', + self.target)) + self.assertTrue( + policy.enforce(self.context, 'create_port:device_id', + self.alt_target)) + def test_create_port_with_device_owner(self): self.assertTrue( policy.enforce( @@ -1608,6 +1689,14 @@ class ServiceRoleTests(PortAPITestCase): self.assertTrue( policy.enforce(self.context, 'update_port', self.target)) + def test_update_port_with_device_id(self): + self.assertTrue( + policy.enforce(self.context, 'update_port:device_id', + self.target)) + self.assertTrue( + policy.enforce(self.context, 'update_port:device_id', + self.alt_target)) + def test_update_port_with_device_owner(self): self.assertTrue( policy.enforce( diff --git a/releasenotes/notes/service-role-port-device-id-61eb7b781b3b01ca.yaml b/releasenotes/notes/service-role-port-device-id-61eb7b781b3b01ca.yaml new file mode 100644 index 00000000000..7f6a5254212 --- /dev/null +++ b/releasenotes/notes/service-role-port-device-id-61eb7b781b3b01ca.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Added ``service`` role to the ``create_port:device_id`` and + ``update_port:device_id`` policies to allow service users + for other OpenStack projects to complete Secure RBAC.