镜像加密和解密

OpenStack 已经具备创建加密卷和临时存储的能力,以确保块数据的机密性。与此不同,目前镜像的处理方式缺乏对机密性的保护,仅提供使用镜像签名来确保完整性的可能性。为了进一步保护用户数据——例如,当用户上传包含私有数据或机密信息的镜像时——镜像数据不应可供未经授权的实体访问。为此,应在 OpenStack 中引入一种加密的镜像格式。

为了实现这一点,需要在各个项目中实施若干调整,以支持镜像加密/解密,例如 Nova、Glance、Cinder 和 OSC。

本文档中描述的提案描述了 Cinder 相关的整体跨项目概念中,镜像加密的部分。

问题描述

当镜像上传到 Glance 或通过 Nova 从现有服务器(虚拟机)创建时,可能包含敏感信息。已经提供的签名功能仅保护镜像免受篡改。镜像可能在多个主机上存储很长时间。首先,这包括 Glance 自身的镜像存储主机。此外,它还可能涉及其他系统,例如卷主机。因此,它们暴露于多种潜在场景,涉及不同的主机、不同的访问模式和攻击面。参与这些场景的 OpenStack 组件——包括 Cinder——不保护镜像数据的机密性。

使用加密存储后端用于卷和计算主机,并结合从/向加密镜像的直接数据传输,可以实现从未在主机文件系统上暴露镜像数据的流程。将加密密钥存储在专用的密钥管理主机上,也能确保密钥的隔离和访问控制。通过这样一套针对安全环境的配置建议,我们能够达到一个良好的基础。未来的增强功能可以基于此构建,并将提供的安全增强扩展到更广泛的变体。

因此,我们建议引入一种加密的镜像格式。

用例

1. 用户希望基于加密镜像创建新的卷。相应的卷主机必须能够使用存储在密钥管理程序中的对称密钥解密镜像,并将其转换为请求的卷资源。

2.1. 用户希望从卷创建加密镜像。卷不使用加密卷类型。目标镜像应使用提议的镜像加密机制和指定的密钥进行加密。

2.2. 用户希望从卷创建加密镜像。卷使用加密卷类型(基于 LUKS)。目标镜像不应重新加密,而是会重用 LUKS 加密和密钥。此用例已经作为 Cinder 默认行为的一部分实现。

2.3. 用户希望从卷创建加密镜像。卷使用加密卷类型(基于 LUKS)。目标镜像应使用提议的镜像加密机制和指定的密钥重新加密。这涉及为 LUKS 加密打开 dmcrypt 映射,并将卷的明文数据直接流式传输到目标镜像文件,同时使用指定的镜像加密机制(例如 GPG)对其进行加密。

提议的变更

在 Glance 中,我们建议添加一个新的 container_format,名为 ‘encrypted’(加密)。此外,我们建议以下附加元数据属性由这种格式的镜像携带

  • ‘os_encrypt_format’ - 使用的主要机制,例如 ‘GPG’

  • ‘os_encrypt_type’ - 加密类型,例如 ‘symmetric’(对称)

  • ‘os_encrypt_cipher’ - 密码算法,例如 ‘AES256’

  • ‘os_encrypt_key_id’ - 密钥管理程序中的密钥引用

  • ‘os_decrypt_container_format’ - payload 解密后的格式

  • ‘os_decrypt_size’ - 负载解密后的尺寸

所有这些元数据属性仅用于镜像的解密,并且不再需要在卷的生命周期中使用。在从卷创建镜像时,这些元数据属性将被重新生成并保存到 Glance 的新镜像元数据中。

对于 Cinder,我们希望添加对从其创建卷时加密镜像解密的支持。Cinder 应根据新的镜像 container_format 和元数据选择合适的解密机制。对称密钥将从密钥管理程序(例如 Barbican)中检索,具体取决于存储在元数据中的密钥 ID。此外,Cinder 还应能够以类似的方式加密卷数据,如果用户请求根据上述用例 2.1 和 2.3 从卷创建加密镜像。

Cinder 中的实现应使用由全局库提供的集中式加密实现,该库在所有参与的 OpenStack 组件之间共享,以防止对加密机制进行单独的实现。

对于通用的镜像加密,我们建议使用 GnuPG 提供的对称 AES 256 实现作为此草案支持的基本机制。它是一个成熟的 PGP 实现,支持可流式加密/解密过程,这很重要,因为我们要求加密/解密机制具有可流式传输能力,原因如下

  1. 将整个镜像加载到卷主机的内存中是不可接受的。

  2. 我们建议直接解密流式传输到目标卷,以防止创建临时未加密的文件。

Cinder 当前实现中已经存在一种创建加密镜像的案例(用例 2.2)。当镜像直接从加密卷创建时就是这种情况。由于加密的块数据只是被复制到镜像中,因此加密(通常是 LUKS)会自动继承——密钥也是如此,它只是在 Barbican 中被克隆。作为本规范的一部分,我们不会更改此行为。我们的更改仅在用户主动希望从任何卷创建加密镜像时才会应用。

密钥管理与加密卷或加密临时存储的处理方式不同。原因是镜像的加密和解密绝不在 Glance 中发生,而是在所有使用镜像的其他服务中发生。因此,为新创建的加密镜像创建密钥的服务可能与随后必须删除密钥的服务相同(在大多数情况下是 Glance)。删除未由同一实体创建的密钥是错误的。为了避免这种情况,我们选择让用户创建和删除密钥。为了避免意外删除用于加密镜像的密钥,我们将 Glance 在上传相应的加密镜像时注册为该密钥的消费者(Barbican 中的 secret [1]),并在 Glance 中删除镜像时取消注册。

用于文件(在本例中为镜像)的加密和解密的方法将在 os-brick 中以类似驱动程序的方式编写,以便可以轻松地使用另一种加密格式扩展镜像加密。加密驱动程序应专注于特定的加密格式,并实现一个精确的加密方法和一个解密方法,两者均基于 GPG aes 的密码实现。该驱动程序可以是现有实现周围的简单包装器。应定义一个抽象基类,并用于 GPG 加密的实现(并且将来可能用于其他实现)。

备选方案

关于镜像加密,我们还探讨了使用更复杂和动态的方法,例如 PKCS#7 (CMS),但最终未能找到一个免费的开源实现(例如 OpenSSL),该实现支持对 CMS 包装的加密数据进行可流式解密。更具体地说,我们测试的任何实现都无法在不尝试完全将其加载到内存中或遭受其他关于大文件的限制的情况下解密对称加密的 CMS 包装容器。

我们还评估了基于 LUKS 的镜像加密实现,LUKS 已经用作 Cinder 和 Nova 中卷和临时磁盘的加密机制。但是,我们无法找到合适的解决方案来直接处理用户空间中的基于文件的 LUKS 加密。首先,即使是基于文件的 LUKS 设备,通过 cryptsetup 处理也始终需要 dm-crypt 内核模块和相应的 root 权限。其次,与 LibVirt 使用的本机 LUKS 不同,通过 cryptsetup 可用的 LUKS 处理会创建临时设备映射器端点,数据从中读取或写入。没有直接从/向加密的 LUKS 文件读取/写入,并且需要相应地处理 LUKS 打开/关闭。最后,LUKS 是一种主要设计用于磁盘加密的格式。虽然它也可以用于文件(通过将文件格式化为 LUKS 设备),但处理起来比较不方便;例如,LUKS 容器文件的大小需要提前计算和分配,因为它充当具有固定大小的磁盘。

数据模型影响

REST API 影响

对于从卷创建加密镜像,需要在 “os-volume_upload_image” 请求体中引入额外的属性,以指定所需的加密格式和密钥 ID。

安全影响

对 OpenStack 的安全性有影响

  • 本规范将解决镜像中数据机密性的问题

  • 引入了镜像加密,因此 Cinder 将使用额外的密码算法来实现此功能

通知影响

其他最终用户影响

  • 用户应该能够选择性地,但有意识地从卷创建不同加密的镜像。

  • 如果管理员配置 Glance 以拒绝未加密的镜像,则尝试上传到 Glance 时将不会接受此类镜像。

性能影响

Cinder 中提议的加密/解密机制仅会在需要时使用,并且对于不是加密的镜像容器类型,将完全跳过。

因此,任何性能影响仅适用于新引入的加密镜像类型,其中此类镜像的处理(或创建)将比常规镜像具有更高的计算成本和更长的处理时间。影响将因各个主机性能和对密码算法 CPU 扩展的支持而异。

对于基于 Ceph 的设置,由于需要将加密的镜像数据格式转换为卷格式,因此 Glance 和 Cinder 之间共享存储提供的常规克隆性能优势对于加密镜像将丢失。

其他部署者影响

  • 需要一个密钥管理程序——例如 Barbican。

  • 密钥管理程序需要可供卷主机访问,需要适当的 cinder.conf 调整。

开发人员影响

  • 为了在 os-brick 中使用图像的编码和解码,我们需要执行特权函数。我们决定像 nova 一样使用 privsep。

升级影响

实现

负责人

主要负责人

Markus Hentsch (IRC: mhen)

其他贡献者

Josephine Seifert (IRC: Luzi)

工作项

  • 在 Cinder 中添加一个解密实现,用于从 GPG 加密镜像创建卷

  • 在 Cinder 中添加一个专用的加密工作流程和实现,用于使用提议的镜像加密格式(GPG)从卷创建加密镜像

  • 在 os-brick 中为 GPG 格式添加加密和解密方法

依赖项

  • GPG 需要安装在所有需要执行加密/解密操作的系统上,以支持提议的基本加密机制。

  • 本规范要求 Glance 中实现加密的 container_format 和相应的元数据属性支持

  • 本规范要求在参与镜像加密工作流程的组件(Nova、Cinder、OSC)之间共享的全局库中实现适当的加密/解密功能,例如 os-brick

测试

Tempest 测试需要访问加密镜像才能进行测试。 这意味着 Tempest 需要提供一个已经加密的镜像文件及其相应的密钥,或者能够自行加密镜像。 这一点仍在讨论中。

文档影响

应该记录给部署者,如何在 OpenStack 配置中启用此功能。应该为最终用户提供文档,说明如何在 Cinder 中使用加密镜像以及如何创建它们。此外,应提及任何由此产生的限制,例如降低的性能,尤其是在通常受益于共享存储克隆的基于 Ceph 的设置中。

参考资料

[1] Barbican Secret Consumer Spec: https://review.opendev.org/#/c/662013/

Nova-Spec: https://review.openstack.org/#/c/608696/

Glance-Spec: https://review.openstack.org/#/c/609667/

历史

修订版

发布名称

描述

Train

引入

Ussuri

推迟