Enable enforce_scope and enforce_new_defaults by default

As per the RBAc goal timeline, we agreed to enable enforce_scope
as well as the enforce_new_defaults by default

- https://governance.openstack.org/tc/goals/selected/consistent-and-secure-rbac.html#id4

Also, marking enforce_scope deprecated and to be removed in 2025.2
(SLURP) cycle.

Change-Id: I23ccdfd810ba8290aa49a47471eabdb65fea2128
This commit is contained in:
Ghanshyam Mann
2024-07-16 12:23:10 -07:00
parent c7083ec2c5
commit 206ae19f48
4 changed files with 103 additions and 45 deletions

View File

@@ -25,7 +25,14 @@ _option_group = 'oslo_policy'
_options = [
cfg.BoolOpt('enforce_scope',
default=False,
default=True,
deprecated_for_removal=True,
deprecated_reason='This configuration was added temporarily '
'to facilitate a smooth transition to the '
'new RBAC. OpenStack will always enforce '
'scope checks. This configuration option '
'is deprecated and will be removed in the '
'2025.2 cycle.',
help=_('This option controls whether or not to enforce scope '
'when evaluating policies. If ``True``, the scope of '
'the token used in the request is compared to the '
@@ -35,7 +42,7 @@ _options = [
'logged informing operators that policies are being '
'invoked with mismatching scope.')),
cfg.BoolOpt('enforce_new_defaults',
default=False,
default=True,
help=_('This option controls whether or not to use old '
'deprecated defaults when evaluating policies. If '
'``True``, the old deprecated defaults are not going '

View File

@@ -40,21 +40,21 @@ class OptsTestCase(test_base.BaseTestCase):
def test_set_defaults_enforce_scope(self):
opts._register(self.conf)
self.assertEqual(False,
self.conf.oslo_policy.enforce_scope)
opts.set_defaults(self.conf, enforce_scope=True)
self.assertEqual(True,
self.conf.oslo_policy.enforce_scope)
opts.set_defaults(self.conf, enforce_scope=False)
self.assertEqual(False,
self.conf.oslo_policy.enforce_scope)
def test_set_defaults_two_opts(self):
opts._register(self.conf)
self.assertEqual(False,
self.conf.oslo_policy.enforce_scope)
self.assertEqual(False,
self.conf.oslo_policy.enforce_new_defaults)
opts.set_defaults(self.conf, enforce_scope=True,
enforce_new_defaults=True)
self.assertEqual(True,
self.conf.oslo_policy.enforce_scope)
self.assertEqual(True,
self.conf.oslo_policy.enforce_new_defaults)
opts.set_defaults(self.conf, enforce_scope=False,
enforce_new_defaults=False)
self.assertEqual(False,
self.conf.oslo_policy.enforce_scope)
self.assertEqual(False,
self.conf.oslo_policy.enforce_new_defaults)

View File

@@ -1271,7 +1271,6 @@ class RuleDefaultTestCase(base.PolicyBaseTestCase):
class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
@mock.patch('warnings.warn', new=mock.Mock())
def test_deprecate_a_policy_check_string(self):
deprecated_rule = policy.DeprecatedRule(
name='foo:create_bar',
@@ -1285,33 +1284,24 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
check_str='role:bang',
description='Create a bar.',
operations=[{'path': '/v1/bars', 'method': 'POST'}],
scope_types=['project'],
deprecated_rule=deprecated_rule,
)]
enforcer = policy.Enforcer(self.conf)
enforcer.register_defaults(rule_list)
expected_msg = (
'Policy "foo:create_bar":"role:fizz" was deprecated in N in favor '
'of "foo:create_bar":"role:bang". Reason: "role:bang" is a better '
'default. Either ensure your deployment is ready for the new '
'default or copy/paste the deprecated policy into your policy '
'file and maintain it manually.'
)
with mock.patch('warnings.warn') as mock_warn:
enforcer.load_rules()
mock_warn.assert_called_once_with(expected_msg)
enforcer.load_rules()
self.assertTrue(
enforcer.enforce('foo:create_bar', {}, {'roles': ['bang']})
)
self.assertTrue(
self.assertFalse(
enforcer.enforce('foo:create_bar', {}, {'roles': ['fizz']})
)
self.assertFalse(
enforcer.enforce('foo:create_bar', {}, {'roles': ['baz']})
)
@mock.patch('warnings.warn', new=mock.Mock())
def test_deprecate_an_empty_policy_check_string(self):
deprecated_rule = policy.DeprecatedRule(
name='foo:create_bar',
@@ -1325,21 +1315,18 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
check_str='role:bang',
description='Create a bar.',
operations=[{'path': '/v1/bars', 'method': 'POST'}],
scope_types=['project'],
deprecated_rule=deprecated_rule,
)]
enforcer = policy.Enforcer(self.conf)
enforcer.register_defaults(rule_list)
with mock.patch('warnings.warn') as mock_warn:
enforcer.load_rules()
mock_warn.assert_called_once()
enforcer.load_rules()
enforcer.enforce('foo:create_bar', {}, {'roles': ['bang']},
do_raise=True)
enforcer.enforce('foo:create_bar', {}, {'roles': ['fizz']},
do_raise=True)
self.assertFalse(
self.enforcer.enforce('foo:create_bar', {}, {'roles': ['fizz']}))
@mock.patch('warnings.warn', new=mock.Mock())
def test_deprecate_replace_with_empty_policy_check_string(self):
deprecated_rule = policy.DeprecatedRule(
name='foo:create_bar',
@@ -1353,14 +1340,12 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
check_str='',
description='Create a bar.',
operations=[{'path': '/v1/bars', 'method': 'POST'}],
scope_types=['project'],
deprecated_rule=deprecated_rule,
)]
enforcer = policy.Enforcer(self.conf)
enforcer.register_defaults(rule_list)
with mock.patch('warnings.warn') as mock_warn:
enforcer.load_rules()
mock_warn.assert_called_once()
enforcer.load_rules()
enforcer.enforce('foo:create_bar', {}, {'roles': ['fizz']},
do_raise=True)
@@ -1387,6 +1372,7 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
check_str='role:baz',
description='Create a bar.',
operations=[{'path': '/v1/bars/', 'method': 'POST'}],
scope_types=['project'],
deprecated_rule=deprecated_rule,
)]
expected_msg = (
@@ -1459,6 +1445,8 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
mock_warn.assert_not_called()
def test_deprecate_check_str_suppress_does_not_log_warning(self):
self.conf.set_override('enforce_new_defaults', False,
group='oslo_policy')
deprecated_rule = policy.DeprecatedRule(
name='foo:create_bar',
check_str='role:fizz',
@@ -1481,6 +1469,8 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
mock_warn.assert_not_called()
def test_deprecate_name_suppress_does_not_log_warning(self):
self.conf.set_override('enforce_new_defaults', False,
group='oslo_policy')
deprecated_rule = policy.DeprecatedRule(
name='foo:bar',
check_str='role:baz',
@@ -1507,6 +1497,9 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
mock_warn.assert_not_called()
def test_deprecate_for_removal_suppress_does_not_log_warning(self):
self.conf.set_override('enforce_new_defaults', False,
group='oslo_policy')
rule_list = [policy.DocumentedRuleDefault(
name='foo:bar',
check_str='role:baz',
@@ -1529,6 +1522,9 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
mock_warn.assert_not_called()
def test_suppress_default_change_warnings_flag_not_log_warning(self):
self.conf.set_override('enforce_new_defaults', False,
group='oslo_policy')
deprecated_rule = policy.DeprecatedRule(
name='foo:create_bar',
check_str='role:fizz',
@@ -1759,8 +1755,6 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
self.assertEqual('bang', self.enforcer.rules['new_rule'].match)
def test_enforce_new_defaults_no_old_check_string(self):
self.conf.set_override('enforce_new_defaults', True,
group='oslo_policy')
deprecated_rule = policy.DeprecatedRule(
name='foo:create_bar',
check_str='role:fizz',
@@ -1791,6 +1785,43 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
enforcer.enforce('foo:create_bar', {}, {'roles': ['baz']})
)
def test_disable_enforce_new_defaults_add_old_check_string(self):
self.conf.set_override('enforce_new_defaults', False,
group='oslo_policy')
deprecated_rule = policy.DeprecatedRule(
name='foo:create_bar',
check_str='role:fizz',
deprecated_reason='"role:bang" is a better default',
deprecated_since='N',
)
rule_list = [policy.DocumentedRuleDefault(
name='foo:create_bar',
check_str='role:bang',
description='Create a bar.',
operations=[{'path': '/v1/bars', 'method': 'POST'}],
deprecated_rule=deprecated_rule,
)]
enforcer = policy.Enforcer(self.conf)
enforcer.register_defaults(rule_list)
enforcer.load_rules()
expected_check = policy.OrCheck([
_parser.parse_rule(cs) for cs in
[rule_list[0].check_str, deprecated_rule.check_str]
])
self.assertEqual(
str(enforcer.rules['foo:create_bar']), str(expected_check))
self.assertTrue(
enforcer.enforce('foo:create_bar', {}, {'roles': ['bang']})
)
self.assertTrue(
enforcer.enforce('foo:create_bar', {}, {'roles': ['fizz']})
)
self.assertFalse(
enforcer.enforce('foo:create_bar', {}, {'roles': ['baz']})
)
def test_deprecation_logic_is_only_performed_once_per_rule(self):
deprecated_rule = policy.DeprecatedRule(
name='foo:create_bar',
@@ -1817,15 +1848,12 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
enforcer.load_rules()
# Loading the rules will store a version of the rule check string
# logically ORed with the check string of the deprecated value. Make
# sure this is happening but that the original rule check is unchanged
expected_check = policy.OrCheck([
_parser.parse_rule(cs) for cs in
[rule.check_str, deprecated_rule.check_str]
])
# but as enforce_new_defaults is True it will not logically ORed with
# the check string of the deprecated value. Make sure this is happening
# and the original rule check is unchanged
self.assertIn('foo:create_bar', enforcer.rules)
self.assertEqual(
str(enforcer.rules['foo:create_bar']), str(expected_check))
self.assertEqual(rule.check_str,
str(enforcer.rules['foo:create_bar']))
self.assertEqual(check, rule.check)
# Hacky way to check whether _handle_deprecated_rule was called again.
# If a second call to load_rules doesn't overwrite our dummy rule then

View File

@@ -0,0 +1,23 @@
---
upgrade:
- |
The default value of config options ``enforce_scope`` and
``enforce_new_defaults`` have been changed to ``True``.
Most of the OpenStack services have enabled these options by
default, and now it's time to change the default in the oslo
policy itself.
If you want to disable them, modify the values of these config
options in the service configuration file (for example, "nova.conf")::
[oslo_policy]
enforce_new_defaults=False
enforce_scope=False
deprecations:
- |
The ``enforce_scope`` configuration option was added temporarily
to facilitate a smooth transition to the new RBAC. OpenStack will
always enforce the scope checks, and they will not be configurable.
This configuration option is marked as deprecated and will be removed
in the 2025.2 cycle.