Merge "[S-RBAC] Change tenant_id to project_id in the API policies"
This commit is contained in:
@@ -88,7 +88,7 @@ ADMIN_OR_NET_OWNER_READER = (
|
||||
# above. We should probably deprecate SG_OWNER rules and use PARENT_OWNER
|
||||
# instead but this can be done later
|
||||
# TODO(slaweq): Deprecate SG_OWNER rules and replace them with PARENT_OWNER
|
||||
# rules but for that, 'ext_parent_owner:tenant_id' needs to be added to the SG
|
||||
# rules but for that, 'ext_parent_owner:project_id' needs to be added to the SG
|
||||
# rule target dict
|
||||
SG_OWNER_MEMBER = 'role:member and ' + RULE_SG_OWNER
|
||||
SG_OWNER_READER = 'role:reader and ' + RULE_SG_OWNER
|
||||
@@ -112,7 +112,7 @@ rules = [
|
||||
description="Default rule for the service-to-service APIs."),
|
||||
policy.RuleDefault(
|
||||
'owner',
|
||||
'tenant_id:%(tenant_id)s',
|
||||
'project_id:%(project_id)s',
|
||||
description='Rule for resource owner access'),
|
||||
policy.RuleDefault(
|
||||
'admin_or_owner',
|
||||
@@ -129,7 +129,7 @@ rules = [
|
||||
policy.RuleDefault(
|
||||
'admin_or_network_owner',
|
||||
neutron_policy.policy_or('rule:context_is_admin',
|
||||
'tenant_id:%(network:tenant_id)s'),
|
||||
'project_id:%(network:project_id)s'),
|
||||
description='Rule for admin or network owner access'),
|
||||
policy.RuleDefault(
|
||||
'admin_owner_or_network_owner',
|
||||
@@ -139,7 +139,7 @@ rules = [
|
||||
'admin or network owner access')),
|
||||
policy.RuleDefault(
|
||||
'network_owner',
|
||||
'tenant_id:%(network:tenant_id)s',
|
||||
'project_id:%(network:project_id)s',
|
||||
description='Rule for network owner access'),
|
||||
policy.RuleDefault(
|
||||
'admin_only',
|
||||
@@ -161,15 +161,15 @@ rules = [
|
||||
policy.RuleDefault(
|
||||
'admin_or_ext_parent_owner',
|
||||
neutron_policy.policy_or('rule:context_is_admin',
|
||||
'tenant_id:%(ext_parent:tenant_id)s'),
|
||||
'project_id:%(ext_parent:project_id)s'),
|
||||
description='Rule for common parent owner check'),
|
||||
policy.RuleDefault(
|
||||
'ext_parent_owner',
|
||||
'tenant_id:%(ext_parent:tenant_id)s',
|
||||
'project_id:%(ext_parent:project_id)s',
|
||||
description='Rule for common parent owner check'),
|
||||
policy.RuleDefault(
|
||||
name='sg_owner',
|
||||
check_str='tenant_id:%(security_group:tenant_id)s',
|
||||
check_str='project_id:%(security_group:project_id)s',
|
||||
description='Rule for security group owner access'),
|
||||
]
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ rules = [
|
||||
name='admin_or_sg_owner',
|
||||
check_str=neutron_policy.policy_or(
|
||||
'rule:context_is_admin',
|
||||
'tenant_id:%(security_group:tenant_id)s'),
|
||||
'project_id:%(security_group:project_id)s'),
|
||||
description='Rule for admin or security group owner access'),
|
||||
policy.RuleDefault(
|
||||
name='admin_owner_or_sg_owner',
|
||||
|
||||
@@ -322,9 +322,12 @@ class DbBasePluginCommon:
|
||||
|
||||
def _make_network_dict(self, network, fields=None,
|
||||
process_extensions=True, context=None):
|
||||
# TODO(slaweq): Remove 'tenant_id' in the 2027.1 cycle, when it will
|
||||
# not be registered for OwnerCheck anymore.
|
||||
res = {'id': network['id'],
|
||||
'name': network['name'],
|
||||
'tenant_id': network['tenant_id'],
|
||||
'project_id': network['project_id'],
|
||||
'admin_state_up': network['admin_state_up'],
|
||||
'mtu': network.get('mtu', constants.DEFAULT_NETWORK_MTU),
|
||||
'status': network['status'],
|
||||
|
||||
@@ -1242,8 +1242,11 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
|
||||
if floatingip.floating_ip_address else None)
|
||||
fixed_ip_address = (str(floatingip.fixed_ip_address)
|
||||
if floatingip.fixed_ip_address else None)
|
||||
# TODO(slaweq): Remove 'tenant_id' in the 2027.1 cycle, when it will
|
||||
# not be registered for OwnerCheck anymore.
|
||||
res = {'id': floatingip.id,
|
||||
'tenant_id': floatingip.project_id,
|
||||
'project_id': floatingip.project_id,
|
||||
'floating_ip_address': floating_ip_address,
|
||||
'floating_network_id': floatingip.floating_network_id,
|
||||
'router_id': floatingip.router_id,
|
||||
|
||||
@@ -345,10 +345,13 @@ class SecurityGroupDbMixin(
|
||||
rbac_entries = security_group['rbac_entries']
|
||||
shared = rbac_db_obj.RbacNeutronDbObjectMixin.is_network_shared(
|
||||
context, rbac_entries)
|
||||
# TODO(slaweq): Remove 'tenant_id' in the 2027.1 cycle, when it will
|
||||
# not be registered for OwnerCheck anymore.
|
||||
res = {'id': security_group['id'],
|
||||
'name': security_group['name'],
|
||||
'stateful': security_group['stateful'],
|
||||
'tenant_id': security_group['tenant_id'],
|
||||
'project_id': security_group['project_id'],
|
||||
'description': security_group['description'],
|
||||
'standard_attr_id': security_group.standard_attr_id,
|
||||
'shared': shared,
|
||||
|
||||
@@ -253,6 +253,9 @@ def _build_match_rule(action, target, pluralized):
|
||||
# This will prevent us from having to handling backward compatibility
|
||||
# for policy.yaml
|
||||
# TODO(salv-orlando): Reinstate GenericCheck for simple tenant_id checks
|
||||
@policy.register('project_id')
|
||||
# TODO(slaweq): Remove registering of the 'tenant_id' for OwnerCheck in
|
||||
# the 2027.1 cycle
|
||||
@policy.register('tenant_id')
|
||||
class OwnerCheck(policy.Check):
|
||||
"""Resource ownership check.
|
||||
@@ -264,6 +267,11 @@ class OwnerCheck(policy.Check):
|
||||
resource and perform the check.
|
||||
"""
|
||||
def __init__(self, kind, match):
|
||||
if kind == 'tenant_id':
|
||||
LOG.warning(
|
||||
"Using 'tenant_id' in the API policy rules is deprecated "
|
||||
"since 2026.1 release and will be removed in "
|
||||
"the 2027.1. Please use 'project_id' instead.")
|
||||
self._orig_kind = kind
|
||||
self._orig_match = match
|
||||
|
||||
|
||||
@@ -145,22 +145,22 @@ class TestPolicyEnforcementHook(test_functional.PecanFunctionalTest):
|
||||
'is_visible': True, 'default': ''},
|
||||
'restricted_attr': {'allow_post': True, 'allow_put': True,
|
||||
'is_visible': True, 'default': ''},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {'type:string':
|
||||
db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'is_visible': True}
|
||||
'project_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {'type:string':
|
||||
db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'is_visible': True}
|
||||
},
|
||||
'admin_mehs': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True, 'primary_key': True},
|
||||
'foo': {'allow_post': True, 'allow_put': True,
|
||||
'is_visible': True, 'default': ''},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {'type:string':
|
||||
db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'is_visible': True}
|
||||
'project_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {'type:string':
|
||||
db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'is_visible': True}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ class TestPolicyEnforcementHook(test_functional.PecanFunctionalTest):
|
||||
'id': 'xxx',
|
||||
'attr': 'meh',
|
||||
'restricted_attr': '',
|
||||
'tenant_id': 'tenid'}
|
||||
'project_id': 'tenid'}
|
||||
response = self.app.post_json('/v2.0/mehs.json',
|
||||
params={'meh': {'attr': 'meh'}},
|
||||
headers={'X-Project-Id': 'tenid'})
|
||||
@@ -227,7 +227,7 @@ class TestPolicyEnforcementHook(test_functional.PecanFunctionalTest):
|
||||
'id': 'xxx',
|
||||
'attr': 'meh',
|
||||
'restricted_attr': '',
|
||||
'tenant_id': 'tenid'}
|
||||
'project_id': 'tenid'}
|
||||
# The policy engine should trigger an exception in 'before', and the
|
||||
# plugin method should not be called at all
|
||||
response = self.app.put_json('/v2.0/mehs/xxx.json',
|
||||
@@ -246,7 +246,7 @@ class TestPolicyEnforcementHook(test_functional.PecanFunctionalTest):
|
||||
'id': 'yyy',
|
||||
'attr': 'meh',
|
||||
'restricted_attr': '',
|
||||
'tenant_id': 'tenid'}
|
||||
'project_id': 'tenid'}
|
||||
response = self.app.put_json('/v2.0/mehs/yyy.json',
|
||||
params={'meh': {'attr': 'meh'}},
|
||||
headers={'X-Project-Id': 'tenid'},
|
||||
@@ -263,7 +263,7 @@ class TestPolicyEnforcementHook(test_functional.PecanFunctionalTest):
|
||||
'id': 'xxx',
|
||||
'attr': 'meh',
|
||||
'restricted_attr': '',
|
||||
'tenant_id': 'tenid'}
|
||||
'project_id': 'tenid'}
|
||||
# The policy engine should trigger an exception in 'before', and the
|
||||
# plugin method should not be called
|
||||
response = self.app.delete_json('/v2.0/mehs/xxx.json',
|
||||
@@ -281,7 +281,7 @@ class TestPolicyEnforcementHook(test_functional.PecanFunctionalTest):
|
||||
'id': 'yyy',
|
||||
'attr': 'meh',
|
||||
'restricted_attr': '',
|
||||
'tenant_id': 'tenid'}
|
||||
'project_id': 'tenid'}
|
||||
# The policy engine should trigger an exception in 'after', and the
|
||||
# plugin method should be called
|
||||
response = self.app.get('/v2.0/mehs/yyy.json',
|
||||
@@ -295,7 +295,7 @@ class TestPolicyEnforcementHook(test_functional.PecanFunctionalTest):
|
||||
'id': 'xxx',
|
||||
'attr': 'meh',
|
||||
'restricted_attr': '',
|
||||
'tenant_id': 'tenid'}
|
||||
'project_id': 'tenid'}
|
||||
response = self.app.get('/v2.0/mehs/xxx.json',
|
||||
headers={'X-Project-Id': 'tenid'})
|
||||
self.assertEqual(200, response.status_int)
|
||||
@@ -307,7 +307,7 @@ class TestPolicyEnforcementHook(test_functional.PecanFunctionalTest):
|
||||
'id': 'xxx',
|
||||
'attr': 'meh',
|
||||
'restricted_attr': '',
|
||||
'tenant_id': 'tenid'}]
|
||||
'project_id': 'tenid'}]
|
||||
response = self.app.get('/v2.0/mehs',
|
||||
headers={'X-Project-Id': 'tenid'})
|
||||
self.assertEqual(200, response.status_int)
|
||||
@@ -319,7 +319,7 @@ class TestPolicyEnforcementHook(test_functional.PecanFunctionalTest):
|
||||
'id': 'xxx',
|
||||
'attr': 'meh',
|
||||
'restricted_attr': '',
|
||||
'tenant_id': 'tenid'}]
|
||||
'project_id': 'tenid'}]
|
||||
policy.reset()
|
||||
response = self.app.get('/v2.0/mehs',
|
||||
headers={'X-Project-Id': 'tenid'})
|
||||
|
||||
@@ -28,11 +28,9 @@ class FloatingipPortForwardingAPITestCase(base.PolicyBaseTestCase):
|
||||
super().setUp()
|
||||
self.fip = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.project_id,
|
||||
'project_id': self.project_id}
|
||||
self.alt_fip = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.alt_project_id,
|
||||
'project_id': self.alt_project_id}
|
||||
|
||||
self.target = {
|
||||
|
||||
@@ -28,11 +28,9 @@ class L3ConntrackHelperAPITestCase(base.PolicyBaseTestCase):
|
||||
super().setUp()
|
||||
self.router = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.project_id,
|
||||
'project_id': self.project_id}
|
||||
self.alt_router = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.alt_project_id,
|
||||
'project_id': self.alt_project_id}
|
||||
|
||||
self.target = {
|
||||
|
||||
@@ -28,11 +28,9 @@ class LocalIPAssociationAPITestCase(base.PolicyBaseTestCase):
|
||||
super().setUp()
|
||||
self.local_ip = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.project_id,
|
||||
'project_id': self.project_id}
|
||||
self.alt_local_ip = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.alt_project_id,
|
||||
'project_id': self.alt_project_id}
|
||||
|
||||
self.target = {
|
||||
|
||||
@@ -29,19 +29,15 @@ class PortAPITestCase(base.PolicyBaseTestCase):
|
||||
|
||||
self.network = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.project_id,
|
||||
'project_id': self.project_id}
|
||||
self.alt_network = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.alt_project_id,
|
||||
'project_id': self.alt_project_id}
|
||||
self.target = {
|
||||
'tenant_id': self.project_id,
|
||||
'project_id': self.project_id,
|
||||
'network_id': self.network['id'],
|
||||
'ext_parent_network_id': self.network['id']}
|
||||
self.alt_target = {
|
||||
'tenant_id': self.project_id,
|
||||
'project_id': self.alt_project_id,
|
||||
'network_id': self.alt_network['id'],
|
||||
'ext_parent_network_id': self.alt_network['id']}
|
||||
|
||||
@@ -455,11 +455,9 @@ class QosRulesAPITestCase(base.PolicyBaseTestCase):
|
||||
super().setUp()
|
||||
self.qos_policy = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.project_id,
|
||||
'project_id': self.project_id}
|
||||
self.alt_qos_policy = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.alt_project_id,
|
||||
'project_id': self.alt_project_id}
|
||||
self.target = {
|
||||
'policy_id': self.qos_policy['id'],
|
||||
|
||||
@@ -389,28 +389,24 @@ class SecurityGroupRuleAPITestCase(base.PolicyBaseTestCase):
|
||||
super().setUp()
|
||||
self.sg = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'project_id': self.project_id,
|
||||
'tenant_id': self.project_id}
|
||||
'project_id': self.project_id}
|
||||
self.alt_sg = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'project_id': self.alt_project_id,
|
||||
'tenant_id': self.alt_project_id}
|
||||
'project_id': self.alt_project_id}
|
||||
|
||||
self.target = {
|
||||
'project_id': self.project_id,
|
||||
'tenant_id': self.project_id,
|
||||
'security_group_id': self.sg['id'],
|
||||
'ext_parent:tenant_id': self.sg['id'],
|
||||
'ext_parent:project_id': self.sg['id'],
|
||||
'ext_parent_security_group_id': self.sg['id']}
|
||||
self.alt_target = {
|
||||
'project_id': self.alt_project_id,
|
||||
'tenant_id': self.alt_project_id,
|
||||
'security_group_id': self.alt_sg['id'],
|
||||
'ext_parent:tenant_id': self.alt_sg['id'],
|
||||
'ext_parent:project_id': self.alt_sg['id'],
|
||||
'ext_parent_security_group_id': self.alt_sg['id']}
|
||||
|
||||
def get_security_group_mock(context, id,
|
||||
fields=None, tenant_id=None):
|
||||
fields=None, project_id=None):
|
||||
if id == self.alt_sg['id']:
|
||||
return self.alt_sg
|
||||
return self.sg
|
||||
@@ -559,7 +555,7 @@ class ProjectManagerSecurityGroupRuleTests(AdminSecurityGroupRuleTests):
|
||||
# Test for the SG_OWNER different then current user case:
|
||||
target = copy.copy(self.target)
|
||||
target['security_group_id'] = self.alt_sg['id']
|
||||
target['ext_parent:tenant_id'] = self.alt_sg['tenant_id']
|
||||
target['ext_parent:project_id'] = self.alt_sg['project_id']
|
||||
target['ext_parent_security_group_id'] = self.alt_sg['id']
|
||||
self.plugin_mock.get_security_group.return_value = self.alt_sg
|
||||
self.assertRaises(
|
||||
@@ -600,7 +596,7 @@ class ProjectManagerSecurityGroupRuleTests(AdminSecurityGroupRuleTests):
|
||||
# Test for the SG_OWNER different then current user case:
|
||||
target = copy.copy(self.target)
|
||||
target['security_group_id'] = self.alt_sg['id']
|
||||
target['ext_parent:tenant_id'] = self.alt_sg['tenant_id']
|
||||
target['ext_parent:project_id'] = self.alt_sg['project_id']
|
||||
target['ext_parent_security_group_id'] = self.alt_sg['id']
|
||||
self.plugin_mock.get_security_group.return_value = self.alt_sg
|
||||
self.assertRaises(
|
||||
@@ -646,7 +642,7 @@ class ProjectReaderSecurityGroupRuleTests(ProjectMemberSecurityGroupRuleTests):
|
||||
# Test for the SG_OWNER different then current user case:
|
||||
target = copy.copy(self.target)
|
||||
target['security_group_id'] = self.alt_sg['id']
|
||||
target['ext_parent:tenant_id'] = self.alt_sg['tenant_id']
|
||||
target['ext_parent:project_id'] = self.alt_sg['project_id']
|
||||
target['ext_parent_security_group_id'] = self.alt_sg['id']
|
||||
self.plugin_mock.get_security_group.return_value = self.alt_sg
|
||||
self.assertRaises(
|
||||
@@ -666,7 +662,7 @@ class ProjectReaderSecurityGroupRuleTests(ProjectMemberSecurityGroupRuleTests):
|
||||
# Test for the SG_OWNER different then current user case:
|
||||
target = copy.copy(self.target)
|
||||
target['security_group_id'] = self.alt_sg['id']
|
||||
target['ext_parent:tenant_id'] = self.alt_sg['tenant_id']
|
||||
target['ext_parent:project_id'] = self.alt_sg['project_id']
|
||||
target['ext_parent_security_group_id'] = self.alt_sg['id']
|
||||
self.plugin_mock.get_security_group.return_value = self.alt_sg
|
||||
self.assertRaises(
|
||||
|
||||
@@ -37,15 +37,12 @@ class SubnetAPITestCase(base.PolicyBaseTestCase):
|
||||
|
||||
self.network = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.project_id,
|
||||
'project_id': self.project_id}
|
||||
self.alt_network = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.alt_project_id,
|
||||
'project_id': self.alt_project_id}
|
||||
self.ext_alt_network = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'tenant_id': self.alt_project_id,
|
||||
'project_id': self.alt_project_id}
|
||||
|
||||
networks = {
|
||||
@@ -56,26 +53,22 @@ class SubnetAPITestCase(base.PolicyBaseTestCase):
|
||||
|
||||
self.target = {
|
||||
'project_id': self.project_id,
|
||||
'tenant_id': self.project_id,
|
||||
'network_id': self.network['id'],
|
||||
'ext_parent_network_id': self.network['id']}
|
||||
# This subnet belongs to "project_id", but not the network that
|
||||
# belongs to "alt_project_id".
|
||||
self.target_net_alt_target = {
|
||||
'project_id': self.project_id,
|
||||
'tenant_id': self.project_id,
|
||||
'network_id': self.alt_network['id'],
|
||||
'ext_parent_network_id': self.alt_network['id']}
|
||||
self.alt_target = {
|
||||
'project_id': self.alt_project_id,
|
||||
'tenant_id': self.alt_project_id,
|
||||
'network_id': self.alt_network['id'],
|
||||
'ext_parent_network_id': self.alt_network['id']}
|
||||
# Both the subnet and the network belongs to "alt_project_id" and the
|
||||
# network is external.
|
||||
self.target_net_ext_alt_target = {
|
||||
'project_id': self.alt_project_id,
|
||||
'tenant_id': self.alt_project_id,
|
||||
'network_id': self.ext_alt_network['id'],
|
||||
'ext_parent_network_id': self.ext_alt_network['id'],
|
||||
'router:external': True}
|
||||
@@ -83,7 +76,6 @@ class SubnetAPITestCase(base.PolicyBaseTestCase):
|
||||
# the subnet.
|
||||
self.alt_target_own_net = {
|
||||
'project_id': self.alt_project_id,
|
||||
'tenant_id': self.alt_project_id,
|
||||
'network_id': self.network['id'],
|
||||
'ext_parent_network_id': self.network['id']}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
deprecations:
|
||||
- |
|
||||
Usage of ``tenant_id`` in the API policy rules is deprecated and will be
|
||||
removed in the 2027.1 release. Please use ``project_id`` instead.
|
||||
Reference in New Issue
Block a user