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')])