Add immutable roles status check
This implements part 3 of the proposed change for immutable roles[1], as well as adds a release note. Part 4 (changing the default behavior of ``keystone-manage bootstrap`` will have to come in the next cycle. [1] http://specs.openstack.org/openstack/keystone-specs/specs/keystone/train/immutable-resources.html#proposed-change Change-Id: Ie9d658deb1fa69e9007f3c50535b5c48a7a292d1 Partial-bug: #1823258
This commit is contained in:
parent
a80d83e76d
commit
5e06ec8163
|
@ -14,11 +14,15 @@ from oslo_policy import _checks
|
||||||
from oslo_policy import policy
|
from oslo_policy import policy
|
||||||
from oslo_upgradecheck import upgradecheck
|
from oslo_upgradecheck import upgradecheck
|
||||||
|
|
||||||
|
from keystone.common import driver_hints
|
||||||
|
from keystone.common import provider_api
|
||||||
from keystone.common import rbac_enforcer
|
from keystone.common import rbac_enforcer
|
||||||
import keystone.conf
|
import keystone.conf
|
||||||
|
from keystone.server import backends
|
||||||
|
|
||||||
CONF = keystone.conf.CONF
|
CONF = keystone.conf.CONF
|
||||||
ENFORCER = rbac_enforcer.RBACEnforcer
|
ENFORCER = rbac_enforcer.RBACEnforcer
|
||||||
|
PROVIDERS = provider_api.ProviderAPIs
|
||||||
|
|
||||||
|
|
||||||
class Checks(upgradecheck.UpgradeCommands):
|
class Checks(upgradecheck.UpgradeCommands):
|
||||||
|
@ -60,12 +64,32 @@ class Checks(upgradecheck.UpgradeCommands):
|
||||||
return upgradecheck.Result(
|
return upgradecheck.Result(
|
||||||
upgradecheck.Code.SUCCESS, 'Trust policies are safe.')
|
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 = (
|
_upgrade_checks = (
|
||||||
("Check trust policies are not empty",
|
("Check trust policies are not empty",
|
||||||
check_trust_policies_are_not_empty),
|
check_trust_policies_are_not_empty),
|
||||||
|
("Check default roles are immutable",
|
||||||
|
check_default_roles_are_immutable),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
keystone.conf.configure()
|
keystone.conf.configure()
|
||||||
|
backends.load_backends()
|
||||||
return upgradecheck.main(CONF, 'keystone', Checks())
|
return upgradecheck.main(CONF, 'keystone', Checks())
|
||||||
|
|
|
@ -1870,6 +1870,7 @@ class TestMappingEngineTester(unit.BaseTestCase):
|
||||||
class CliStatusTestCase(unit.SQLDriverOverrides, unit.TestCase):
|
class CliStatusTestCase(unit.SQLDriverOverrides, unit.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
self.useFixture(database.Database())
|
||||||
super(CliStatusTestCase, self).setUp()
|
super(CliStatusTestCase, self).setUp()
|
||||||
self.load_backends()
|
self.load_backends()
|
||||||
self.policy_file = self.useFixture(temporaryfile.SecureTempFile())
|
self.policy_file = self.useFixture(temporaryfile.SecureTempFile())
|
||||||
|
@ -1909,3 +1910,24 @@ class CliStatusTestCase(unit.SQLDriverOverrides, unit.TestCase):
|
||||||
f.write(jsonutils.dumps(overridden_policies))
|
f.write(jsonutils.dumps(overridden_policies))
|
||||||
result = self.checks.check_trust_policies_are_not_empty()
|
result = self.checks.check_trust_policies_are_not_empty()
|
||||||
self.assertEqual(upgradecheck.Code.SUCCESS, result.code)
|
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)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
[`bug 1823258 <https://bugs.launchpad.net/keystone/+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.
|
Loading…
Reference in New Issue