Skip to content

Commit d4af91f

Browse files
committed
Add nova-status upgrade check and reno for policy new defaults
There are cases where policy file is re-generated freshly and end up having the new defaults only but expectation is that old deprecated rule keep working. If a rule is present in policy file then, that has priority over its defaults so either rules should not be present in policy file or users need to update their token to match the overridden rule permission. This issue was always present when any policy defaults were changed with old defaults being supported as deprecated. This is we have changed all the policy for new defaults so it came up as broken case. Adding nova-status upgrade check also to detect such policy file. Related-Bug: #1875418 Change-Id: Id9cd65877e53577bff22e408ca07bbeec4407f6e
1 parent 347d656 commit d4af91f

File tree

5 files changed

+163
-0
lines changed

5 files changed

+163
-0
lines changed

doc/source/cli/nova-status.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ Upgrade
143143
**21.0.0 (Ussuri)**
144144
* Checks for the Placement API are modified to require version 1.35.
145145

146+
**21.0.0 (Ussuri)**
147+
148+
* Checks for the policy files are not automatically overwritten with
149+
new defaults.
150+
146151
See Also
147152
========
148153

doc/source/install/verify.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,7 @@ Verify operation of the Compute service.
123123
| Result: Success |
124124
| Details: None |
125125
+--------------------------------------------------------------------+
126+
| Check: Policy Scope-based Defaults |
127+
| Result: Success |
128+
| Details: None |
129+
+--------------------------------------------------------------------+

nova/cmd/status.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from nova import exception
4141
from nova.i18n import _
4242
from nova.objects import cell_mapping as cell_mapping_obj
43+
from nova import policy
4344
from nova import utils
4445
from nova import version
4546
from nova.volume import cinder
@@ -346,6 +347,70 @@ def _check_cinder(self):
346347
six.text_type(ex))
347348
return upgradecheck.Result(upgradecheck.Code.SUCCESS)
348349

350+
def _check_policy(self):
351+
"""Checks to see if policy file is overwritten with the new
352+
defaults.
353+
"""
354+
msg = _("Your policy file contains rules which examine token scope, "
355+
"which may be due to generation with the new defaults. "
356+
"If that is done intentionally to migrate to the new rule "
357+
"format, then you are required to enable the flag "
358+
"'oslo_policy.enforce_scope=True' and educate end users on "
359+
"how to request scoped tokens from Keystone. Another easy "
360+
"and recommended way for you to achieve the same is via two "
361+
"flags, 'oslo_policy.enforce_scope=True' and "
362+
"'oslo_policy.enforce_new_defaults=True' and avoid "
363+
"overwriting the file. Please refer to this document to "
364+
"know the complete migration steps: "
365+
"https://docs.openstack.org/nova/latest/configuration"
366+
"/policy-concepts.html. If you did not intend to migrate "
367+
"to new defaults in this upgrade, then with your current "
368+
"policy file the scope checking rule will fail. A possible "
369+
"reason for such a policy file is that you generated it with "
370+
"'oslopolicy-sample-generator' in json format. "
371+
"Three ways to fix this until you are ready to migrate to "
372+
"scoped policies: 1. Generate the policy file with "
373+
"'oslopolicy-sample-generator' in yaml format, keep "
374+
"the generated content commented out, and update "
375+
"the generated policy.yaml location in "
376+
"``oslo_policy.policy_file``. "
377+
"2. Use a pre-existing sample config file from the Train "
378+
"release. 3. Use an empty or non-existent file to take all "
379+
"the defaults.")
380+
rule = "system_admin_api"
381+
rule_new_default = "role:admin and system_scope:all"
382+
status = upgradecheck.Result(upgradecheck.Code.SUCCESS)
383+
# NOTE(gmann): Initialise the policy if it not initialized.
384+
# We need policy enforcer with all the rules loaded to check
385+
# their value with defaults.
386+
try:
387+
if policy._ENFORCER is None:
388+
policy.init(suppress_deprecation_warnings=True)
389+
390+
# For safer side, recheck that the enforcer is available before
391+
# upgrade checks. If something is wrong on oslo side and enforcer
392+
# is still not available the return warning to avoid any false
393+
# result.
394+
if policy._ENFORCER is not None:
395+
current_rule = str(policy._ENFORCER.rules[rule]).strip("()")
396+
if (current_rule == rule_new_default and
397+
not CONF.oslo_policy.enforce_scope):
398+
status = upgradecheck.Result(upgradecheck.Code.WARNING,
399+
msg)
400+
else:
401+
status = upgradecheck.Result(
402+
upgradecheck.Code.WARNING,
403+
_('Policy is not initialized to check the policy rules'))
404+
except Exception as ex:
405+
status = upgradecheck.Result(
406+
upgradecheck.Code.WARNING,
407+
_('Unable to perform policy checks due to error: %s') %
408+
six.text_type(ex))
409+
# reset the policy state so that it can be initialized from fresh if
410+
# operator changes policy file after running this upgrade checks.
411+
policy.reset()
412+
return status
413+
349414
# The format of the check functions is to return an upgradecheck.Result
350415
# object with the appropriate upgradecheck.Code and details set. If the
351416
# check hits warnings or failures then those should be stored in the
@@ -362,6 +427,8 @@ def _check_cinder(self):
362427
(_('Ironic Flavor Migration'), _check_ironic_flavor_migration),
363428
# Added in Train
364429
(_('Cinder API'), _check_cinder),
430+
# Added in Ussuri
431+
(_('Policy Scope-based Defaults'), _check_policy),
365432
)
366433

367434

nova/tests/unit/cmd/test_status.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
# NOTE(mriedem): We only use objects as a convenience to populate the database
4040
# in the tests, we don't use them in the actual CLI.
4141
from nova import objects
42+
from nova import policy
4243
from nova import test
4344
from nova.tests import fixtures as nova_fixtures
45+
from nova.tests.unit import policy_fixture
4446

4547

4648
CONF = nova.conf.CONF
@@ -546,3 +548,57 @@ def test_microversion_available(self, mock_version_check):
546548
result = self.cmd._check_cinder()
547549
mock_version_check.assert_called_once()
548550
self.assertEqual(upgradecheck.Code.SUCCESS, result.code)
551+
552+
553+
class TestUpgradeCheckPolicy(test.NoDBTestCase):
554+
555+
new_default_status = upgradecheck.Code.WARNING
556+
557+
def setUp(self):
558+
super(TestUpgradeCheckPolicy, self).setUp()
559+
self.cmd = status.UpgradeCommands()
560+
self.rule_name = "system_admin_api"
561+
562+
def tearDown(self):
563+
super(TestUpgradeCheckPolicy, self).tearDown()
564+
# Check if policy is reset back after the upgrade check
565+
self.assertIsNone(policy._ENFORCER)
566+
567+
def test_policy_rule_with_new_defaults(self):
568+
new_default = "role:admin and system_scope:all"
569+
rule = {self.rule_name: new_default}
570+
self.policy.set_rules(rule, overwrite=False)
571+
self.assertEqual(self.new_default_status,
572+
self.cmd._check_policy().code)
573+
574+
def test_policy_rule_with_old_defaults(self):
575+
new_default = "is_admin:True"
576+
rule = {self.rule_name: new_default}
577+
self.policy.set_rules(rule, overwrite=False)
578+
579+
self.assertEqual(upgradecheck.Code.SUCCESS,
580+
self.cmd._check_policy().code)
581+
582+
def test_policy_rule_with_both_defaults(self):
583+
new_default = "(role:admin and system_scope:all) or is_admin:True"
584+
rule = {self.rule_name: new_default}
585+
self.policy.set_rules(rule, overwrite=False)
586+
587+
self.assertEqual(upgradecheck.Code.SUCCESS,
588+
self.cmd._check_policy().code)
589+
590+
def test_policy_checks_with_fresh_init_and_no_policy_override(self):
591+
self.policy = self.useFixture(policy_fixture.OverridePolicyFixture(
592+
rules_in_file={}))
593+
policy.reset()
594+
self.assertEqual(upgradecheck.Code.SUCCESS,
595+
self.cmd._check_policy().code)
596+
597+
598+
class TestUpgradeCheckPolicyEnableScope(TestUpgradeCheckPolicy):
599+
600+
new_default_status = upgradecheck.Code.SUCCESS
601+
602+
def setUp(self):
603+
super(TestUpgradeCheckPolicyEnableScope, self).setUp()
604+
self.flags(enforce_scope=True, group="oslo_policy")
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
upgrade:
3+
- |
4+
Nova policies implemented the ``scope_type`` and new defaults
5+
provided by keystone. Old defaults are deprecated and still work
6+
if rules are not overridden in the policy file. If you don't override
7+
any policies at all, then you don't need to do anything different until the
8+
W release when old deprecated rules are removed and tokens need to be
9+
scoped to work with new defaults and scope of policies. For migration
10+
to new policies you can refer to `this document
11+
<https://docs.openstack.org/nova/latest/configuration/policy-concepts.html#migration-plan>`_.
12+
13+
If you are overwriting the policy rules (all or some of them) in the policy
14+
file with new default values or any new value that requires scoped tokens,
15+
then non-scoped tokens will not work. Also if you generate the policy
16+
file with 'oslopolicy-sample-generator' json format or any other tool,
17+
you will get rules defaulted in the new format, which examines the token
18+
scope. Unless you turn on ``oslo_policy.enforce_scope``, scope-checking
19+
rules will fail. Thus, be sure to enable ``oslo_policy.enforce_scope`` and
20+
`educate <https://docs.openstack.org/nova/latest/configuration/policy-concepts.html>`_
21+
end users on how to request scoped tokens from Keystone, or
22+
use a pre-existing sample config file from the Train release until you are
23+
ready to migrate to scoped policies. Another way is to generate the policy
24+
file in yaml format as described `here
25+
<https://docs.openstack.org/oslo.policy/latest/cli/index.html#oslopolicy-policy-generator>`_
26+
and update the policy.yaml location in ``oslo_policy.policy_file``.
27+
28+
For more background about the possible problem, check `this bug
29+
<https://bugs.launchpad.net/nova/+bug/1875418>`_.
30+
A upgrade check has been added to the ``nova-status upgrade check``
31+
command for this.

0 commit comments

Comments
 (0)