diff --git a/keystone/cmd/status.py b/keystone/cmd/status.py index d3b6ee09bc..3585c2e2b1 100644 --- a/keystone/cmd/status.py +++ b/keystone/cmd/status.py @@ -14,11 +14,15 @@ from oslo_policy import _checks from oslo_policy import policy from oslo_upgradecheck import upgradecheck +from keystone.common import driver_hints +from keystone.common import provider_api from keystone.common import rbac_enforcer import keystone.conf +from keystone.server import backends CONF = keystone.conf.CONF ENFORCER = rbac_enforcer.RBACEnforcer +PROVIDERS = provider_api.ProviderAPIs class Checks(upgradecheck.UpgradeCommands): @@ -60,12 +64,32 @@ class Checks(upgradecheck.UpgradeCommands): return upgradecheck.Result( upgradecheck.Code.SUCCESS, 'Trust policies are safe.') + def check_default_roles_are_immutable(self): + hints = driver_hints.Hints() + hints.add_filter('domain_id', None) # Only check global roles + roles = PROVIDERS.role_api.list_roles(hints=hints) + default_roles = ('admin', 'member', 'reader',) + failed_roles = [] + for role in [r for r in roles if r['name'] in default_roles]: + if not role.get('options', {}).get('immutable'): + failed_roles.append(role['name']) + if any(failed_roles): + return upgradecheck.Result( + upgradecheck.Code.FAILURE, + "Roles are not immutable: %s" % ", ".join(failed_roles) + ) + return upgradecheck.Result( + upgradecheck.Code.SUCCESS, "Default roles are immutable.") + _upgrade_checks = ( ("Check trust policies are not empty", check_trust_policies_are_not_empty), + ("Check default roles are immutable", + check_default_roles_are_immutable), ) def main(): keystone.conf.configure() + backends.load_backends() return upgradecheck.main(CONF, 'keystone', Checks()) diff --git a/keystone/tests/unit/test_cli.py b/keystone/tests/unit/test_cli.py index 65540d39ce..42c771a9f4 100644 --- a/keystone/tests/unit/test_cli.py +++ b/keystone/tests/unit/test_cli.py @@ -1870,6 +1870,7 @@ class TestMappingEngineTester(unit.BaseTestCase): class CliStatusTestCase(unit.SQLDriverOverrides, unit.TestCase): def setUp(self): + self.useFixture(database.Database()) super(CliStatusTestCase, self).setUp() self.load_backends() self.policy_file = self.useFixture(temporaryfile.SecureTempFile()) @@ -1909,3 +1910,24 @@ class CliStatusTestCase(unit.SQLDriverOverrides, unit.TestCase): f.write(jsonutils.dumps(overridden_policies)) result = self.checks.check_trust_policies_are_not_empty() self.assertEqual(upgradecheck.Code.SUCCESS, result.code) + + def test_check_immutable_roles(self): + role_ref = unit.new_role_ref(name='admin') + PROVIDERS.role_api.create_role(role_ref['id'], role_ref) + result = self.checks.check_default_roles_are_immutable() + self.assertEqual(upgradecheck.Code.FAILURE, result.code) + role_ref['options'] = {'immutable': True} + PROVIDERS.role_api.update_role(role_ref['id'], role_ref) + result = self.checks.check_default_roles_are_immutable() + self.assertEqual(upgradecheck.Code.SUCCESS, result.code) + # Check domain-specific roles are not reported + PROVIDERS.resource_api.create_domain( + default_fixtures.ROOT_DOMAIN['id'], + default_fixtures.ROOT_DOMAIN) + domain_ref = unit.new_domain_ref() + domain = PROVIDERS.resource_api.create_domain( + domain_ref['id'], domain_ref) + role_ref = unit.new_role_ref(name='admin', domain_id=domain['id']) + PROVIDERS.role_api.create_role(role_ref['id'], role_ref) + result = self.checks.check_default_roles_are_immutable() + self.assertEqual(upgradecheck.Code.SUCCESS, result.code) diff --git a/releasenotes/notes/bug-1823258-9f93dbdc0fa8441d.yaml b/releasenotes/notes/bug-1823258-9f93dbdc0fa8441d.yaml new file mode 100644 index 0000000000..b89c92018c --- /dev/null +++ b/releasenotes/notes/bug-1823258-9f93dbdc0fa8441d.yaml @@ -0,0 +1,11 @@ +--- +features: + - | + [`bug 1823258 `_] + Adds support for an "immutable" resource option for roles, which when + enabled prevents accidental harmful modification or deletion of roles. Also + adds a new flag ``--immutable-roles`` to the ``keystone-manage bootstrap`` + command to make the default roles (admin, member, and reader) immutable by + default, as well as a check in the ``keystone-status upgrade check`` + command to check that these roles have been made immutable. In a future + release, these three roles will be immutable by default.