From a80d83e76dfb1114b8cd1b31bd2f175d36ae18ae Mon Sep 17 00:00:00 2001 From: Colleen Murphy Date: Wed, 7 Aug 2019 16:22:05 -0700 Subject: [PATCH] Add --immutable-roles flag to bootstrap command This implements Step 2 of the Proposed Change for Immutable Resources[1]. [1] http://specs.openstack.org/openstack/keystone-specs/specs/keystone/train/immutable-resources.html#proposed-change Change-Id: I4d99f630cb16e1d58261012e59d3a92c7035734c Partial-bug: #1823258 --- keystone/cmd/bootstrap.py | 12 ++++++++++++ keystone/cmd/cli.py | 9 +++++++++ keystone/tests/unit/test_cli.py | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/keystone/cmd/bootstrap.py b/keystone/cmd/bootstrap.py index d0e0af867e..b18a3f5501 100644 --- a/keystone/cmd/bootstrap.py +++ b/keystone/cmd/bootstrap.py @@ -56,6 +56,8 @@ class Bootstrapper(object): self.default_domain_id = None self.admin_user_id = None + self.immutable_roles = False + def bootstrap(self): # NOTE(morganfainberg): Ensure the default domain is in-fact created self._bootstrap_default_domain() @@ -114,8 +116,18 @@ class Bootstrapper(object): try: role_id = uuid.uuid4().hex role = {'name': role_name, 'id': role_id} + if self.immutable_roles: + role['options'] = {'immutable': True} role = PROVIDERS.role_api.create_role(role_id, role) LOG.info('Created role %s', role_name) + if not self.immutable_roles: + LOG.warning("Role %(role)s was created as a mutable role. It " + "is recommended to make this role immutable, " + "which will become the default behavior of the " + "bootstrap command in the future.You can opt into " + "this behavior by using the --immutable-role " + "flag, or update role %(role)s with the " + "'immutable' resource option.", {'role': role_name}) return role except exception.Conflict: LOG.info('Role %s exists, skipping creation.', role_name) diff --git a/keystone/cmd/cli.py b/keystone/cmd/cli.py index 6c9b999271..272bd5cb9a 100644 --- a/keystone/cmd/cli.py +++ b/keystone/cmd/cli.py @@ -111,6 +111,14 @@ class BootStrap(BaseApp): help=('The initial region_id endpoints will be ' 'placed in during the keystone bootstrap ' 'process.')) + parser.add_argument('--immutable-roles', + default=False, + action='store_true', + help=('Whether default roles (admin, member, and ' + 'reader) should be immutable. Immutable ' + 'default roles is currently an opt-in ' + 'behavior, but will become the default in ' + 'future releases.')) return parser def do_bootstrap(self): @@ -166,6 +174,7 @@ class BootStrap(BaseApp): self.bootstrapper.public_url = self.public_url self.bootstrapper.internal_url = self.internal_url self.bootstrapper.region_id = self.region_id + self.bootstrapper.immutable_roles = CONF.command.immutable_roles self.bootstrapper.bootstrap() self.reader_role_id = self.bootstrapper.reader_role_id diff --git a/keystone/tests/unit/test_cli.py b/keystone/tests/unit/test_cli.py index 15d87bab77..65540d39ce 100644 --- a/keystone/tests/unit/test_cli.py +++ b/keystone/tests/unit/test_cli.py @@ -219,6 +219,12 @@ class CliBootStrapTestCase(unit.SQLDriverOverrides, unit.TestCase): c.get('/v3/auth/tokens', headers={'X-Auth-Token': r.headers['X-Subject-Token'], 'X-Subject-Token': token}) + admin_role = PROVIDERS.role_api.get_role(self.bootstrap.role_id) + reader_role = PROVIDERS.role_api.get_role(self.bootstrap.reader_role_id) + member_role = PROVIDERS.role_api.get_role(self.bootstrap.member_role_id) + self.assertEqual(admin_role['options'], {}) + self.assertEqual(member_role['options'], {}) + self.assertEqual(reader_role['options'], {}) def test_bootstrap_is_not_idempotent_when_password_does_change(self): # NOTE(lbragstad): Ensure bootstrap isn't idempotent when run with @@ -292,6 +298,19 @@ class CliBootStrapTestCase(unit.SQLDriverOverrides, unit.TestCase): user_id, self.bootstrap.password) + def test_bootstrap_with_immutable_roles(self): + CONF(args=['bootstrap', + '--bootstrap-password', uuid.uuid4().hex, + '--immutable-roles'], + project='keystone') + self._do_test_bootstrap(self.bootstrap) + admin_role = PROVIDERS.role_api.get_role(self.bootstrap.role_id) + reader_role = PROVIDERS.role_api.get_role(self.bootstrap.reader_role_id) + member_role = PROVIDERS.role_api.get_role(self.bootstrap.member_role_id) + self.assertTrue(admin_role['options']['immutable']) + self.assertTrue(member_role['options']['immutable']) + self.assertTrue(reader_role['options']['immutable']) + class CliBootStrapTestCaseWithEnvironment(CliBootStrapTestCase):