summaryrefslogtreecommitdiff
path: root/nova/virt
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2023-01-14 01:55:41 +0000
committerGerrit Code Review <review@openstack.org>2023-01-14 01:55:41 +0000
commit9e2ca01988b8889738eba3c9af336ad82d214e1b (patch)
treeec4eaef779b146f95ae301fb30d297049a60d44e /nova/virt
parent8e3ffb851b3faa8144894a3299f84acd8eed38dc (diff)
parent2eeefabde4f5f46e95849efe910027455ba70186 (diff)
downloadnova-9e2ca01988b8889738eba3c9af336ad82d214e1b.tar.gz
Merge "libvirt: Add encryption support to qemu-img create command"
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/libvirt/utils.py69
1 files changed, 60 insertions, 9 deletions
diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py
index 0675e4ac14..adb2ec45a1 100644
--- a/nova/virt/libvirt/utils.py
+++ b/nova/virt/libvirt/utils.py
@@ -22,6 +22,7 @@ import grp
import os
import pwd
import re
+import tempfile
import typing as ty
import uuid
@@ -114,6 +115,7 @@ def create_image(
disk_format: str,
disk_size: ty.Optional[ty.Union[str, int]],
backing_file: ty.Optional[str] = None,
+ encryption: ty.Optional[ty.Dict[str, ty.Any]] = None
) -> None:
"""Disk image creation with qemu-img
:param path: Desired location of the disk image
@@ -125,15 +127,16 @@ def create_image(
If no suffix is given, it will be interpreted as bytes.
Can be None in the case of a COW image.
:param backing_file: (Optional) Backing file to use.
+ :param encryption: (Optional) Dict detailing various encryption attributes
+ such as the format and passphrase.
"""
- base_cmd = [
+ cmd = [
'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'create', '-f', disk_format
]
- cow_opts = []
if backing_file:
base_details = images.qemu_img_info(backing_file)
- cow_opts += [
+ cow_opts = [
f'backing_file={backing_file}',
f'backing_fmt={base_details.file_format}'
]
@@ -147,12 +150,60 @@ def create_image(
# Format as a comma separated list
csv_opts = ",".join(cow_opts)
- cow_opts = ['-o', csv_opts]
-
- cmd = base_cmd + cow_opts + [path]
- if disk_size is not None:
- cmd += [str(disk_size)]
- processutils.execute(*cmd)
+ cmd += ['-o', csv_opts]
+
+ # Disk size can be None in the case of a COW image
+ disk_size_arg = [str(disk_size)] if disk_size is not None else []
+
+ if encryption:
+ with tempfile.NamedTemporaryFile(mode='tr+', encoding='utf-8') as f:
+ # Write out the passphrase secret to a temp file
+ f.write(encryption.get('secret'))
+
+ # Ensure the secret is written to disk, we can't .close() here as
+ # that removes the file when using NamedTemporaryFile
+ f.flush()
+
+ # The basic options include the secret and encryption format
+ encryption_opts = [
+ '--object', f"secret,id=sec,file={f.name}",
+ '-o', 'encrypt.key-secret=sec',
+ '-o', f"encrypt.format={encryption.get('format')}",
+ ]
+ # Supported luks options:
+ # cipher-alg=<str> - Name of cipher algorithm and key length
+ # cipher-mode=<str> - Name of encryption cipher mode
+ # hash-alg=<str> - Name of hash algorithm to use for PBKDF
+ # iter-time=<num> - Time to spend in PBKDF in milliseconds
+ # ivgen-alg=<str> - Name of IV generator algorithm
+ # ivgen-hash-alg=<str> - Name of IV generator hash algorithm
+ #
+ # NOTE(melwitt): Sensible defaults (that match the qemu defaults)
+ # are hardcoded at this time for simplicity and consistency when
+ # instances are migrated. Configuration of luks options could be
+ # added in a future release.
+ encryption_options = {
+ 'cipher-alg': 'aes-256',
+ 'cipher-mode': 'xts',
+ 'hash-alg': 'sha256',
+ 'iter-time': 2000,
+ 'ivgen-alg': 'plain64',
+ 'ivgen-hash-alg': 'sha256',
+ }
+
+ for option, value in encryption_options.items():
+ encryption_opts += [
+ '-o',
+ f'encrypt.{option}={value}',
+ ]
+
+ # We need to execute the command while the NamedTemporaryFile still
+ # exists
+ cmd += encryption_opts + [path] + disk_size_arg
+ processutils.execute(*cmd)
+ else:
+ cmd += [path] + disk_size_arg
+ processutils.execute(*cmd)
def create_ploop_image(