标准化镜像加密和解密¶
OpenStack 已经具备创建加密卷和临时存储的能力,以确保块数据的机密性。虽然存储加密镜像也是可行的,但目前只有 Cinder 服务利用了这一选项,并且 Nova 只能间接使用(用户必须先从镜像创建卷),因此用户没有直观的方式来创建和上传加密镜像。此外,目前用于检测和使用加密镜像的所有元数据要么不存在,要么仅限于 Cinder 的范围。总而言之,对加密镜像的支持在某种程度上存在,但方式不明确且未标准化。为了在所有 OpenStack 服务以及用户层面建立一致的镜像加密方法,需要在 Glance、Cinder 和 OSC 中进行一些调整。
问题描述¶
上传到 Glance 的镜像或通过 Nova 从现有服务器(虚拟机快照)创建的镜像可能包含敏感信息。已经提供的签名功能仅保护镜像免受篡改。镜像可能存储在多个主机上很长时间。首先,这包括 Glance 自身的镜像存储主机。此外,它可能还涉及计算主机等系统上的缓存。总之,它们暴露于多种潜在场景,涉及不同的主机、不同的访问模式和攻击面。参与这些场景的 OpenStack 组件无法保护镜像数据的机密性。
使用加密存储后端用于卷和计算主机,并结合从/到加密镜像的直接数据传输,可以实现无需在主机文件系统上暴露镜像数据的流程。将加密密钥存储在专用的密钥管理主机上,也能确保密钥的隔离和访问控制。
如上文介绍所述,Nova 中临时磁盘和 Cinder 中卷的一些磁盘镜像加密实现已经涉及到了这个主题,但并非总是以标准化和可互操作的方式进行。例如,处理镜像元数据和加密密钥的方式可能不同。此外,用户在提供自己的镜像时,很难使用这些实现,从而使加密在所有服务中以相同的方式工作。
因此,我们建议引入一种精简的加密镜像格式,以及跨 OpenStack 服务支持现有加密实现并提高互操作性和用户可用性的明确定义的元数据规范。
用例¶
用户想要上传包含敏感信息的镜像。为了确保镜像的完整性,可以生成签名并用于验证。此外,用户希望通过加密来保护镜像数据的机密性。用户在密钥管理器(例如 Barbican)中生成或上传密钥,并在上传之前使用它对镜像进行本地加密。可以在后续版本中添加一种机制,让 OpenStack 客户端 (OSC) 执行加密。因此,存储在 Glance 主机上的镜像将被加密。
用户想要基于 a) 外部创建的加密镜像或 b) 从 Nova 和 Cinder 等组件中的已加密存储对象创建的备份镜像创建新的服务器或卷。相应的计算或卷主机必须能够直接使用加密镜像,或者(如果兼容性不足)将加密从例如 qcow2-LUKS 转换为原始 LUKS 加密块,以用于卷。为此,OpenStack 服务需要访问密钥管理器中的密钥以及有关加密镜像的一些镜像属性。
用户想要下载并直接解密加密镜像,以便私下使用或在其他部署中使用。如果可能,可以调整客户端下载机制以直接解密此类镜像。
提议的变更¶
有两种方式可以处理镜像中的加密。第一种是具有内部加密的 qcow2 格式的磁盘。此类镜像的 ‘disk_format’ 将相应地为 ‘qcow2’,并且可以通过存在建议的附加元数据来检测加密。对于其他镜像,将使用 ‘disk_format’ 来指示加密。它应说明使用的主加密机制,目前为 ‘luks’。我们还假设解密后的 LUKS 镜像的格式始终为 ‘raw’。只有在解密至少前几个字节后才能检查格式,这目前不在 Glance 的范围内。任何使用此类加密 LUKS 镜像的服务都需要了解这一点。
此外,我们建议将以下附加元数据属性包含在格式的镜像中
‘os_encrypt_format’ - 使用的具体机制,例如 ‘LUKSv1’
‘os_encrypt_key_id’ - 密钥管理中的密钥引用
‘os_encrypt_key_deletion_policy’ - 在删除镜像时,指示是否应同时删除密钥
‘os_decrypt_container_format’ - 格式更改,例如从 ‘compressed’ 到 ‘bare’
‘os_decrypt_size’ - 负载解密后的尺寸
为了将加密镜像上传到 Glance,我们希望扩展 OpenStack 客户端,以便允许指定必要的元数据属性,例如密钥 ID 和加密,以及可选的元数据属性,例如指定密钥删除策略。稍后可能会添加支持使用指定的密钥 ID 在 OpenStack 客户端中直接加密镜像的功能。
换句话说:用户必须在上传之前加密镜像。在将加密镜像上传到 Glance 时,必须指定上述元数据属性。
我们建议将加密与 Nova 和 Cinder 对齐,并使用 LUKS,LUKS 可以与 qcow 和 raw 镜像结合使用。我们使用这两个版本的原因如下
Nova 在创建服务器时可以直接使用 qcow-LUKS 加密。这是 Nova 的标准流程。Nova 还可以处理 LUKS 加密的 raw 镜像。
Cinder 允许从加密卷创建镜像。这些将始终导致 LUKS 加密的 raw 镜像。这些镜像可以直接转换回卷。Cinder 当前期望加密镜像为 raw 镜像。
在后一种情况下,可以将此类加密镜像上传到另一个 OpenStack 基础设施,上传密钥并设置相应的元数据。完成此操作后,可以在第二个基础设施中使用该镜像来创建加密卷。
我们希望通过标准化使用的元数据参数并在适用时添加互操作性来对齐 Nova 和 Cinder 之间的现有实现。此外,我们希望为用户提供在 Glance 中上传外部加密镜像的手段,这些镜像将以类似的方式由 Cinder 和 Nova 处理。
密钥管理的处理方式与加密卷或加密临时存储不同。原因是,镜像的加密和解密绝不应在 Glance 中发生,而应在客户端进行。因此,为新创建的加密镜像创建密钥的服务可能与随后必须删除密钥的服务相同(在大多数情况下为 Glance)。删除由同一实体未创建的密钥是错误的。为了避免这种情况,我们选择执行以下操作
如果用户上传镜像,则用户负责创建和删除密钥。
如果 Cinder 或 Nova 上传镜像,则它们负责创建密钥(例如,Cinder 当前处理的方式)。
通过将特殊元数据参数“os_encrypt_key_deletion_policy”设置为 true,可以选择将密钥的删除委托给 Glance。此行为已经为来自 Cinder 的加密镜像实现,我们将仅重命名该属性,使其不只是由 Cinder 可用。
为了避免意外删除用于加密镜像的密钥,Glance 将在上传相应的加密镜像时注册为该密钥(Barbican 中的 secret [1])的消费者,并在 Glance 中删除镜像时取消注册。当参数“os_encrypt_key_deletion_policy”设置为“True”时,我们将尝试删除密钥。如果失败,因为仍有消费者,我们将让 Glance 将其记录为警告并继续进行镜像删除过程。在这种情况下,密钥可能仍然用于另一个镜像或某些其他资源,我们不想删除它,而是假设“os_encrypt_key_deletion_policy”被错误地设置为“True”。
镜像转换将不感知加密,因此,本规范不支持加密镜像的转换。vmdk 格式不受此规范支持,并且转换本身需要处理解密和加密,由 Glance 处理。这将超出本规范的范围。因此,如果启用了镜像转换并上传了需要转换的加密镜像,API 将返回 400 错误,并且镜像将作为结果置于排队状态。
备选方案¶
我们可以为每种数据格式和密码算法的组合在 Glance 中引入单独的容器类型,而不是使用带有元数据的单个容器类型。此决定会影响 Nova 和 Cinder 中的实现。关于镜像加密,我们还探讨了使用更复杂和动态的方法,例如 PKCS#7 (CMS),但最终未能找到支持 CMS 包装加密数据流式解密的免费开源实现。更具体地说,我们测试的任何实现都无法在不尝试完全将数据加载到内存中或遭受其他关于大文件的限制的情况下解密对称加密的 CMS 包装容器。
我们还评估了基于 GPG 的镜像加密实现。这种实现的一个缺点是,每次使用此类镜像创建服务器或卷时,都必须解密该镜像,并可能为了另一种加密格式而重新加密,因为 Nova 和 Cinder 都使用 LUKS 作为加密机制。这不仅会影响操作的性能,还需要加密镜像文件、解密部分以及创建的加密卷或服务器的可用空间。
我们评估使用单个容器格式来处理所有加密镜像,但由于 Cinder 已经使用不同的容器存储镜像(例如 ‘compressed’),我们决定使用通常的容器格式并检查加密参数是否存在以检测加密镜像。
数据模型影响¶
影响取决于实现是否会对镜像数据模型进行实际更改,或者只是使用元数据中的通用属性字段。在后一种情况下,加密属性将被添加到 metadefs 中。
REST API 影响¶
在上传要加密的镜像时,需要在请求主体中引入额外的属性来指定所需的加密格式和密钥 ID。两者都将用于在上传之前本地加密镜像。
示例请求:` REQ: curl -g -i -X POST http://a.b.c.d/image/v2/images -H "Content-Type: application/json" .... -d ' {"disk_format": "LUKS", "name": "cirros", "container_format": "compressed", "os_encrypt_format": "LUKSv1", "os_encrypt_key_id": "...", "os_encrypt_key_deletion_policy": "True", "os_decrypt_format": "raw", "os_decrypt_container_format": "bare", "os_decrypt_size": "...", ...}' `
此外,GET 镜像 API 调用将显示所有设置的属性。
安全影响¶
对 OpenStack 的安全性有影响
本规范将解决镜像中数据机密性的问题
正式引入镜像加密,因此加密算法将在所有相关组件(Nova、Cinder、OSC)中使用
Glance 可能会失去提供针对镜像策略违规行为的第一层防御能力(例如,拒绝无效/禁止的格式),因为无法检查加密数据。
通知影响¶
无
其他最终用户影响¶
用户应该能够选择性地,但有意识地上传加密镜像。
如果管理员配置 Glance 以拒绝未加密的镜像,则尝试上传到 Glance 时将不会接受此类镜像。
性能影响¶
OpenStack 组件中建议的加密/解密机制仅在客户端使用,并且完全跳过未加密的镜像。
从加密镜像创建卷或服务器时,可能触发的唯一操作是在 qcow-LUKS 和 raw LUKS 块之间进行转换。
因此,任何性能影响仅适用于新引入的加密镜像类型,其中镜像处理将比常规镜像具有更高的计算成本和更长的处理时间。 影响将因各个主机性能和支持的密码算法 CPU 扩展而异。
其他部署者影响¶
如果使用加密镜像,则需要密钥管理器 - 例如 Barbican。
开发人员影响¶
无
升级影响¶
我们可以假设,所有已加密并已存在于 OpenStack 部署中的镜像都是从加密的 Cinder 卷创建的。需要以以下方式调整它们
所有设置了 ‘cinder_encryption_key_id’ 的镜像,都需要将其转换为 ‘os_encrypt_key_id’
所有设置了 ‘cinder_encryption_key_deletion_policy’ 的镜像,都需要将其转换为 ‘os_encrypt_key_deletion_policy’
实现¶
负责人¶
主要负责人:Markus Hentsch (IRC: mhen)
其他贡献者:Josephine Seifert (IRC: Luzi)
工作项¶
将支持加密的标准化参数添加到 Glance
在上传加密镜像时,增加注册为 Barbican 密钥的消费者
在删除加密镜像时,增加注销为 Barbican 密钥的消费者
为 python-openstackclient 和 openstacksdk 添加支持,以便提供新的镜像属性,从而可以上传加密镜像
更改 Glance 代码库中 ‘cinder_encryption_key_deletion_policy’ 和 ‘cinder_encryption_key_id’ 的用法,以使用新的参数
添加上传加密镜像的单元测试和功能测试
添加一个迁移脚本,用于转换基于卷的加密镜像的旧属性
调整文档以显示新的和更改的参数
在安全指南中添加镜像加密的文档
依赖项¶
Glance 需要 Barbican 中的 secret consumer API 才能注册和注销为密钥的消费者
测试¶
Tempest 测试需要访问加密镜像才能进行测试。 这意味着 Tempest 需要提供一个已经加密的镜像文件及其相应的密钥,或者能够自行加密镜像。 这一点仍在讨论中。
文档影响¶
应该为部署者记录如何在 OpenStack 配置中启用此功能。最终用户应该有关于如何创建和使用加密镜像的文档。
参考资料¶
[1] Barbican Secret Consumer Spec: https://review.opendev.org/#/c/662013/
历史¶
发布名称 |
描述 |
|---|---|
Dalmatian |
引入 |