summaryrefslogtreecommitdiff
path: root/nova/keymgr
diff options
context:
space:
mode:
authorKaitlin Farr <kaitlin.farr@jhuapl.edu>2016-04-21 14:58:46 -0400
committerKaitlin Farr <kaitlin.farr@jhuapl.edu>2016-04-27 14:37:06 -0400
commitf006ff4de70077b05c3e4e266499bda2fc22db17 (patch)
treecf5093f9adcd1279ba7c59bc89304e57d577cb10 /nova/keymgr
parent9702e5d2e9433c67067847c02fb100cd808a3596 (diff)
downloadnova-f006ff4de70077b05c3e4e266499bda2fc22db17.tar.gz
Replace key manager with Castellan
Because key manager code is duplicated across several projects, a key manager interface was moved into its own library. This patch goes back to replace the old code with the new library. Change-Id: Ib563b0ea4b8b4bc1833bf52bf49a68546c384996 Implements: blueprint use-castellan-key-manager
Diffstat (limited to 'nova/keymgr')
-rw-r--r--nova/keymgr/__init__.py58
-rw-r--r--nova/keymgr/barbican.py340
-rw-r--r--nova/keymgr/conf_key_mgr.py92
-rw-r--r--nova/keymgr/key.py90
-rw-r--r--nova/keymgr/key_mgr.py102
-rw-r--r--nova/keymgr/mock_key_mgr.py133
-rw-r--r--nova/keymgr/not_implemented_key_mgr.py41
-rw-r--r--nova/keymgr/single_key_mgr.py72
8 files changed, 138 insertions, 790 deletions
diff --git a/nova/keymgr/__init__.py b/nova/keymgr/__init__.py
index 5e10b395b7..67dbb3ecc4 100644
--- a/nova/keymgr/__init__.py
+++ b/nova/keymgr/__init__.py
@@ -14,13 +14,65 @@
# under the License.
+from castellan import options as castellan_opts
+from oslo_config import cfg
+from oslo_log import log as logging
from oslo_utils import importutils
import nova.conf
+from nova.i18n import _LW
+LOG = logging.getLogger(__name__)
CONF = nova.conf.CONF
-def API():
- cls = importutils.import_class(CONF.keymgr.api_class)
- return cls()
+castellan_opts.set_defaults(CONF)
+
+# NOTE(kfarr): This line can be removed when a value is assigned in DevStack
+CONF.set_default('api_class', 'nova.keymgr.conf_key_mgr.ConfKeyManager',
+ group='key_manager')
+
+# NOTE(kfarr): For backwards compatibility, everything below this comment
+# is deprecated for removal
+api_class = None
+try:
+ api_class = CONF.key_manager.api_class
+except cfg.NoSuchOptError:
+ LOG.warning(_LW("key_manager.api_class is not set, will use deprecated "
+ "option keymgr.api_class if set"))
+ try:
+ api_class = CONF.keymgr.api_class
+ except cfg.NoSuchOptError:
+ LOG.warning(_LW("keymgr.api_class is not set"))
+
+deprecated_barbican = 'nova.keymgr.barbican.BarbicanKeyManager'
+barbican = 'castellan.key_manager.barbican_key_manager.BarbicanKeyManager'
+deprecated_mock = 'nova.tests.unit.keymgr.mock_key_mgr.MockKeyManager'
+castellan_mock = ('castellan.tests.unit.key_manager.mock_key_manager.'
+ 'MockKeyManager')
+
+
+def log_deprecated_warning(deprecated, castellan):
+ LOG.warning(_LW("key manager api_class set to use deprecated option "
+ "%(deprecated)s, using %(castellan)s instead"),
+ {'deprecated': deprecated, 'castellan': castellan})
+
+if api_class == deprecated_barbican:
+ log_deprecated_warning(deprecated_barbican, barbican)
+ api_class = barbican
+elif api_class == deprecated_mock:
+ log_deprecated_warning(deprecated_mock, castellan_mock)
+ api_class = castellan_mock
+elif api_class is None:
+ # TODO(kfarr): key_manager.api_class should be set in DevStack, and this
+ # block can be removed
+ LOG.warning(_LW("key manager not set, using insecure default %s"),
+ castellan_mock)
+ api_class = castellan_mock
+
+CONF.set_override('api_class', api_class, 'key_manager')
+
+
+def API(conf=CONF):
+ cls = importutils.import_class(CONF.key_manager.api_class)
+ return cls(conf)
diff --git a/nova/keymgr/barbican.py b/nova/keymgr/barbican.py
deleted file mode 100644
index 972d81f0a5..0000000000
--- a/nova/keymgr/barbican.py
+++ /dev/null
@@ -1,340 +0,0 @@
-# Copyright (c) 2015 The Johns Hopkins University/Applied Physics Laboratory
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-Key manager implementation for Barbican
-"""
-
-import array
-import base64
-import binascii
-
-from barbicanclient import client as barbican_client
-from keystoneauth1 import loading as ks_loading
-from keystoneauth1 import session
-from oslo_log import log as logging
-from oslo_utils import excutils
-
-import nova.conf
-
-from nova import exception
-from nova.i18n import _
-from nova.i18n import _LE
-from nova.keymgr import key as keymgr_key
-from nova.keymgr import key_mgr
-
-
-CONF = nova.conf.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-class BarbicanKeyManager(key_mgr.KeyManager):
- """Key Manager Interface that wraps the Barbican client API."""
-
- def __init__(self):
- self._barbican_client = None
- self._current_context = None
- self._base_url = None
-
- def _get_barbican_client(self, ctxt):
- """Creates a client to connect to the Barbican service.
-
- :param ctxt: the user context for authentication
- :return: a Barbican Client object
- :raises Forbidden: if the ctxt is None
- """
-
- # Confirm context is provided, if not raise forbidden
- if not ctxt:
- msg = _("User is not authorized to use key manager.")
- LOG.error(msg)
- raise exception.Forbidden(msg)
-
- if not hasattr(ctxt, 'project_id') or ctxt.project_id is None:
- msg = _("Unable to create Barbican Client without project_id.")
- LOG.error(msg)
- raise exception.KeyManagerError(msg)
-
- # If same context, return cached barbican client
- if self._barbican_client and self._current_context == ctxt:
- return self._barbican_client
-
- try:
- _SESSION = ks_loading.load_session_from_conf_options(
- CONF,
- nova.conf.barbican.barbican_group.name)
-
- auth = ctxt.get_auth_plugin()
- service_type, service_name, interface = (CONF.
- barbican.
- catalog_info.
- split(':'))
- region_name = CONF.barbican.os_region_name
- service_parameters = {'service_type': service_type,
- 'service_name': service_name,
- 'interface': interface,
- 'region_name': region_name}
-
- if CONF.barbican.endpoint_template:
- self._base_url = (CONF.barbican.endpoint_template %
- ctxt.to_dict())
- else:
- self._base_url = _SESSION.get_endpoint(
- auth, **service_parameters)
-
- # the barbican endpoint can't have the '/v1' on the end
- self._barbican_endpoint = self._base_url.rpartition('/')[0]
-
- sess = session.Session(auth=auth)
- self._barbican_client = barbican_client.Client(
- session=sess,
- endpoint=self._barbican_endpoint)
- self._current_context = ctxt
-
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error creating Barbican client: %s"), e)
-
- return self._barbican_client
-
- def create_key(self, ctxt, expiration=None, name='Nova Compute Key',
- payload_content_type='application/octet-stream', mode='CBC',
- algorithm='AES', length=256):
- """Creates a key.
-
- :param ctxt: contains information of the user and the environment
- for the request (nova/context.py)
- :param expiration: the date the key will expire
- :param name: a friendly name for the secret
- :param payload_content_type: the format/type of the secret data
- :param mode: the algorithm mode (e.g. CBC or CTR mode)
- :param algorithm: the algorithm associated with the secret
- :param length: the bit length of the secret
-
- :return: the UUID of the new key
- :raises Exception: if key creation fails
- """
- barbican_client = self._get_barbican_client(ctxt)
-
- try:
- key_order = barbican_client.orders.create_key(
- name,
- algorithm,
- length,
- mode,
- payload_content_type,
- expiration)
- order_ref = key_order.submit()
- order = barbican_client.orders.get(order_ref)
- return self._retrieve_secret_uuid(order.secret_ref)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error creating key: %s"), e)
-
- def store_key(self, ctxt, key, expiration=None, name='Nova Compute Key',
- payload_content_type='application/octet-stream',
- payload_content_encoding='base64', algorithm='AES',
- bit_length=256, mode='CBC', from_copy=False):
- """Stores (i.e., registers) a key with the key manager.
-
- :param ctxt: contains information of the user and the environment for
- the request (nova/context.py)
- :param key: the unencrypted secret data. Known as "payload" to the
- barbicanclient api
- :param expiration: the expiration time of the secret in ISO 8601
- format
- :param name: a friendly name for the key
- :param payload_content_type: the format/type of the secret data
- :param payload_content_encoding: the encoding of the secret data
- :param algorithm: the algorithm associated with this secret key
- :param bit_length: the bit length of this secret key
- :param mode: the algorithm mode used with this secret key
- :param from_copy: establishes whether the function is being used
- to copy a key. In case of the latter, it does not
- try to decode the key
-
- :returns: the UUID of the stored key
- :raises Exception: if key storage fails
- """
- barbican_client = self._get_barbican_client(ctxt)
-
- try:
- if key.get_algorithm():
- algorithm = key.get_algorithm()
- if payload_content_type == 'text/plain':
- payload_content_encoding = None
- encoded_key = key.get_encoded()
- elif (payload_content_type == 'application/octet-stream' and
- not from_copy):
- key_list = key.get_encoded()
- string_key = ''.join(map(lambda byte: "%02x" % byte, key_list))
- encoded_key = base64.b64encode(binascii.unhexlify(string_key))
- else:
- encoded_key = key.get_encoded()
- secret = barbican_client.secrets.create(name,
- encoded_key,
- payload_content_type,
- payload_content_encoding,
- algorithm,
- bit_length,
- mode,
- expiration)
- secret_ref = secret.store()
- return self._retrieve_secret_uuid(secret_ref)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error storing key: %s"), e)
-
- def copy_key(self, ctxt, key_id):
- """Copies (i.e., clones) a key stored by barbican.
-
- :param ctxt: contains information of the user and the environment for
- the request (nova/context.py)
- :param key_id: the UUID of the key to copy
- :return: the UUID of the key copy
- :raises Exception: if key copying fails
- """
-
- try:
- secret = self._get_secret(ctxt, key_id)
- con_type = secret.content_types['default']
- secret_data = self._get_secret_data(secret,
- payload_content_type=con_type)
- key = keymgr_key.SymmetricKey(secret.algorithm, secret_data)
- copy_uuid = self.store_key(ctxt, key, secret.expiration,
- secret.name, con_type,
- 'base64',
- secret.algorithm, secret.bit_length,
- secret.mode, True)
- return copy_uuid
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error copying key: %s"), e)
-
- def _create_secret_ref(self, key_id):
- """Creates the URL required for accessing a secret.
-
- :param key_id: the UUID of the key to copy
-
- :return: the URL of the requested secret
- """
- if not key_id:
- msg = "Key ID is None"
- raise exception.KeyManagerError(msg)
- return self._base_url + "/secrets/" + key_id
-
- def _retrieve_secret_uuid(self, secret_ref):
- """Retrieves the UUID of the secret from the secret_ref.
-
- :param secret_ref: the href of the secret
-
- :return: the UUID of the secret
- """
-
- # The secret_ref is assumed to be of a form similar to
- # http://host:9311/v1/secrets/d152fa13-2b41-42ca-a934-6c21566c0f40
- # with the UUID at the end. This command retrieves everything
- # after the last '/', which is the UUID.
- return secret_ref.rpartition('/')[2]
-
- def _get_secret_data(self,
- secret,
- payload_content_type='application/octet-stream'):
- """Retrieves the secret data given a secret and content_type.
-
- :param ctxt: contains information of the user and the environment for
- the request (nova/context.py)
- :param secret: the secret from barbican with the payload of data
- :param payload_content_type: the format/type of the secret data
-
- :returns: the secret data
- :raises Exception: if data cannot be retrieved
- """
- try:
- generated_data = secret.payload
- if payload_content_type == 'application/octet-stream':
- secret_data = base64.b64encode(generated_data)
- else:
- secret_data = generated_data
- return secret_data
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error getting secret data: %s"), e)
-
- def _get_secret(self, ctxt, key_id):
- """Returns the metadata of the secret.
-
- :param ctxt: contains information of the user and the environment for
- the request (nova/context.py)
- :param key_id: UUID of the secret
-
- :return: the secret's metadata
- :raises Exception: if there is an error retrieving the data
- """
-
- barbican_client = self._get_barbican_client(ctxt)
-
- try:
- secret_ref = self._create_secret_ref(key_id)
- return barbican_client.secrets.get(secret_ref)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error getting secret metadata: %s"), e)
-
- def get_key(self, ctxt, key_id,
- payload_content_type='application/octet-stream'):
- """Retrieves the specified key.
-
- :param ctxt: contains information of the user and the environment for
- the request (nova/context.py)
- :param key_id: the UUID of the key to retrieve
- :param payload_content_type: The format/type of the secret data
-
- :return: SymmetricKey representation of the key
- :raises Exception: if key retrieval fails
- """
- try:
- secret = self._get_secret(ctxt, key_id)
- secret_data = self._get_secret_data(secret,
- payload_content_type)
- if payload_content_type == 'application/octet-stream':
- # convert decoded string to list of unsigned ints for each byte
- key_data = array.array('B',
- base64.b64decode(secret_data)).tolist()
- else:
- key_data = secret_data
- key = keymgr_key.SymmetricKey(secret.algorithm, key_data)
- return key
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error getting key: %s"), e)
-
- def delete_key(self, ctxt, key_id):
- """Deletes the specified key.
-
- :param ctxt: contains information of the user and the environment for
- the request (nova/context.py)
- :param key_id: the UUID of the key to delete
- :raises Exception: if key deletion fails
- """
- barbican_client = self._get_barbican_client(ctxt)
-
- try:
- secret_ref = self._create_secret_ref(key_id)
- barbican_client.secrets.delete(secret_ref)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error deleting key: %s"), e)
diff --git a/nova/keymgr/conf_key_mgr.py b/nova/keymgr/conf_key_mgr.py
index 1e0a1ce14e..209f3653e0 100644
--- a/nova/keymgr/conf_key_mgr.py
+++ b/nova/keymgr/conf_key_mgr.py
@@ -31,15 +31,22 @@ encrypted with a key provided by this key manager actually share the same
encryption key so *any* volume can be decrypted once the fixed key is known.
"""
+import binascii
+
+from castellan.common.objects import symmetric_key as key
+from castellan.key_manager import key_manager
+from oslo_log import log as logging
+
import nova.conf
-from nova.i18n import _
-from nova.keymgr import single_key_mgr
+from nova import exception
+from nova.i18n import _, _LW
CONF = nova.conf.CONF
+LOG = logging.getLogger(__name__)
-class ConfKeyManager(single_key_mgr.SingleKeyManager):
+class ConfKeyManager(key_manager.KeyManager):
"""This key manager implementation supports all the methods specified by
the key manager interface. This implementation creates a single key in
response to all invocations of create_key. Side effects
@@ -47,11 +54,78 @@ class ConfKeyManager(single_key_mgr.SingleKeyManager):
as specified by the key manager interface.
"""
- def __init__(self):
- if CONF.keymgr.fixed_key is None:
+ def __init__(self, configuration):
+ LOG.warning(_LW('This key manager is insecure and is not recommended '
+ 'for production deployments'))
+ super(ConfKeyManager, self).__init__(configuration)
+
+ self.key_id = '00000000-0000-0000-0000-000000000000'
+
+ self.conf = CONF if configuration is None else configuration
+
+ if CONF.key_manager.fixed_key is None:
raise ValueError(_('keymgr.fixed_key not defined'))
- self._hex_key = CONF.keymgr.fixed_key
- super(ConfKeyManager, self).__init__()
+ self._hex_key = CONF.key_manager.fixed_key
+ super(ConfKeyManager, self).__init__(configuration)
+
+ def _get_key(self):
+ key_bytes = bytes(binascii.unhexlify(self._hex_key))
+ return key.SymmetricKey('AES', len(key_bytes) * 8, key_bytes)
+
+ def create_key(self, context, algorithm, length, **kwargs):
+ """Creates a symmetric key.
+
+ This implementation returns a UUID for the key read from the
+ configuration file. A Forbidden exception is raised if the
+ specified context is None.
+ """
+ if context is None:
+ raise exception.Forbidden()
+
+ return self.key_id
+
+ def create_key_pair(self, context, **kwargs):
+ raise NotImplementedError(
+ "ConfKeyManager does not support asymmetric keys")
+
+ def store(self, context, managed_object, **kwargs):
+ """Stores (i.e., registers) a key with the key manager."""
+ if context is None:
+ raise exception.Forbidden()
+
+ if managed_object != self._get_key():
+ raise exception.KeyManagerError(
+ reason="cannot store arbitrary keys")
+
+ return self.key_id
+
+ def get(self, context, managed_object_id):
+ """Retrieves the key identified by the specified id.
+
+ This implementation returns the key that is associated with the
+ specified UUID. A Forbidden exception is raised if the specified
+ context is None; a KeyError is raised if the UUID is invalid.
+ """
+ if context is None:
+ raise exception.Forbidden()
+
+ if managed_object_id != self.key_id:
+ raise KeyError(str(managed_object_id) + " != " + str(self.key_id))
+
+ return self._get_key()
+
+ def delete(self, context, managed_object_id):
+ """Represents deleting the key.
+
+ Because the ConfKeyManager has only one key, which is read from the
+ configuration file, the key is not actually deleted when this is
+ called.
+ """
+ if context is None:
+ raise exception.Forbidden()
+
+ if managed_object_id != self.key_id:
+ raise exception.KeyManagerError(
+ reason="cannot delete non-existent key")
- def _generate_hex_key(self, **kwargs):
- return self._hex_key
+ LOG.warning(_LW("Not deleting key %s"), managed_object_id)
diff --git a/nova/keymgr/key.py b/nova/keymgr/key.py
deleted file mode 100644
index 54080ab64c..0000000000
--- a/nova/keymgr/key.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright (c) 2013 The Johns Hopkins University/Applied Physics Laboratory
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-Base Key and SymmetricKey Classes
-
-This module defines the Key and SymmetricKey classes. The Key class is the base
-class to represent all encryption keys. The basis for this class was copied
-from Java.
-"""
-
-import abc
-
-import six
-
-
-@six.add_metaclass(abc.ABCMeta)
-class Key(object):
- """Base class to represent all keys."""
-
- @abc.abstractmethod
- def get_algorithm(self):
- """Returns the key's algorithm.
-
- Returns the key's algorithm. For example, "DSA" indicates that this key
- is a DSA key and "AES" indicates that this key is an AES key.
- """
- pass
-
- @abc.abstractmethod
- def get_format(self):
- """Returns the encoding format.
-
- Returns the key's encoding format or None if this key is not encoded.
- """
- pass
-
- @abc.abstractmethod
- def get_encoded(self):
- """Returns the key in the format specified by its encoding."""
- pass
-
-
-class SymmetricKey(Key):
- """This class represents symmetric keys."""
-
- def __init__(self, alg, key):
- """Create a new SymmetricKey object.
-
- The arguments specify the algorithm for the symmetric encryption and
- the bytes for the key.
- """
- self.alg = alg
- self.key = key
-
- def get_algorithm(self):
- """Returns the algorithm for symmetric encryption."""
- return self.alg
-
- def get_format(self):
- """This method returns 'RAW'."""
- return "RAW"
-
- def get_encoded(self):
- """Returns the key in its encoded format."""
- return self.key
-
- def __eq__(self, other):
- if isinstance(other, SymmetricKey):
- return (self.alg == other.alg and
- self.key == other.key)
- return NotImplemented
-
- def __ne__(self, other):
- result = self.__eq__(other)
- if result is NotImplemented:
- return result
- return not result
diff --git a/nova/keymgr/key_mgr.py b/nova/keymgr/key_mgr.py
deleted file mode 100644
index c020ca2474..0000000000
--- a/nova/keymgr/key_mgr.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright (c) 2013 The Johns Hopkins University/Applied Physics Laboratory
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-Key manager API
-"""
-
-import abc
-
-import six
-
-
-@six.add_metaclass(abc.ABCMeta)
-class KeyManager(object):
- """Base Key Manager Interface
-
- A Key Manager is responsible for managing encryption keys for volumes. A
- Key Manager is responsible for creating, reading, and deleting keys.
- """
-
- @abc.abstractmethod
- def create_key(self, ctxt, algorithm='AES', length=256, expiration=None,
- **kwargs):
- """Creates a key.
-
- This method creates a key and returns the key's UUID. If the specified
- context does not permit the creation of keys, then a NotAuthorized
- exception should be raised.
- """
- pass
-
- @abc.abstractmethod
- def store_key(self, ctxt, key, expiration=None, **kwargs):
- """Stores (i.e., registers) a key with the key manager.
-
- This method stores the specified key and returns its UUID that
- identifies it within the key manager. If the specified context does
- not permit the creation of keys, then a NotAuthorized exception should
- be raised.
- """
- pass
-
- @abc.abstractmethod
- def copy_key(self, ctxt, key_id, **kwargs):
- """Copies (i.e., clones) a key stored by the key manager.
-
- This method copies the specified key and returns the copy's UUID. If
- the specified context does not permit copying keys, then a
- NotAuthorized error should be raised.
-
- Implementation note: This method should behave identically to::
-
- store_key(context, get_key(context, <encryption key UUID>))
-
- although it is preferable to perform this operation within the key
- manager to avoid unnecessary handling of the key material.
- """
- pass
-
- @abc.abstractmethod
- def get_key(self, ctxt, key_id, **kwargs):
- """Retrieves the specified key.
-
- Implementations should verify that the caller has permissions to
- retrieve the key by checking the context object passed in as ctxt. If
- the user lacks permission then a NotAuthorized exception is raised.
-
- If the specified key does not exist, then a KeyError should be raised.
- Implementations should preclude users from discerning the UUIDs of
- keys that belong to other users by repeatedly calling this method.
- That is, keys that belong to other users should be considered "non-
- existent" and completely invisible.
- """
- pass
-
- @abc.abstractmethod
- def delete_key(self, ctxt, key_id, **kwargs):
- """Deletes the specified key.
-
- Implementations should verify that the caller has permission to delete
- the key by checking the context object (ctxt). A NotAuthorized
- exception should be raised if the caller lacks permission.
-
- If the specified key does not exist, then a KeyError should be raised.
- Implementations should preclude users from discerning the UUIDs of
- keys that belong to other users by repeatedly calling this method.
- That is, keys that belong to other users should be considered "non-
- existent" and completely invisible.
- """
- pass
diff --git a/nova/keymgr/mock_key_mgr.py b/nova/keymgr/mock_key_mgr.py
deleted file mode 100644
index ab947c1cb2..0000000000
--- a/nova/keymgr/mock_key_mgr.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# Copyright (c) 2013 The Johns Hopkins University/Applied Physics Laboratory
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-A mock implementation of a key manager that stores keys in a dictionary.
-
-This key manager implementation is primarily intended for testing. In
-particular, it does not store keys persistently. Lack of a centralized key
-store also makes this implementation unsuitable for use among different
-services.
-
-Note: Instantiating this class multiple times will create separate key stores.
-Keys created in one instance will not be accessible from other instances of
-this class.
-"""
-
-import array
-import codecs
-
-from oslo_log import log as logging
-from oslo_utils import uuidutils
-
-from nova import exception
-from nova.i18n import _LW
-from nova.keymgr import key
-from nova.keymgr import key_mgr
-from nova import utils
-
-
-LOG = logging.getLogger(__name__)
-decode_hex = codecs.getdecoder("hex_codec")
-
-
-class MockKeyManager(key_mgr.KeyManager):
- """This mock key manager implementation supports all the methods specified
- by the key manager interface. This implementation stores keys within a
- dictionary, and as a result, it is not acceptable for use across different
- services. Side effects (e.g., raising exceptions) for each method are
- handled as specified by the key manager interface.
-
- This key manager is not suitable for use in production deployments.
- """
-
- def __init__(self):
- LOG.warning(_LW('This key manager is not suitable for use in '
- 'production deployments'))
-
- self.keys = {}
-
- def _generate_hex_key(self, **kwargs):
- key_length = kwargs.get('key_length', 256)
- # hex digit => 4 bits
- hex_encoded = utils.generate_password(length=key_length // 4,
- symbolgroups='0123456789ABCDEF')
- return hex_encoded
-
- def _generate_key(self, **kwargs):
- _hex = self._generate_hex_key(**kwargs)
- return key.SymmetricKey('AES',
- array.array('B', decode_hex(_hex)[0]).tolist())
-
- def create_key(self, ctxt, **kwargs):
- """Creates a key.
-
- This implementation returns a UUID for the created key. A
- Forbidden exception is raised if the specified context is None.
- """
- if ctxt is None:
- raise exception.Forbidden()
-
- key = self._generate_key(**kwargs)
- return self.store_key(ctxt, key)
-
- def _generate_key_id(self):
- key_id = uuidutils.generate_uuid()
- while key_id in self.keys:
- key_id = uuidutils.generate_uuid()
-
- return key_id
-
- def store_key(self, ctxt, key, **kwargs):
- """Stores (i.e., registers) a key with the key manager."""
- if ctxt is None:
- raise exception.Forbidden()
-
- key_id = self._generate_key_id()
- self.keys[key_id] = key
-
- return key_id
-
- def copy_key(self, ctxt, key_id, **kwargs):
- if ctxt is None:
- raise exception.Forbidden()
-
- copied_key_id = self._generate_key_id()
- self.keys[copied_key_id] = self.keys[key_id]
-
- return copied_key_id
-
- def get_key(self, ctxt, key_id, **kwargs):
- """Retrieves the key identified by the specified id.
-
- This implementation returns the key that is associated with the
- specified UUID. A Forbidden exception is raised if the specified
- context is None; a KeyError is raised if the UUID is invalid.
- """
- if ctxt is None:
- raise exception.Forbidden()
-
- return self.keys[key_id]
-
- def delete_key(self, ctxt, key_id, **kwargs):
- """Deletes the key identified by the specified id.
-
- A Forbidden exception is raised if the context is None and a
- KeyError is raised if the UUID is invalid.
- """
- if ctxt is None:
- raise exception.Forbidden()
-
- del self.keys[key_id]
diff --git a/nova/keymgr/not_implemented_key_mgr.py b/nova/keymgr/not_implemented_key_mgr.py
deleted file mode 100644
index a98e657df3..0000000000
--- a/nova/keymgr/not_implemented_key_mgr.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (c) 2013 The Johns Hopkins University/Applied Physics Laboratory
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-Key manager implementation that raises NotImplementedError
-"""
-
-from nova.keymgr import key_mgr
-
-
-class NotImplementedKeyManager(key_mgr.KeyManager):
- """Key Manager Interface that raises NotImplementedError for all operations
- """
-
- def create_key(self, ctxt, algorithm='AES', length=256, expiration=None,
- **kwargs):
- raise NotImplementedError()
-
- def store_key(self, ctxt, key, expiration=None, **kwargs):
- raise NotImplementedError()
-
- def copy_key(self, ctxt, key_id, **kwargs):
- raise NotImplementedError()
-
- def get_key(self, ctxt, key_id, **kwargs):
- raise NotImplementedError()
-
- def delete_key(self, ctxt, key_id, **kwargs):
- raise NotImplementedError()
diff --git a/nova/keymgr/single_key_mgr.py b/nova/keymgr/single_key_mgr.py
deleted file mode 100644
index 6cf0e75670..0000000000
--- a/nova/keymgr/single_key_mgr.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (c) 2013 The Johns Hopkins University/Applied Physics Laboratory
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-An implementation of a key manager that returns a single key in response to
-all invocations of get_key.
-"""
-
-from oslo_log import log as logging
-
-from nova import exception
-from nova.i18n import _, _LW
-from nova.keymgr import mock_key_mgr
-
-
-LOG = logging.getLogger(__name__)
-
-
-class SingleKeyManager(mock_key_mgr.MockKeyManager):
- """This key manager implementation supports all the methods specified by
- the key manager interface. This implementation creates a single key in
- response to all invocations of create_key. Side effects
- (e.g., raising exceptions) for each method are handled as specified by
- the key manager interface.
- """
-
- def __init__(self):
- LOG.warning(_LW('This key manager is insecure and is not recommended '
- 'for production deployments'))
- super(SingleKeyManager, self).__init__()
-
- self.key_id = '00000000-0000-0000-0000-000000000000'
- self.key = self._generate_key(key_length=256)
-
- # key should exist by default
- self.keys[self.key_id] = self.key
-
- def _generate_hex_key(self, **kwargs):
- key_length = kwargs.get('key_length', 256)
- return b'0' * (key_length // 4) # hex digit => 4 bits
-
- def _generate_key_id(self):
- return self.key_id
-
- def store_key(self, ctxt, key, **kwargs):
- if key != self.key:
- raise exception.KeyManagerError(
- reason=_("cannot store arbitrary keys"))
-
- return super(SingleKeyManager, self).store_key(ctxt, key, **kwargs)
-
- def delete_key(self, ctxt, key_id, **kwargs):
- if ctxt is None:
- raise exception.Forbidden()
-
- if key_id != self.key_id:
- raise exception.KeyManagerError(
- reason=_("cannot delete non-existent key"))
-
- LOG.warning(_LW("Not deleting key %s"), key_id)