Add policy granularity to the encryption API
Add granularity to the volume_extension:volume_type_encryption policy with the addition of actions for create, get, update, and delete. To address backwards compatibility, the new rules added to the cinder/policies/volume_type.py policy file, default to the existing rule (volume_extension:volume_type_encryption). That way across upgrades this should ensure if an existing admin has customised the rule, it keeps working, but folks that know about the new setting can override the default rule. In addtion, a verify_deprecated_policy method is added to see if the old policy action is being configured instead of the new actions. This verify_deprecated_policy method is adapted from previous nova commit from this patch: https://review.openstack.org/#/c/449288 Change-Id: Iba58e785df934d1c4175c0877d266193ac0167b7
This commit is contained in:
parent
1aa9231cb2
commit
ebc9a12a19
@ -25,7 +25,9 @@ from cinder.api import validation
|
||||
from cinder import db
|
||||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
from cinder.policies import base
|
||||
from cinder.policies import volume_type as policy
|
||||
from cinder import policy as cinder_policy
|
||||
from cinder import rpc
|
||||
from cinder.volume import volume_types
|
||||
|
||||
@ -56,10 +58,26 @@ class VolumeTypeEncryptionController(wsgi.Controller):
|
||||
else:
|
||||
return False
|
||||
|
||||
def _authorize_policy(self, context, new_policy):
|
||||
# TODO(cl566n): In future release, this _authorize_policy function
|
||||
# can be removed. The call to it can be replaced by
|
||||
# context.authorize(new_policy) once the old
|
||||
# policy.ENCRYPTION_POLICY is deprecated.
|
||||
|
||||
using_old_action = cinder_policy.verify_deprecated_policy(
|
||||
policy.ENCRYPTION_POLICY,
|
||||
new_policy,
|
||||
base.RULE_ADMIN_API,
|
||||
context)
|
||||
|
||||
if not using_old_action:
|
||||
context.authorize(new_policy)
|
||||
|
||||
def index(self, req, type_id):
|
||||
"""Returns the encryption specs for a given volume type."""
|
||||
context = req.environ['cinder.context']
|
||||
context.authorize(policy.ENCRYPTION_POLICY)
|
||||
self._authorize_policy(context, policy.GET_ENCRYPTION_POLICY)
|
||||
|
||||
self._check_type(context, type_id)
|
||||
return self._get_volume_type_encryption(context, type_id)
|
||||
|
||||
@ -67,7 +85,7 @@ class VolumeTypeEncryptionController(wsgi.Controller):
|
||||
def create(self, req, type_id, body):
|
||||
"""Create encryption specs for an existing volume type."""
|
||||
context = req.environ['cinder.context']
|
||||
context.authorize(policy.ENCRYPTION_POLICY)
|
||||
self._authorize_policy(context, policy.CREATE_ENCRYPTION_POLICY)
|
||||
|
||||
key_size = body['encryption'].get('key_size')
|
||||
if key_size is not None:
|
||||
@ -95,7 +113,7 @@ class VolumeTypeEncryptionController(wsgi.Controller):
|
||||
def update(self, req, type_id, id, body):
|
||||
"""Update encryption specs for a given volume type."""
|
||||
context = req.environ['cinder.context']
|
||||
context.authorize(policy.ENCRYPTION_POLICY)
|
||||
self._authorize_policy(context, policy.UPDATE_ENCRYPTION_POLICY)
|
||||
|
||||
key_size = body['encryption'].get('key_size')
|
||||
if key_size is not None:
|
||||
@ -119,7 +137,7 @@ class VolumeTypeEncryptionController(wsgi.Controller):
|
||||
def show(self, req, type_id, id):
|
||||
"""Return a single encryption item."""
|
||||
context = req.environ['cinder.context']
|
||||
context.authorize(policy.ENCRYPTION_POLICY)
|
||||
self._authorize_policy(context, policy.GET_ENCRYPTION_POLICY)
|
||||
|
||||
self._check_type(context, type_id)
|
||||
|
||||
@ -133,7 +151,7 @@ class VolumeTypeEncryptionController(wsgi.Controller):
|
||||
def delete(self, req, type_id, id):
|
||||
"""Delete encryption specs for a given volume type."""
|
||||
context = req.environ['cinder.context']
|
||||
context.authorize(policy.ENCRYPTION_POLICY)
|
||||
self._authorize_policy(context, policy.DELETE_ENCRYPTION_POLICY)
|
||||
|
||||
if self._encrypted_type_in_use(context, type_id):
|
||||
expl = _('Cannot delete encryption specs. Volume type in use.')
|
||||
|
@ -20,6 +20,11 @@ from cinder.policies import base
|
||||
|
||||
MANAGE_POLICY = "volume_extension:types_manage"
|
||||
ENCRYPTION_POLICY = "volume_extension:volume_type_encryption"
|
||||
BASE_POLICY_RULE = 'rule:%s' % ENCRYPTION_POLICY
|
||||
CREATE_ENCRYPTION_POLICY = "volume_extension:volume_type_encryption:create"
|
||||
GET_ENCRYPTION_POLICY = "volume_extension:volume_type_encryption:get"
|
||||
UPDATE_ENCRYPTION_POLICY = "volume_extension:volume_type_encryption:update"
|
||||
DELETE_ENCRYPTION_POLICY = "volume_extension:volume_type_encryption:delete"
|
||||
QOS_POLICY = "volume_extension:access_types_qos_specs_id"
|
||||
EXTRA_SPEC_POLICY = "volume_extension:access_types_extra_specs"
|
||||
|
||||
@ -46,7 +51,8 @@ volume_type_policies = [
|
||||
name=ENCRYPTION_POLICY,
|
||||
check_str=base.RULE_ADMIN_API,
|
||||
description="List, show, create, update and delete volume "
|
||||
"type encryption.",
|
||||
"type encryption. This is deprecated in the Stein "
|
||||
"release and will be removed in the future.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'POST',
|
||||
@ -69,6 +75,50 @@ volume_type_policies = [
|
||||
'path': '/types/{type_id}/encryption/{encryption_id}'
|
||||
}
|
||||
]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=CREATE_ENCRYPTION_POLICY,
|
||||
check_str=BASE_POLICY_RULE,
|
||||
description="Create volume type encryption.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'POST',
|
||||
'path': '/types/{type_id}/encryption'
|
||||
}
|
||||
]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=GET_ENCRYPTION_POLICY,
|
||||
check_str=BASE_POLICY_RULE,
|
||||
description="Show, list volume type encryption.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'GET',
|
||||
'path': '/types/{type_id}/encryption/{encryption_id}'
|
||||
},
|
||||
{
|
||||
'method': 'GET',
|
||||
'path': '/types/{type_id}/encryption'
|
||||
}
|
||||
]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=UPDATE_ENCRYPTION_POLICY,
|
||||
check_str=BASE_POLICY_RULE,
|
||||
description="Update volume type encryption.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'PUT',
|
||||
'path': '/types/{type_id}/encryption/{encryption_id}'
|
||||
}
|
||||
]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=DELETE_ENCRYPTION_POLICY,
|
||||
check_str=BASE_POLICY_RULE,
|
||||
description="Delete volume type encryption.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'DELETE',
|
||||
'path': '/types/{type_id}/encryption/{encryption_id}'
|
||||
}
|
||||
]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=EXTRA_SPEC_POLICY,
|
||||
check_str=base.RULE_ADMIN_API,
|
||||
|
@ -178,3 +178,33 @@ def check_is_admin(context):
|
||||
credentials = context.to_policy_values()
|
||||
target = credentials
|
||||
return _ENFORCER.authorize('context_is_admin', target, credentials)
|
||||
|
||||
|
||||
def verify_deprecated_policy(old_policy, new_policy, default_rule, context):
|
||||
"""Check the rule of the deprecated policy action
|
||||
|
||||
If the current rule of the deprecated policy action is set to a non-default
|
||||
value, then a warning message is logged stating that the new policy
|
||||
action should be used to dictate permissions as the old policy action is
|
||||
being deprecated.
|
||||
|
||||
:param old_policy: policy action that is being deprecated
|
||||
:param new_policy: policy action that is replacing old_policy
|
||||
:param default_rule: the old_policy action default rule value
|
||||
:param context: the cinder context
|
||||
"""
|
||||
|
||||
if _ENFORCER:
|
||||
current_rule = str(_ENFORCER.rules[old_policy])
|
||||
else:
|
||||
current_rule = None
|
||||
|
||||
if current_rule != default_rule:
|
||||
LOG.warning('Start using the new action %(new_policy)s. The existing '
|
||||
'action %(old_policy)s is being deprecated and will be '
|
||||
'removed in future release.',
|
||||
{'new_policy': new_policy, 'old_policy': old_policy})
|
||||
|
||||
context.authorize(old_policy)
|
||||
return True
|
||||
return False
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
import os.path
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as config_fixture
|
||||
from oslo_policy import policy as oslo_policy
|
||||
@ -75,6 +76,9 @@ class PolicyTestCase(test.TestCase):
|
||||
"role:admin"),
|
||||
oslo_policy.RuleDefault("test:uppercase_admin",
|
||||
"role:ADMIN"),
|
||||
oslo_policy.RuleDefault("old_action_not_default", "@"),
|
||||
oslo_policy.RuleDefault("new_action", "@"),
|
||||
oslo_policy.RuleDefault("old_action_default", "rule:admin_api"),
|
||||
]
|
||||
policy.reset()
|
||||
policy.init()
|
||||
@ -129,3 +133,26 @@ class PolicyTestCase(test.TestCase):
|
||||
roles=['AdMiN'])
|
||||
policy.authorize(admin_context, lowercase_action, self.target)
|
||||
policy.authorize(admin_context, uppercase_action, self.target)
|
||||
|
||||
@mock.patch.object(policy.LOG, 'warning')
|
||||
def test_verify_deprecated_policy_using_old_action(self, mock_warning):
|
||||
|
||||
old_policy = "old_action_not_default"
|
||||
new_policy = "new_action"
|
||||
default_rule = "rule:admin_api"
|
||||
|
||||
using_old_action = policy.verify_deprecated_policy(
|
||||
old_policy, new_policy, default_rule, self.context)
|
||||
|
||||
self.assertTrue(mock_warning.called)
|
||||
self.assertTrue(using_old_action)
|
||||
|
||||
def test_verify_deprecated_policy_using_new_action(self):
|
||||
old_policy = "old_action_default"
|
||||
new_policy = "new_action"
|
||||
default_rule = "rule:admin_api"
|
||||
|
||||
using_old_action = policy.verify_deprecated_policy(
|
||||
old_policy, new_policy, default_rule, self.context)
|
||||
|
||||
self.assertFalse(using_old_action)
|
||||
|
@ -0,0 +1,16 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Add granularity to the ``volume_extension:volume_type_encryption``
|
||||
policy with the addition of distinct actions for create, get, update,
|
||||
and delete:
|
||||
|
||||
- ``volume_extension:volume_type_encryption:create``
|
||||
- ``volume_extension:volume_type_encryption:get``
|
||||
- ``volume_extension:volume_type_encryption:update``
|
||||
- ``volume_extension:volume_type_encryption:delete``
|
||||
|
||||
To address backwards compatibility, the new rules added to the
|
||||
volume_type.py policy file, default to the existing rule,
|
||||
``volume_extension:volume_type_encryption``, if it is set to a
|
||||
non-default value.
|
Loading…
Reference in New Issue
Block a user