强化虚拟化层¶
在本章的开头,我们将讨论实例对物理和虚拟硬件的使用、相关的安全风险,以及一些减轻这些风险的建议。然后,我们将讨论如何使用 AMD-Secure Encrypted Virtualization 技术来加密支持该技术的 AMD 机器上的虚拟机内存。本章最后将讨论 sVirt,一个将 SELinux 强制访问控制与虚拟化组件集成的开源项目。
物理硬件 (PCI 直通)¶
许多 hypervisor 提供一种称为 PCI 直通的功能。这允许实例直接访问节点上的硬件。例如,这可用于允许实例访问视频卡或 GPU,从而提供用于高性能计算的计算统一设备架构 (CUDA)。此功能具有两种类型的安全风险:直接内存访问和硬件感染。
直接内存访问 (DMA) 是一项功能,它允许某些硬件设备访问主机计算机中的任意物理内存地址。通常,视频卡具有此功能。但是,不应向实例授予任意物理内存访问权限,因为这将使其完全了解主机系统和在同一节点上运行的其他实例。硬件供应商使用输入/输出内存管理单元 (IOMMU) 来管理这些情况下的 DMA 访问。我们建议云架构师确保配置 hypervisor 以利用此硬件功能。
注意
IOMMU 功能由 Intel 营销为 VT-d,由 AMD 营销为 AMD-Vi。
当实例对固件或其他设备的某个部分进行恶意修改时,会发生硬件感染。由于该设备被其他实例或主机操作系统使用,恶意代码可以传播到这些系统。最终结果是,一个实例可以在其安全域之外运行代码。这是一个严重的漏洞,因为重置物理硬件的状态比重置虚拟硬件的状态更困难,并且可能导致额外的暴露,例如访问管理网络。
解决硬件感染问题的方案取决于领域。策略是确定实例如何修改硬件状态,然后确定实例完成使用硬件后如何重置任何修改。例如,一种选择是在使用后重新刷新固件。需要在硬件寿命和安全性之间取得平衡,因为某些固件在写入次数过多后会失败。TPM 技术,在 安全引导 中描述,是检测未经授权的固件更改的解决方案。无论选择哪种策略,重要的是要了解与这种硬件共享相关的风险,以便可以针对给定的部署场景正确地减轻这些风险。
由于 PCI 直通相关的风险和复杂性,默认情况下应禁用它。如果为了特定需要而启用,则需要制定适当的流程来确保在重新发布硬件之前对其进行清理。
虚拟硬件 (QEMU)¶
当运行虚拟机时,虚拟硬件是一个软件层,它为虚拟机提供硬件接口。实例使用此功能来提供网络、存储、视频和其他可能需要的设备。考虑到这一点,您的环境中的大多数实例将专门使用虚拟硬件,少数实例需要直接硬件访问。主要的开源 hypervisor 使用 QEMU 用于此功能。虽然 QEMU 满足了虚拟化平台的重要需求,但事实证明它是一个非常具有挑战性的软件项目,难以编写和维护。QEMU 中的许多功能都是使用低级代码实现的,大多数开发人员难以理解。QEMU 虚拟化的硬件包括许多遗留设备,这些设备具有自己的一系列怪癖。综上所述,QEMU 已成为许多安全问题的来源,包括 hypervisor 突破攻击。
采取积极措施来强化 QEMU 非常重要。我们建议采取三个具体步骤
最小化代码库。
使用编译器强化。
使用强制访问控制,例如 sVirt、SELinux 或 AppArmor。
确保您的 iptables 具有默认策略,以过滤网络流量,并考虑检查现有的规则集以了解每个规则并确定是否需要扩展策略。
最小化 QEMU 代码库¶
我们建议通过从系统中删除未使用的组件来最小化 QEMU 代码库。QEMU 提供对许多不同虚拟硬件设备的支持,但是,给定实例只需要少量设备。最常见的硬件设备是 virtio 设备。一些遗留实例需要访问特定的硬件,可以使用 glance 元数据指定。
$ glance image-update \
--property hw_disk_bus=ide \
--property hw_cdrom_bus=ide \
--property hw_vif_model=e1000 \
f16-x86_64-openstack-sda
云架构师应决定向云用户提供哪些设备。不需要的任何设备都应从 QEMU 中删除。此步骤需要在修改传递给 QEMU 配置脚本的选项后重新编译 QEMU。要获取完整的最新选项列表,只需从 QEMU 源代码目录中运行 ./configure --help。确定您的部署需要什么,并禁用其余选项。
编译器强化¶
使用编译器强化选项来强化 QEMU。现代编译器提供了各种编译时选项来提高结果二进制文件的安全性。这些功能包括重定位只读 (RELRO)、堆栈金丝雀、永不执行 (NX)、位置无关可执行文件 (PIE) 和地址空间布局随机化 (ASLR)。
许多现代 Linux 发行版已经使用编译器强化选项构建 QEMU,我们建议在继续操作之前验证您现有的可执行文件。可以帮助您进行此验证的工具称为 checksec.sh
- 重定位只读 (RELRO)
强化可执行文件的的数据段。gcc 支持完全 RELRO 和部分 RELRO 模式。对于 QEMU,完全 RELRO 是您的最佳选择。这将使全局偏移表只读,并将各种内部数据段放在结果可执行文件中的程序数据段之前。
- 堆栈金丝雀
将值放在堆栈上并验证其存在,以帮助防止缓冲区溢出攻击。
- 永不执行 (NX)
也称为数据执行保护 (DEP),确保可执行文件的的数据段不能被执行。
- 位置无关可执行文件 (PIE)
生成位置无关的可执行文件,这对于 ASLR 是必需的。
- 地址空间布局随机化 (ASLR)
这确保了代码和数据区域的放置将被随机化。由内核启用(所有现代 Linux 内核都支持 ASLR),当可执行文件使用 PIE 构建时。
以下编译器选项建议在编译 QEMU 时使用 GCC
CFLAGS="-arch x86_64 -fstack-protector-all -Wstack-protector \
--param ssp-buffer-size=4 -pie -fPIE -ftrapv -D_FORTIFY_SOURCE=2 -O2 \
-Wl,-z,relro,-z,now"
我们建议在编译后测试您的 QEMU 可执行文件,以确保编译器强化正常工作。
大多数云部署不会手动构建软件,例如 QEMU。最好使用打包来确保该过程可重复,并确保最终结果可以轻松地部署到整个云中。以下参考资料提供了有关将编译器强化选项应用于现有软件包的更多详细信息。
- DEB 包
- RPM 包
安全加密虚拟化¶
安全加密虚拟化 (SEV) 是 AMD 的一项技术,它能够使用与虚拟机唯一的密钥加密虚拟机的内存。SEV 在 Train 版本中作为技术预览版提供,适用于某些 AMD 机器上的 KVM 客户,目的是评估该技术。
KVM hypervisor 部分的 nova 配置指南 包含配置机器和 hypervisor 所需的信息,并列出了 SEV 的几个限制。
SEV 为正在运行的虚拟机使用的内存中的数据提供保护。但是,虽然 SEV 与 OpenStack 的集成第一阶段启用了虚拟机的加密内存,但重要的是,它没有提供 SEV 固件中可用的 LAUNCH_MEASURE 或 LAUNCH_SECRET 功能。这意味着用于受 SEV 保护的虚拟机的的数据可能受到控制 hypervisor 的恶意攻击者的攻击。例如,hypervisor 机器上的恶意管理员可以为租户提供带有后门和间谍软件的虚拟机镜像,这些后门和间谍软件能够窃取机密,或者替换 VNC 服务器进程以窥探发送到或从虚拟机控制台的数据,包括解锁完整磁盘加密解决方案的密码。
为了降低恶意管理员获得对数据未经授权访问的风险,应将以下安全措施与 SEV 的使用结合起来
应使用完整的磁盘加密解决方案。
应在虚拟机上使用启动加载程序密码。
此外,应使用标准的安全性最佳实践来保护虚拟机,包括以下内容
虚拟机应得到良好的维护,包括定期安全扫描和修补,以确保虚拟机的持续强大的安全性。
对虚拟机的连接应使用加密和身份验证协议,例如 HTTPS 和 SSH。
应考虑并使用其他安全工具和流程来保护虚拟机,具体取决于数据的敏感性级别。
强制访问控制¶
编译器强化使攻击 QEMU 进程更加困难。但是,如果攻击者成功了,您希望限制攻击的影响。强制访问控制可以做到这一点,方法是将 QEMU 进程的权限限制为仅需要的内容。这可以通过使用 sVirt、SELinux 或 AppArmor 来完成。我们将在下面的部分中提供有关 sVirt 和实例隔离的更多详细信息 sVirt:SELinux 和虚拟化。
许多 OpenStack 服务的特定 SELinux 策略可用。CentOS 用户可以通过 安装 selinux-policy 源代码包 来查看这些策略。最新的策略出现在 Fedora 的 selinux-policy 存储库中。 rawhide-contrib 分支具有以 .te 结尾的文件,例如 cinder.te,这些文件可以用于在运行 SELinux 的系统上。
AppArmor 配置文件对于 OpenStack 服务目前不存在,但是 OpenStack-Ansible 项目通过 将 AppArmor 配置文件应用于运行 OpenStack 服务的每个容器 来处理此问题。
sVirt:SELinux 和虚拟化¶
凭借独特的内核级架构和国家安全局 (NSA) 开发的安全机制,KVM 为多租户提供了基础隔离技术。Secure Virtualization (sVirt) 技术起源于 2002 年,是对现代虚拟化应用 SELinux 的应用。SELinux 旨在应用基于标签的分离控制,已被扩展为提供虚拟机进程、设备、数据文件和代表它们行事的系统进程之间的隔离。
OpenStack 的 sVirt 实现旨在保护 hypervisor 主机和虚拟机免受两个主要威胁向量
- Hypervisor 威胁
在虚拟机内运行的受损应用程序攻击 hypervisor 以访问底层资源。例如,当虚拟机能够访问 hypervisor 操作系统、物理设备或其他应用程序时。此威胁向量代表着相当大的风险,因为 hypervisor 上的妥协可能会感染物理硬件以及暴露其他虚拟机和网络段。
- 虚拟机 (多租户) 威胁
在虚拟机内运行的受损应用程序攻击 hypervisor 以访问或控制另一个虚拟机及其资源。这是虚拟化特有的威胁向量,代表着相当大的风险,因为由于单个应用程序中的漏洞,可能会损害大量的虚拟机镜像文件。
每个基于 KVM 的虚拟机都是一个进程,该进程由 SELinux 标记,从而有效地在每个虚拟机周围建立安全边界。Linux 内核监视并强制执行此安全边界,限制虚拟机对其边界之外的资源的访问,例如主机机器数据文件或其他虚拟机。
sVirt 隔离与虚拟机内运行的客户操作系统无关。可以使用 Linux 或 Windows 虚拟机。此外,许多 Linux 发行版在其操作系统内提供 SELinux,允许虚拟机保护内部虚拟资源免受威胁。
标签和类别¶
基于 KVM 的虚拟机实例被标记为自己的 SELinux 数据类型,称为 svirt_image_t。内核级保护防止未经授权的系统进程(例如恶意软件)操纵磁盘上的虚拟机镜像文件。当虚拟机关闭电源时,镜像存储为 svirt_image_t,如下所示
system_u:object_r:svirt_image_t:SystemLow image1
system_u:object_r:svirt_image_t:SystemLow image2
system_u:object_r:svirt_image_t:SystemLow image3
system_u:object_r:svirt_image_t:SystemLow image4
svirt_image_t 标签唯一标识磁盘上的镜像文件,允许 SELinux 策略限制访问。当基于 KVM 的计算镜像上电时,sVirt 会将随机数字标识符附加到镜像。sVirt 能够为每个 hypervisor 节点分配多达 524,288 个虚拟机的数字标识符,但是大多数 OpenStack 部署不太可能遇到此限制。
此示例显示了 sVirt 类别标识符
system_u:object_r:svirt_image_t:s0:c87,c520 image1
system_u:object_r:svirt_image_t:s0:419,c172 image2
SELinux 用户和角色¶
SELinux 管理用户角色。可以通过 -Z 标志或使用 semanage 命令查看这些角色。在 hypervisor 上,只有管理员才能访问系统,并且应该在管理用户和系统上的任何其他用户周围具有适当的上下文。有关更多信息,请参阅 SELinux 用户文档。
布尔值¶
为了减轻管理 SELinux 的管理负担,许多企业 Linux 平台利用 SELinux 布尔值来快速更改 sVirt 的安全态势。
基于 Red Hat Enterprise Linux 的 KVM 部署使用以下 sVirt 布尔值
sVirt SELinux 布尔值 |
描述 |
|---|---|
virt_use_common |
允许 virt 使用串行或并行通信端口。 |
virt_use_fusefs |
允许 virt 读取 FUSE 挂载的文件。 |
virt_use_nfs |
允许 virt 管理 NFS 挂载的文件。 |
virt_use_samba |
允许 virt 管理 CIFS 挂载的文件。 |
virt_use_sanlock |
允许受限的虚拟机与 sanlock 交互。 |
virt_use_sysfs |
允许 virt 管理设备配置 (PCI)。 |
virt_use_usb |
允许 virt 使用 USB 设备。 |
virt_use_xserver |
允许虚拟机与 X Window 系统交互。 |