From 9e2af26b6d10c145dcb51dfb9e54bd8b2906bcfa Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Fri, 31 Aug 2018 15:25:27 +0100 Subject: [PATCH] Make image location ops policy configurable Some users may not want *_image_location operations to be restricted to role:admin so this patch allows that to be configurable and sets the default to be False since enabling this by default is breaking RBD COW clones in Nova for non-admin users (and anywhere else that relies on that information). Change-Id: I8c293d6036bc1d6104dab5458f6915968459a09e Closes-Bug: #1786144 --- config.yaml | 12 ++++++++++++ hooks/glance_utils.py | 6 +++++- unit_tests/test_glance_utils.py | 29 ++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/config.yaml b/config.yaml index 9eb67cfa..ac3829d7 100644 --- a/config.yaml +++ b/config.yaml @@ -126,6 +126,18 @@ options: Expose underlying image locations via the API when using Ceph for image storage. Only disable this option if you do not wish to use copy-on-write clones of RAW format images with Ceph in Cinder and Nova. + restrict-image-location-operations: + type: boolean + default: False + description: | + If this is set to True, all *_image_location operations in the Glance api + will be restricted to role:admin which will result in non-admin users no + longer being able to view the "locations" information for an image. + This only affects environments that have expose-image-locations set to + True. + WARNING: enabling this restriction will cause Nova to no longer be able + to create COW clones or snapshots for non-admin users when using the + RBDImageBackend in the nova-compute charm. rabbit-user: type: string default: glance diff --git a/hooks/glance_utils.py b/hooks/glance_utils.py index 0b533c83..6be9f6fa 100644 --- a/hooks/glance_utils.py +++ b/hooks/glance_utils.py @@ -562,7 +562,11 @@ def update_image_location_policy(): log("key '{}' not found in policy file".format(policy_key), level=INFO) - policy_value = 'role:admin' + if config('restrict-image-location-operations'): + policy_value = 'role:admin' + else: + policy_value = '' + log("Updating Glance policy file setting policy " "'{}':'{}'".format(policy_key, policy_value), level=INFO) update_json_file(GLANCE_POLICY_FILE, {policy_key: policy_value}) diff --git a/unit_tests/test_glance_utils.py b/unit_tests/test_glance_utils.py index f7c33bd9..6cc79cca 100644 --- a/unit_tests/test_glance_utils.py +++ b/unit_tests/test_glance_utils.py @@ -297,13 +297,19 @@ class TestGlanceUtils(CharmTestCase): def test_is_api_ready_false(self): self._test_is_api_ready(False) + @patch.object(utils, 'config') @patch.object(utils, 'json') @patch.object(utils, 'update_json_file') @patch.object(utils, 'kv') @patch.object(utils, 'os_release') def test_update_image_location_policy(self, mock_os_release, mock_kv, - mock_update_json_file, mock_json): + mock_update_json_file, mock_json, + mock_config): db_vals = {} + config = {'restrict-image-location-operations': False} + + def fake_config(key): + return config.get(key) def fake_db_get(key): return db_vals.get(key) @@ -313,6 +319,8 @@ class TestGlanceUtils(CharmTestCase): db_obj.get.side_effect = fake_db_get db_obj.set = MagicMock() + mock_config.side_effect = fake_config + fake_open = mock_open() with patch.object(utils, 'open', fake_open, create=True): mock_json.loads.return_value = {'get_image_location': '', @@ -326,6 +334,25 @@ class TestGlanceUtils(CharmTestCase): mock_os_release.return_value = 'kilo' utils.update_image_location_policy() self.assertTrue(mock_kv.called) + mock_update_json_file.assert_has_calls([ + call('/etc/glance/policy.json', + {'get_image_location': ''}), + call('/etc/glance/policy.json', + {'set_image_location': ''}), + call('/etc/glance/policy.json', + {'delete_image_location': ''})]) + + mock_update_json_file.reset_mock() + config['restrict-image-location-operations'] = True + utils.update_image_location_policy() + mock_update_json_file.assert_has_calls([ + call('/etc/glance/policy.json', + {'get_image_location': 'role:admin'}), + call('/etc/glance/policy.json', + {'set_image_location': 'role:admin'}), + call('/etc/glance/policy.json', + {'delete_image_location': 'role:admin'})]) + db_obj.get.assert_has_calls([call('policy_get_image_location'), call('policy_set_image_location'), call('policy_delete_image_location')])