Adds dmcrypt utility module

Patch adds a module for manipulating dmcrypt devices.

Implements: blueprint encrypt-ephemeral-storage
Change-Id: I308b9f26c382b332c02f13aa1d5f0a830e9ef277
This commit is contained in:
Dan Genin 2014-01-02 09:44:45 -05:00
parent 50c9055c8e
commit b15b197b6f
3 changed files with 139 additions and 1 deletions

View File

@ -202,9 +202,12 @@ systool: CommandFilter, systool, root
# nova/virt/libvirt/volume.py:
sginfo: CommandFilter, sginfo, root
sg_scan: CommandFilter, sg_scan, root
cryptsetup: CommandFilter, cryptsetup, root
ln: RegExpFilter, ln, root, ln, --symbolic, --force, /dev/mapper/ip-.*-iscsi-iqn.2010-10.org.openstack:volume-.*, /dev/disk/by-path/ip-.*-iscsi-iqn.2010-10.org.openstack:volume-.*
# nova/volume/encryptors.py:
# nova/virt/libvirt/dmcrypt.py:
cryptsetup: CommandFilter, cryptsetup, root
# nova/virt/xenapi/vm_utils.py:
xenstore-read: CommandFilter, xenstore-read, root

View File

@ -0,0 +1,72 @@
# Copyright (c) 2014 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.
import os
from nova import test
from nova import utils
from nova.virt.libvirt import dmcrypt
class LibvirtDmcryptTestCase(test.TestCase):
def setUp(self):
super(LibvirtDmcryptTestCase, self).setUp()
self.CIPHER = 'cipher'
self.KEY_SIZE = 256
self.NAME = 'disk'
self.TARGET = dmcrypt.volume_name(self.NAME)
self.PATH = '/dev/nova-lvm/instance_disk'
self.KEY = range(0, self.KEY_SIZE)
self.KEY_STR = ''.join(["%02x" % x for x in range(0, self.KEY_SIZE)])
self.executes = []
self.kwargs = {}
def fake_execute(*cmd, **kwargs):
self.executes.append(cmd)
self.kwargs = kwargs
return None, None
def fake_listdir(path):
return [self.TARGET, '/dev/mapper/disk']
self.stubs.Set(utils, 'execute', fake_execute)
self.stubs.Set(os, 'listdir', fake_listdir)
def test_create_volume(self):
expected_commands = [('cryptsetup',
'create',
self.TARGET,
self.PATH,
'--cipher=' + self.CIPHER,
'--key-size=' + str(self.KEY_SIZE),
'--key-file=-')]
dmcrypt.create_volume(self.TARGET, self.PATH, self.CIPHER,
self.KEY_SIZE, self.KEY)
self.assertEqual(expected_commands, self.executes)
self.assertEqual(self.KEY_STR, self.kwargs['process_input'])
def test_delete_volume(self):
expected_commands = [('cryptsetup', 'remove', self.TARGET)]
dmcrypt.delete_volume(self.TARGET)
self.assertEqual(expected_commands, self.executes)
def test_list_volumes(self):
encrypted_volumes = dmcrypt.list_volumes()
self.assertEqual([self.TARGET], encrypted_volumes)

View File

@ -0,0 +1,63 @@
# Copyright (c) 2014 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.
import os
from nova.virt.libvirt import utils
_dmcrypt_suffix = '-dmcrypt'
def volume_name(base):
"""Returns the suffixed dmcrypt volume name.
This is to avoid collisions with similarly named device mapper names for
LVM volumes
"""
return base + _dmcrypt_suffix
def create_volume(target, device, cipher, key_size, key):
"""Sets up a dmcrypt mapping
:param target: device mapper logical device name
:param device: underlying block device
:param cipher: encryption cipher string digestible by cryptsetup
:param cipher: encryption key size
:param key: encryption key as an array of unsigned bytes
"""
cmd = ('cryptsetup',
'create',
target,
device,
'--cipher=' + cipher,
'--key-size=' + str(key_size),
'--key-file=-')
key = ''.join(map(lambda byte: "%02x" % byte, key))
utils.execute(*cmd, process_input=key, run_as_root=True)
def delete_volume(target):
"""Deletes a dmcrypt mapping
:param target: name of the mapped logical device
"""
utils.execute('cryptsetup', 'remove', target, run_as_root=True)
def list_volumes():
"""Function enumerates encrypted volumes."""
return [dmdev for dmdev in os.listdir('/dev/mapper')
if dmdev.endswith('-dmcrypt')]