Glance 镜像签名和验证

https://blueprints.launchpad.net/glance/+spec/image-signing-and-verification-support

OpenStack 目前不支持以下功能

  • 上传的已签名镜像的签名验证

部署身份验证将通过验证镜像在用户上传后是否被修改来保护镜像完整性。此功能提高了 OpenStack 的企业级能力。

问题描述

没有方法可以验证先前上传的镜像是否被修改过。镜像有可能在传输过程中被修改(例如,在上传到 Glance 或传输到 Nova 时),或者 Glance 本身不可信并可能在用户不知情的情况下修改镜像。被修改的镜像可能包含恶意代码。提供镜像签名和签名验证的支持将允许用户在启动镜像之前验证镜像是否被修改过。

此功能将支持以下几种用例

  • 镜像由最终用户使用用户的私钥签名。然后用户将镜像上传到 Glance,并提供创建的签名以及对用户公钥证书的引用。Glance 使用此信息来验证签名是否有效,并在签名无效时通知用户。

  • 镜像在 Nova 中创建,并且 Nova 应最终用户的要求对镜像进行签名。当镜像上传到 Glance 时,签名和公钥证书引用也会一并提供。Glance 在存储镜像之前验证签名,并在签名验证失败时通知 Nova。

  • Nova 请求一个已签名的镜像,Glance 连同镜像一起向 Nova 提供签名以及对公钥证书的引用,以便 Nova 在启动镜像之前验证签名。

提议的变更

对于初始实现,此更改将使用 Glance 的属性功能来存储镜像签名和验证所需的元数据项。这些包括公钥证书引用和签名。这些在创建镜像时提供,并在上传镜像时可访问。请注意,此提议的更改仅支持使用 Glance API v2 进行镜像上传(不支持使用 Glance API v1)。 另外请注意,将支持多种密钥格式(例如 SubjectPublicKeyInfo)和签名格式(例如 PSS)。签名的格式将作为属性之一存储。

证书引用将用于从密钥管理器访问证书,该证书将存储在密钥管理器中。最终用户在上传镜像之前将此证书添加到密钥管理器。请注意,签名是离线完成的。

Glance 已经支持在上传镜像时计算镜像的校验和,并将校验和与镜像一起存储。相同的哈希值(默认情况下为 MD5)将用于签名验证。

校验和哈希值在 glance_store 中计算(当上传镜像数据时),然后用于验证签名。Glance 前端应使用对公钥证书的引用从密钥管理器检索证书,然后使用此公钥以及签名、计算出的校验和和其余签名元数据来验证签名。如果签名验证失败,镜像将转换为已杀死状态,并且会通知用户上传失败以及失败原因。

备选方案

与在存储后端中为签名验证/创建使用已经创建的哈希值相比,在存储前端计算哈希值是一种替代方案。但是,表示镜像数据的 eventlet.wsgi.Input 类文件只能读取一次,并且需要读取到存储后端才能上传镜像。为了在 Glance 前端读取镜像数据,Glance 可以将数据复制到文件中,使用该文件来验证/创建签名,然后将此文件提供给存储后端进行上传。这类似于 S3 后端 [1] 所做的事情。但是,这种方法将花费大量时间(在镜像上传期间),并且不会获得太多收益。

将公钥证书的引用存储在 Glance 中的替代方案是将实际的公钥证书存储在 Glance 中。但是,这种方法是不安全的,因为 Glance 与专用的密钥管理器不同,它并非为存储密钥或证书而创建的。

与使用非对称密钥进行完整性和机密性相比,使用对称密钥是一种替代方案。但是,为了使 Glance 能够验证镜像,它需要访问用于创建签名的密钥。这种访问将使 Glance 能够在用户不知情的情况下修改镜像并创建新的签名。使用非对称密钥使 Glance 能够在不赋予 Glance 修改镜像和签名权限的情况下验证签名。

与使用 Glance 属性来存储和检索签名元数据相比,创建支持签名的 API 扩展是一种替代方案。然后,用户将使用 API 扩展设置元数据,而不是使用属性键值对。目前,如果用户将元数据键(用于证书和签名)用于其他目的,镜像上传将失败。另一个需要注意的是,API 扩展允许以一种干净的方式管理每个镜像的多个签名,而属性方法无法做到这一点。但是,Images API 不支持扩展,因此这不是一种有效的方法。

与使用 Glance 属性来存储和检索签名元数据相比,使用 RFC 5652 第 5 节中定义的 CMS(密码消息语法)格式是一种替代方案。但是,此大小是可变的,并且无法使用现有的 Glance 属性,这将需要 API 修改。对于初始实现,将使用 Glance 属性,并计划在未来实现中迁移到使用 CMS,因为需要更大的灵活性。

与要求用户单独提供签名不同,支持已经具有嵌入式签名的镜像是一种替代方案。虽然这可以作为未来的改进,但初始实现不会提供嵌入式签名支持,因为保持初始工作集中和小型是有利的。

与使用现有的 MD5 哈希算法相比,创建用于签名验证/创建的单独可配置的哈希值是一种替代方案。但是,创建单独的哈希值会降低性能,而不会提供太多好处。请注意,由于存在比 MD5 更安全的更可取的哈希算法,因此正在提出一项单独的更改以允许配置此哈希算法 [2]。为了拥有一个直接的初始实现,这不会包含在本更改中。

与专注于单云实现相比,在初始实现中包含对多云的支持是一种替代方案。如果图像在不同的云之间交换,签名验证可用于确认图像未被修改。但是,为了更简单的初始实现,对多云的显式支持将保留到未来的迭代中。

数据模型影响

无。

REST API 影响

对于初始实现,不需要 API 更改,只要其他服务能够检索给定镜像的所有属性即可。

请注意,现有的 API 允许将签名元数据作为 Glance 属性提供,并在验证失败时返回错误消息。

安全影响

此更改通过启用签名签名和验证来提高 OpenStack 的企业级能力。

虽然此更改中使用了密钥,但密钥本身假定存储在密钥管理器中,并且仅将证书的引用存储在 Glance 中。

此更改涉及对镜像数据进行哈希处理,用于验证和创建镜像的签名。

请注意,由于这是 Glance 属性支持的最大大小,因此当前签名长度限制为 255 个字节。反过来,这限制了可用于签名创建的密钥的大小。

通知影响

此更改将涉及添加日志消息以指示签名验证和创建的成功或失败。

其他最终用户影响

用户需要提供签名和验证所需的信息才能使用此功能。

不需要对 python-glanceclient 进行任何更改。

性能影响

只有当用户在镜像上传期间提供了适当的属性时,才会使用该功能。否则,不会发生签名验证或创建。

当发生签名验证和创建时,从密钥管理器检索证书会产生一些延迟。由于已经为镜像创建了哈希值,因此哈希值创建对性能没有影响。

其他部署者影响

无。

开发人员影响

无。

实现

负责人

主要负责人

brianna-poulos

其他贡献者

dane-fichter

评审人员

核心评审人

flaper87 sigmavirus24 nikhil_k

其他审核员

joel-coffman

工作项

该功能将分以下阶段完成

  1. 启用 Glance 在用户发起的镜像上传期间验证用户提供的签名。

  2. 启用 Glance 验证 Nova 在 Nova 拍摄的快照上传镜像期间提供的签名。

依赖项

用于哈希创建和签名验证/创建的密码库已经是 OpenStack 的全局要求的一部分。但是,它不是 Glance 的一部分,需要添加进去。

Glance 目前不与任何密钥管理器交互。由于需要密钥管理器来管理密钥,因此需要进行更改以允许 Glance 使用密钥管理器检索公钥证书。具体来说,Castellan [3] 将用于与所选的密钥管理器接口。初始密钥管理器将是 Barbican,但 Castellan 可以配置为使用不同的后端。

为了利用 Glance 中的签名,Nova 需要更新以从 Glance 检索签名并验证它们。但是,Glance 不需要 Nova 支持此功能才能添加该功能。Nova 中的此规范 [4] 尚未获得批准。

测试

在添加 Nova 对此功能的支持之前,单元测试就足够了。一旦添加了 Nova 支持,Tempest 测试应确保 Nova 和 Glance 之间的交互按预期工作。

文档影响

需要记录如何使用该更改的说明。这些包括有关如何创建密钥和签名并在创建镜像期间提供此信息的用户的说明。

此文档还将包括以下签名元数据属性的描述

  • signature:以 base64 格式编码的“校验和哈希”的签名

  • signature_hash_method:用于创建签名的哈希方法

  • signature_key_type:用于创建签名的密钥类型

    • 有效值为:“RSA-PSS”

  • signature_certificate_uuid:用于从 castellan 检索证书的 uuid

  • mask_gen_algorithm:仅用于 RSA-PSS,定义了签名生成中使用的掩码生成算法,可选且默认值为“MGF1”

    • 有效值为:“MGF1”

  • pss_salt_length:仅用于 RSA-PSS,定义了签名生成中使用的盐长度,可选且默认值为 PSS.MAX_LENGTH

参考资料

cryptography:https://cryptography.io/en/latest/

[1] http://goo.gl/Y3u3lK

[2] https://review.openstack.org/191542

[3] http://git.openstack.org/cgit/openstack/castellan

[4] https://review.openstack.org/#/c/188874/