From c589b76e13f54f8c0d753b1d2c4d4c2ef3399359 Mon Sep 17 00:00:00 2001 From: Kaitlin Farr Date: Fri, 10 Mar 2017 18:09:49 -0500 Subject: [PATCH] Parse algorithm from cipher for ephemeral disk encryption Nova's keymgr implementation used to have default values for the algorithm and bit length. Castellan does not have default values, and when Castellan replaced keymgr in Ib563b0ea4b8b4bc1833bf52bf49a68546c384996, the parameters to the create_key method were not updated. This change parses the algorithm from the cipher value and passes it to Castellan's key manager interface. Conflicts: nova/conf/ephemeral_storage.py NOTE(mriedem): The conflicts are due to not having Ic8ea9b0852d5b6f5d8a468fe0a03d21e220a8913 in newton, which was a refactor/cleanup change in ocata. It's just preserved here for readability. Closes-Bug: #1651887 Change-Id: Ib90bc7571aef59325be0efe123fcf12e86252b85 (cherry picked from commit 1d3acad111c5106592b0921628480fcf41e0fb4c) (cherry picked from commit fcc931f4017ab4bb830ff645431edaa8a18bf880) --- nova/compute/api.py | 7 ++++++ nova/conf/ephemeral_storage.py | 7 +++--- nova/tests/unit/compute/test_compute.py | 33 ++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 93283711b372..ea842e4c2eea 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1398,8 +1398,15 @@ class API(base.Base): instance.old_flavor = None instance.new_flavor = None if CONF.ephemeral_storage_encryption.enabled: + # NOTE(kfarr): dm-crypt expects the cipher in a + # hyphenated format: cipher-chainmode-ivmode + # (ex: aes-xts-plain64). The algorithm needs + # to be parsed out to pass to the key manager (ex: aes). + cipher = CONF.ephemeral_storage_encryption.cipher + algorithm = cipher.split('-')[0] if cipher else None instance.ephemeral_key_uuid = self.key_manager.create_key( context, + algorithm=algorithm, length=CONF.ephemeral_storage_encryption.key_size) else: instance.ephemeral_key_uuid = None diff --git a/nova/conf/ephemeral_storage.py b/nova/conf/ephemeral_storage.py index 8747cfc27287..4f21a12e180c 100644 --- a/nova/conf/ephemeral_storage.py +++ b/nova/conf/ephemeral_storage.py @@ -39,9 +39,10 @@ Enables/disables LVM ephemeral storage encryption. help=""" Cipher-mode string to be used -The cipher and mode to be used to encrypt ephemeral -storage. The set of cipher-mode combinations available -depends on kernel support. +The cipher and mode to be used to encrypt ephemeral storage. The set of +cipher-mode combinations available depends on kernel support. According +to the dm-crypt documentation, the cipher is expected to be in the format: +"--". Possible values: diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index bc1bb0523fbc..ac482893d1ad 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -19,13 +19,14 @@ import base64 import datetime +from itertools import chain import operator import sys import time import traceback import uuid -from itertools import chain +from castellan import key_manager import mock from neutronclient.common import exceptions as neutron_exceptions from oslo_log import log as logging @@ -7890,6 +7891,36 @@ class ComputeAPITestCase(BaseTestCase): instance['display_name']) self.assertIsNotNone(instance.get('uuid')) self.assertEqual([], instance.security_groups.objects) + self.assertIsNone(instance.ephemeral_key_uuid) + + def test_populate_instance_for_create_encrypted(self, num_instances=1): + CONF.set_override('enabled', True, + group='ephemeral_storage_encryption', + enforce_type=True) + CONF.set_override('api_class', + 'castellan.tests.unit.key_manager.mock_key_manager.' + 'MockKeyManager', + group='key_manager', + enforce_type=True) + base_options = {'image_ref': self.fake_image['id'], + 'system_metadata': {'fake': 'value'}, + 'display_name': 'foo', + 'uuid': uuids.instance} + instance = objects.Instance() + instance.update(base_options) + inst_type = flavors.get_flavor_by_name("m1.tiny") + self.compute_api.key_manager = key_manager.API() + index = 1 + instance = self.compute_api._populate_instance_for_create( + self.context, + instance, + self.fake_image, + index, + security_groups=objects.SecurityGroupList(), + instance_type=inst_type, + num_instances=num_instances, + shutdown_terminate=False) + self.assertIsNotNone(instance.ephemeral_key_uuid) def test_default_hostname_generator(self): fake_uuids = [str(uuid.uuid4()) for x in range(4)]