Merge "libvirt: Wire up 'os_secure_boot' property"

This commit is contained in:
Zuul 2021-03-16 11:47:12 +00:00 committed by Gerrit Code Review
commit bf4d4c16fd
5 changed files with 166 additions and 6 deletions

View File

@ -23,8 +23,8 @@ EXTRA_SPEC_VALIDATORS = [
base.ExtraSpecValidator(
name='os:secure_boot',
description=(
'Determine whether secure boot is enabled or not. Currently only '
'supported by the HyperV driver.'
'Determine whether secure boot is enabled or not. Only supported '
'by the libvirt and HyperV drivers.'
),
value={
'type': str,

View File

@ -1891,6 +1891,10 @@ class UEFINotSupported(Invalid):
msg_fmt = _("UEFI is not supported")
class SecureBootNotSupported(Invalid):
msg_fmt = _("Secure Boot is not supported by host")
class TriggerCrashDumpNotSupported(Invalid):
msg_fmt = _("Triggering crash dump is not supported")

View File

@ -1993,6 +1993,36 @@ class FakeLibvirtFixture(fixtures.Fixture):
'features': ['acpi-s3', 'amd-sev', 'verbose-dynamic'],
'tags': [],
},
{
'description': 'UEFI firmware for x86_64, with SB+SMM',
'interface-types': ['uefi'],
'mapping': {
'device': 'flash',
'executable': {
'filename': '/usr/share/OVMF/OVMF_CODE.secboot.fd',
'format': 'raw',
},
'nvram-template': {
'filename': '/usr/share/OVMF/OVMF_VARS.secboot.fd',
'format': 'raw',
},
},
'targets': [
{
'architecture': 'x86_64',
'machines': ['pc-q35-*'],
},
],
'features': [
'acpi-s3',
'amd-sev',
'enrolled-keys',
'requires-smm',
'secure-boot',
'verbose-dynamic',
],
'tags': [],
},
{
'description': 'UEFI firmware for aarch64',
'interface-types': ['uefi'],
@ -2015,7 +2045,7 @@ class FakeLibvirtFixture(fixtures.Fixture):
],
'features': ['verbose-static'],
"tags": [],
}
},
]
self.useFixture(
fixtures.MockPatch(

View File

@ -5008,10 +5008,86 @@ class LibvirtConnTestCase(test.NoDBTestCase,
CONF.libvirt.virt_type, instance_ref, image_meta)
cfg = drvr._get_guest_config(
instance_ref, [], image_meta, disk_info)
# these values are derived from the FakeLibvirtFixture
# these paths are derived from the FakeLibvirtFixture
self.assertEqual('/usr/share/OVMF/OVMF_CODE.fd', cfg.os_loader)
self.assertEqual('/usr/share/OVMF/OVMF_VARS.fd', cfg.os_nvram_template)
@ddt.data(True, False)
def test_get_guest_config_with_secure_boot_required(
self, host_has_support,
):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
drvr._host._supports_uefi = True
drvr._host._supports_secure_boot = host_has_support
image_meta = objects.ImageMeta.from_dict({
'disk_format': 'raw',
# secure boot requires UEFI
'properties': {
'hw_firmware_type': 'uefi',
'hw_machine_type': 'q35',
'os_secure_boot': 'required',
},
})
instance_ref = objects.Instance(**self.test_instance)
disk_info = blockinfo.get_disk_info(
CONF.libvirt.virt_type, instance_ref, image_meta)
if host_has_support:
# if the host supports it, we should get the feature
cfg = drvr._get_guest_config(
instance_ref, [], image_meta, disk_info)
# these paths are derived from the FakeLibvirtFixture
self.assertEqual(
'/usr/share/OVMF/OVMF_CODE.secboot.fd', cfg.os_loader)
self.assertEqual(
'/usr/share/OVMF/OVMF_VARS.secboot.fd', cfg.os_nvram_template)
self.assertTrue(cfg.os_loader_secure)
else:
# if not, we should see an exception
self.assertRaises(
exception.SecureBootNotSupported,
drvr._get_guest_config,
instance_ref, [], image_meta, disk_info)
@ddt.data(True, False)
def test_get_guest_config_with_secure_boot_optional(
self, host_has_support,
):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
drvr._host._supports_uefi = True
drvr._host._supports_secure_boot = host_has_support
image_meta = objects.ImageMeta.from_dict({
'disk_format': 'raw',
# secure boot requires UEFI
'properties': {
'hw_firmware_type': 'uefi',
'hw_machine_type': 'q35',
'os_secure_boot': 'optional',
},
})
instance_ref = objects.Instance(**self.test_instance)
disk_info = blockinfo.get_disk_info(
CONF.libvirt.virt_type, instance_ref, image_meta)
cfg = drvr._get_guest_config(
instance_ref, [], image_meta, disk_info)
if host_has_support:
# if the host supports it we should get the feature
self.assertEqual(
'/usr/share/OVMF/OVMF_CODE.secboot.fd', cfg.os_loader)
self.assertEqual(
'/usr/share/OVMF/OVMF_VARS.secboot.fd', cfg.os_nvram_template)
self.assertTrue(cfg.os_loader_secure)
else:
# if not, silently ignore
self.assertEqual(
'/usr/share/OVMF/OVMF_CODE.fd', cfg.os_loader)
self.assertEqual(
'/usr/share/OVMF/OVMF_VARS.fd', cfg.os_nvram_template)
self.assertFalse(cfg.os_loader_secure)
def test_check_uefi_support_aarch64(self):
self.mock_uname.return_value = fakelibvirt.os_uname(
'Linux', '', '5.4.0-0-generic', '', fields.Architecture.AARCH64)

View File

@ -5822,6 +5822,29 @@ class LibvirtDriver(driver.ComputeDriver):
caps.host.cpu.arch == fields.Architecture.AARCH64
)
def _check_secure_boot_support(
self,
arch: str,
machine_type: str,
firmware_type: str,
) -> bool:
if not self._host.supports_secure_boot:
# secure boot requires host configuration
return False
if firmware_type != fields.FirmwareType.UEFI:
# secure boot is only supported with UEFI
return False
if (
arch == fields.Architecture.X86_64 and
'q35' not in machine_type
):
# secure boot on x86_64 requires the Q35 machine type
return False
return True
def _get_supported_perf_events(self):
if not len(CONF.libvirt.enabled_perf_events):
return []
@ -5887,8 +5910,35 @@ class LibvirtDriver(driver.ComputeDriver):
# architecture that we have no default machine type for
raise exception.UEFINotSupported()
loader, nvram_template = self._host.get_loader(
arch, mach_type, has_secure_boot=False)
os_secure_boot = hardware.get_secure_boot_constraint(
flavor, image_meta)
if os_secure_boot == 'required':
# hard fail if we don't support secure boot and it's
# required
if not self._check_secure_boot_support(
arch, mach_type, hw_firmware_type,
):
raise exception.SecureBootNotSupported()
guest.os_loader_secure = True
elif os_secure_boot == 'optional':
# only enable it if the host is configured appropriately
guest.os_loader_secure = self._check_secure_boot_support(
arch, mach_type, hw_firmware_type,
)
else:
guest.os_loader_secure = False
try:
loader, nvram_template = self._host.get_loader(
arch, mach_type,
has_secure_boot=guest.os_loader_secure)
except exception.UEFINotSupported as exc:
if guest.os_loader_secure:
# we raise a specific exception if we requested secure
# boot and couldn't get that
raise exception.SecureBootNotSupported() from exc
raise
guest.os_loader = loader
guest.os_loader_type = 'pflash'