Merge "Add policy granularity to the encryption API"

This commit is contained in:
Zuul 2018-09-25 08:55:32 +00:00 committed by Gerrit Code Review
commit 4580c56058
5 changed files with 147 additions and 6 deletions

View File

@ -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.')

View File

@ -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"
GET_POLICY = "volume_extension:type_get"
@ -68,7 +73,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',
@ -91,6 +97,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,

View File

@ -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

View File

@ -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)

View File

@ -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.