允许 QEMU 和 KVM 基于的客户机使用安全启动 (SB)¶
https://blueprints.launchpad.net/nova/+spec/allow-secure-boot-for-qemu-kvm-guests
问题描述¶
目前,Nova 的 libvirt 驱动程序仅支持通用的 UEFI 启动,但不支持 QEMU 和 KVM 客户机的安全启动(其目标是:“确保未签名的内核代码在机器上运行”)。安全启动可以保护客户机免受启动时恶意软件的侵害,并验证客户机固件执行的代码是否可信。
更确切地说,libvirt 驱动程序将 OVMF(虚拟机的 UEFI 开源实现)二进制文件的路径硬编码在变量中
[...]
DEFAULT_UEFI_LOADER_PATH = {
"x86_64": "/usr/share/OVMF/OVMF_CODE.fd",
"aarch64": "/usr/share/AAVMF/AAVMF_CODE.fd"
}
[...]
以上仅提供通用的 UEFI 启动 [1],而非安全启动。而且,以这种方式硬编码 OVMF 二进制文件路径也不够健壮。
本规范建议扩展 Nova libvirt 驱动程序中现有的 UEFI 启动支持,以同时支持安全启动。有关支持 KVM / QEMU 客户机的安全启动需要做什么,请参阅 拟议的更改 和 工作项目 部分。在本规范中,我们仅关注 x86_64 架构。
注意
Nova 的 Hyper-V 驱动程序已经支持安全启动;它是在提交 29dab99 – “Hyper-V: 添加 Hyper-V UEFI 安全启动” [2] 中添加的。
用例¶
一个不完全的列表
提议的变更¶
为了允许 KVM 和 QEMU 客户机使用安全启动,以下是计划的更改的大致集合
重用现有的 Nova 元数据属性
os_secure_boot(为 Hyper-V 支持添加),以允许用户请求安全启动支持。在初始实现中,Nova 将仅支持默认 UEFI 密钥,这将适用于大多数发行版(Debian、Ubuntu、SUSE、Fedora、CentOS 和 RHEL)——因为它们提供了一个包含默认 UEFI 密钥的变量文件(“VARS”)。 (如果您不信任默认 UEFI 密钥,那么这等同于您不信任运行计算节点的的文件系统。)如果以后需要,我们可以重用现有的镜像元数据属性
os_secure_boot_signature,该属性允许您指定启动加载程序的签名。让 Nova 使用 libvirt 的接口来自动选择固件二进制文件;这在 libvirt 6.0 中添加 [6]。为什么?
问题:目前,Nova 没有明智的方法来确定选择哪个固件二进制文件。它所看到的就是硬编码的固件二进制文件路径,这既难看又脆弱。最重要的是,很难确定该二进制文件是否支持安全启动。
解决方案:这里是 libvirt 的固件自动选择发挥作用的地方。它利用了 QEMU 和 OVMF 中完成的大量工作,并通过提供健壮的接口解决了上述问题。也就是说,libvirt 现在可以获取正确的 OVMF 二进制文件,并启用安全启动 (SB) 和系统管理模式 (SMM),并使用方便的 XML 配置
<os firmware='efi'> <loader secure='yes'/> </os>
‘Wallaby’ 版本应该满足版本要求,因为 Nova 已经宣布它将拥有这些 libvirt 和 QEMU 版本:
NEXT_MIN_LIBVIRT_VERSION = (6, 0, 0)和NEXT_MIN_QEMU_VERSION = (4, 2, 0)。这使我们能够使用 libvirt 的正式接口来自动选择固件二进制文件——这也意味着 Nova 中相对较少的“脚手架代码”。上述 libvirt 功能利用了 QEMU 的固件描述模式 [7]。
让 Nova 以编程方式查询
getDomainCapabilities()API,以检查 libvirt 是否支持相关的安全启动相关功能。引入一个_has_uefi_secure_boot_support()方法来检查 libvirt 是否可以支持该功能。可以通过检查getDomainCapabilities()API 输出中的efi和secureXML 属性来完成此操作。在初始实现中,将不会有调度程序支持来隔离不具备安全启动能力的宿主机,类似于现有的基本 UEFI 启动支持。如果宿主机 hypervisor 不支持安全启动,Nova 将报错。
可以通过引入“trait”来避免选择不支持安全启动的宿主机来完成此操作。它还支持其他用例,例如通过隔离“聚合” [8] 来过滤宿主机。
不同类型的 OVMF 构建的低级背景¶
[感谢:Laszlo Ersek,OVMF 维护者,感谢下面的讨论。在获得许可的情况下,我添加了 Laszlo 的大量逐字文本。]
可以构建到 OVMF 中的一个功能是“安全启动功能”。这与名为“安全启动”(SB) 的操作模式不同。如果固件包含该功能,则客户机可以启用或禁用操作模式。如果固件不包含该功能,则客户机无法启用操作模式。
可以构建到 OVMF 中的另一个功能称为“SMM”(安全管理模式)。这意味着一个驱动程序堆栈,它由一组在 SMM 中运行的特权驱动程序和另一个接口集,即仅格式化请求的非特权驱动程序,并解析其响应。一旦 SMM 功能构建到 OVMF 中,QEMU 平台上的 SMM 模拟就是强制的,是必需的。
安全启动功能和 SMM 功能堆栈是正交的。您可以在所有四种配置中构建 OVMF。但是,如果您希望您的客户机中的可信代码能够启用安全启动操作模式(用于自我保护),并且还希望防止客户机中的恶意代码绕过安全启动操作模式的实际安全性,那么您必须将这两个功能都构建到 OVMF 中。
注意
不同的发行版会发布不同类型的构建。例如,Fedora 会发布两种 OVMF 固件二进制文件:一种没有 SB 或 SMM,另一种同时具有 SB 和 SMM。其他发行版会发布不同的构建,并且在不同的路径下。即使他们发布了 SB+SMM OVMF 构建,固件二进制文件的路径也可能不同。
幸运的是,Nova 不需要弄清楚 OVMF 二进制文件路径。这由 (a) Linux 发行版发布固件描述符文件(描述 UEFI 固件二进制文件详细信息的小型 JSON 文件,例如固件二进制文件路径、其架构、支持的机器类型、NVRAM 模板)与 EDK2/OVMF;以及 (b) libvirt >=5.3,利用所述固件描述符文件来处理。
OVMF 二进制文件和变量存储(“VARS”)文件路径¶
每个发行版都有其自己的(略有不同的)OVMF 路径
- SUSE
软件包名称:
qemu-ovmf-x86_64;/usr/share/qemu/ovmf-x86_64-opensuse-code.bin是使用 SB 和 SMM 构建的固件二进制文件/usr/share/qemu/ovmf-x86_64-opensuse-vars.bin是与上述二进制文件匹配的变量存储模板
- Fedora
软件包名称:“edk2-ovmf”(x86_64)
/usr/share/edk2/ovmf/OVMF_CODE.fd是没有 SB 或 SMM 构建的固件二进制文件/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd是使用 SB 和 SMM 构建的固件二进制文件/usr/share/edk2/ovmf/OVMF_VARS.fd是与上述两个二进制文件匹配的变量存储模板/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd是包含默认 UEFI 密钥的变量存储模板
- RHEL-7.6 和 RHEL-8
软件包名称:“ovmf”(x86_64)
/usr/share/OVMF/OVMF_CODE.secboot.fd是使用 SB 加上 SMM 构建的固件二进制文件/usr/share/OVMF/OVMF_VARS.secboot.fd是匹配的变量存储模板
- Debian (Buster)
软件包名称:“ovmf”(x86_64)
/usr/share/OVMF/OVMF_CODE.fd是使用 SB 加上 SMM 构建的固件二进制文件。
- Ubuntu (Eoan)
软件包名称:“ovmf”(x86_64)
Eoan 版本也通过 EDK2 软件包发布了我们需要的固件描述符文件(参考下文)
这部分比较棘手,但幸运的是,libvirt 5.2 版本大大简化了 OVMF 文件名处理——通过提供自动选择固件的接口(反过来,利用 QEMU (QEMU 2.9 及以上版本提供) 的固件描述符文件)。
备选方案¶
无。
数据模型影响¶
无。
REST API 影响¶
无。
安全影响¶
有了此功能,基于 KVM 和 QEMU 的 Nova 实例就可以获得安全启动支持。从而保护客户机免受启动时恶意软件的侵害,并确保固件执行的代码只有受信任的代码。
通知影响¶
无。
其他最终用户影响¶
不会影响冷迁移或实时迁移;libvirt 已经有了必要的保障措施。
性能影响¶
无。
其他部署者影响¶
要使用此功能,以下是版本要求:QEMU >=4.1.0,libvirt >=5.3,发布 JSON 描述符文件的 OVMF/EDK2 软件包。详情请参见 依赖项 部分。
开发人员影响¶
无。
升级影响¶
无。
实现¶
负责人¶
- 主要负责人
Kashyap Chamarthy <kchamart@redhat.com>
功能联络人¶
- 功能联络人
johnthetubaguy
工作项¶
以 x86_64 架构为例。以下是启用 QEMU 和 KVM 客户机安全启动支持的工作项目
确保 Nova 在请求安全启动时配置客户机 XML 中的 SMM(系统管理模式)hypervisor 功能
<features> [...] <smm state='on'/> </features>
请注意,在使用 libvirt 的固件自动选择功能时,libvirt 在启动客户机时会自动添加 SMM 功能,因为 SMM 和 SB 是密不可分的。
确保 OVMF
loader和nvram相关的客户机 XML 片段如下(对于使用启用 SMM + SB 的 OVMF 构建的 Fedora 客户机和 Q35 机器类型)<os> <type arch='x86_64' machine='pc-q35-3.0'>hvm</type> <loader readonly='yes' secure='yes' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</loader> <nvram template='/export/vmimages/fedora_VARS.secboot.fd'>/var/lib/libvirt/qemu/nvram/fedora_VARS.secboot.fd</nvram> <boot dev='hd'/> </os>
请注意,Nova 无需担心 NVRAM 存储的文件管理,因为 libvirt 的固件自动选择功能还会检测与固件映像关联的 NVRAM 存储,将其复制到客户机的私有路径,并要求客户机使用它。
注意 1:不同发行版的 UEFI 二进制文件路径不同,但 libvirt 会为我们处理。
注意 2:使用 OVMF 的安全启动必须使用 Q35 机器类型。
为了真正获得安全启动,我们需要确保非易失性存储(“VARS”)文件(在上面的示例中,
fedora_VARS.secboot.fd)已注册默认 UEFI 密钥。有两种方法可以实现这一点。第一种,使用您的 Linux 发行版发布的“VARS”模板文件(已注册 UEFI 密钥);这是首选方法。第二种,您可以使用各种 Linux 发行版(作为其 EDK2 / OVMF 软件包的一部分)提供的
UefiShell.iso+EnrollDefaultKeys.efi工具在“VARS”文件中注册默认 UEFI 密钥,并将其放置在适当的位置。一些 Linux 发行版提供了一个工具(参考下文)来自动执行密钥注册过程。该工具的使用方法如下运行
ovmf-vars-generator工具(根据发行版调整参数)一次$> ./ovmf-vars-generator \ --ovmf-binary /usr/share/edk2/ovmf/OVMF_CODE.secboot.fd \ --uefi-shell-iso /usr/share/edk2/ovmf/UefiShell.iso \ --ovmf-template-vars /usr/share/edk2/ovmf/OVMF_VARS.fd \ --fedora-version 31 \ --kernel-path /tmp/kernel \ --kernel-url /path/to/vmlinuz \ template_VARS.fd ... INFO:root:Created and verified template_VARS.fd使用指向上述
template_VARS.fd的唯一副本重新启动客户机。此时,您将实际看到安全启动已启用。可以通过dmesg进行验证(fedora-vm)$ dmesg | grep -i secure [ 0.000000] secureboot: Secure boot enabled [ 0.000000] Kernel is locked down from EFI secure boot; see man kernel_lockdown.7
但是,如前所述,无需手动运行上述步骤。大多数常见的 Linux 发行版(SUSE、Fedora、RHEL)已经发布了一个包含默认 UEFI 密钥的“VARS”文件。Debian 和 Ubuntu 也现在发布它们 [9]。
如果您的发行版没有随附带有默认 UEFI 密钥注册的“VARS”文件,这里 [10] 提供了一个小型的 Python 工具,
ovmf-vars-generator,它可以自动执行上述三个步骤。该工具在 Fedora 中被打包为 EDK2/OVMF 的子 RPM,名为 ‘edk2-qosb’。Ubuntu 已经将其包含在其固件包中。记录使用工具
ovmf-vars-generator生成上述“VARS”文件的方法。该工具已经作为主要 ‘edk2’ / OVMF 的子包(名为:‘edk2-qosb’)在不同的发行版中发布。Ubuntu 和 Debian 也在努力发布此脚本。引入一个“特征”(需要更新到 ‘os-traits’ 库)用于安全启动,以便镜像元数据可以请求该特征。如前所述,允许 Nova 仅选择那些支持安全启动的主机。这需要安装(或在必要时升级)运行
placement服务的宿主机上的 ‘os-traits’。然后重新启动placement服务——这将把特征同步到 Placement 数据库。
依赖项¶
对于 SMM(系统管理模式)功能,仅支持 QEMU Q35 机器类型。
QEMU >=2.4 以获得安全启动支持。
QEMU >=4.1.0(发布于 2019 年 8 月)以获得符合 QEMU
firmware.json规范的固件描述符文件。这里 [11] 提供了一些所述“固件描述符文件”的示例。libvirt >=5.3(发布于 2019 年 5 月)用于固件自动选择功能以及通过
getDomainCapabilities()API 查询efi[12] 固件可用性的能力。Ubuntu (Eoan) 发行版中的 OVMF
0~20190606.20d2e5a1-2ubuntu1,以提供 JSON 描述符文件 [13]。
测试¶
如果满足上述最小的 libvirt 和 QEMU 版本要求,则应该可以在上游 gating 环境中测试此功能。Nova 实例应该能够启动使用 OVMF 的安全启动 KVM 客户机,并在 dmesg 中验证安全启动是否实际生效。
文档影响¶
记录如何使用 OVMF 为 QEMU 和 KVM 客户机启动具有安全启动的 x86_64 Nova 实例。并更新 Glance 的“有用的镜像属性”文档 [14]。
参考资料¶
历史¶
发布名称 |
描述 |
|---|---|
Train |
引入 |
Ussuri |
重新提出 |
Wallaby |
重新提出 |