Neutron LBaaS TLS - 规范

BP https://blueprints.launchpad.net/neutron/+spec/lbaas-ssl-termination

在负载均衡器上终止 TLS 连接是现代负载均衡器期望的功能,并被整合到许多应用程序中。此功能能够更好地管理证书并改进基于应用程序的负载均衡,例如基于 cookie 的持久性、L7 策略设备等。

问题描述

Neutron LBaaS 目前没有 TLS 卸载功能

提议的变更

注意:本文档引用了 https://review.openstack.org/#/c/89903 上提出的新的 LBaaS 对象模型

注意:本文档不考虑 https://review.openstack.org/#/c/90070 上提出的 flavors 框架。在 flavors 框架到位之前,不支持 TLS 功能的特定后端驱动程序应抛出异常,声明缺少 TLS 支持,一旦收到带有 TLS 配置的 listener 请求。本文档指定了一个“核心”功能集,所有实现 TLS 功能的后端都必须遵守。各种后端实现中的 TLS 功能可能在未来的版本中有所不同,因此 flavors 方面肯定应包含在 TLS 功能规范中

注意:Horizon 项目方面不属于本规范的一部分。

  • 租户将使用 Barbican 管理其 TLS 证书。证书将存储在 Barbican 安全容器中。

  • Barbican 负责容器生命周期管理、容器分类和验证。LBaaS TLS 需要特定的容器类型 (TLS)。在配置 listener 的 TLS 容器以使用时,只有这种类型的容器才会列出给租户进行选择。任何无效的容器使用都会引发错误。

  • Barbican 还会管理每个容器感兴趣的消费者列表。请参阅 https://review.openstack.org/#/c/99516 上的规范

    Neutron LBaaS(根据 Barbican 的术语,是一个消费者)不会使用常规 GET 请求来获取容器资源,而是会使用 POST 请求到容器的消费者资源 (http://admin-api/v1/containers/{container-uuid}/consumers) 并包含以下信息

    {

    “type”: “LBaaS”, “URL”: “https://lbaas.myurl.net/loadbalancers/<lb_id>/”

    }

    注意:我们可能希望使用特定的 Listener URL 代替 Loadbalancer 的 URL,例如 “https://lbaas.myurl.net/lbaas/listeners/<listener_id>”

    作为响应,它将获得与使用容器资源 GET 请求相同的数据容器。Barbican 依次会在其数据库中存储消费者的(LBaaS 实例 URL)数据,以便可以使用此信息来获取特定 TLS 容器的所有消费者。

    因此,Neutron LBaaS TLS 实现需要

    • 仅使用 POST 请求到容器的消费者资源来获取容器的数据。

    • 停止使用容器时,执行 DELETE 请求到容器的消费者资源。

  • Barbican TLS 容器将包含 PEM 编码的数据。特定的后端实现可以将证书数据转换为其他格式,例如 DER(如果需要)。

  • 除了现有的 HTTP、HTTPS 和 TCP 之外,将为 listener 创建添加新的协议 TERMINATED_HTTPS

  • 对于租户而言,使用 TERMINATED_HTTPS 作为协议创建 listener 意味着希望卸载传入的加密流量。新的配置选项将可用于 listener 的配置,包括

    • 用于 TLS 终止的默认 TLS 容器 ID

    • 用于 SNI 的 TLS 容器列表

  • 如果特定的后端无法支持 TLS 功能,则其驱动程序应抛出异常。异常消息应说明此特定的后端(提供程序)不支持带有 TLS 卸载的 listener。listener 需要 TLS 卸载功能的明确标志是其 TERMINATED_HTTPS 协议。

  • 将在 Neutron LBaaS 中开发一个新模块,用于与 Barbican TLS 容器交互。该模块将由 Neutron LBaaS 前端 API 代码和提供程序驱动程序代码使用。该模块将用于验证和从默认 TLS 容器和 SNI 容器中提取数据。此模块代表与 Barbican TLS 容器交互的唯一合法 API。有关详细的模块规范,请参阅“SNI 证书列表管理”部分。

  • 创建具有 TERMINATED_HTTPS 协议的 listener 时

    • 前端 TLS 卸载始终启用 - 默认情况下,具有 TERMINATED_HTTPS 协议的 listener 的行为是硬编码的

    • 租户必须提供用于前端卸载的默认 TLS 容器。未提供容器是无效的配置。

    • TLS 支持的协议和用于终止的密码套件将由每个后端的特定代码设置为合理的值

    • SNI 证书列表是可选的,并非强制指定

    • 指定 SNI 证书列表在“SNI 证书列表管理”部分中描述

    • 证书中间链将作为 Barbican 的 TLS 容器的一部分存储

  • 第一阶段将不支持后端重新加密

  • 第一阶段将不支持前端客户端身份验证和后端服务器身份验证

  • 更新具有 TERMINATED_HTTPS 协议的 listener 时

    • 在 TLS 配置域中,用于前端卸载的默认 TLS 容器 ID 和 SNI 容器 ID 列表是可能更改的值

    • 如果为 listener 替换了默认 TLS 容器 ID,后端实现应确保 LB 设备上没有停机时间。

    • 对于更改 SNI 容器 ID 列表,后端应避免 LB 停机时间。

  • HA-Proxy LBaaS 实现和其他 LBaaS 实现应进行修改以支持此规范。

根据上述内容,以下是基本租户用例的描述 - 创建具有 TLS 卸载的 listener

  • 租户使用证书创建 Barbican TLS 容器。

  • 租户使用 TERMINATED_HTTPS 作为 listener 协议创建 listener,并将 Barbican TLS 容器 ID 指定为用于前端卸载的默认 TLS 容器

  • 结果是,创建的 listener 在前端卸载加密流量,使用默认租户的 TLS 证书,不将流量重新加密到后端。

来自 Barbican 的要求

  • 租户应能够使用 Barbican 创建和删除 TLS 容器

  • 能够在 Barbican 容器中存储 TLS 证书,其中包含 TLS 证书本身、其私钥和可选的中间链

    • 创建 TLS 容器时

      • Certificate: PEM 文本字段

      • Private_key: PEM text_field

      • (提取) Private_key_pass_phrase: 文本字段

      • Intermediates: PEM 文本字段(可选)此字段是特定顺序中 PEM 编码证书块的连接

    • 删除 TLS 证书 可选:检查证书是否被任何消费者使用,并在删除之前发出警告。Barbican 的 BP 讨论此功能:https://review.openstack.org/#/c/99516/

    • 通过容器 ID 获取 TLS 容器,包括 PEM 编码的 PKCS1 或 PKCS7 格式的私钥

    • 通过容器 ID 获取 PEM 编码的 x509 格式的 TLS 证书

限制

  • TLS 设置仅适用于具有 TERMINATED_HTTPS 作为协议的 listener。在其他情况下,TLS 设置将被禁用并具有 None 或空值。如果配置无效,应向用户提供有意义的错误消息,解释失败的确切原因。

  • listener 协议是不可变的。更改协议将需要提供程序后端系统的彻底重新配置,这似乎对于此用例来说是不合理的。租户应创建新的 listener。

  • 在更新现有的 TLS 证书时,名称和描述是允许修改的唯一值。创建新的 TLS 容器并使用它代替旧容器将比重新配置 LBaaS 后端具有修改后的容器更容易,至少在第一阶段是这样。

SNI 证书列表管理

对于 SNI 功能,租户将以特定顺序提供 TLS 容器列表。如果特定的后端无法支持 SNI 功能,则其驱动程序应抛出异常。异常消息应说明此特定的后端(提供程序)不支持 SNI 功能。listener 需要 SNI 功能的明确标志是一个非空的 SNI 容器 ID 列表。但是,参考实现必须支持 SNI 功能。

将在 Neutron LBaaS 中开发一个新模块,用于与 Barbican TLS 容器交互。该模块将使用服务帐户进行 Barbican API 交互。该模块将具有用于:* 确保 Barbican TLS 容器存在(由 LBaaS 前端 API 使用)的 API

  • 验证 Barbican TLS 容器(由 LBaaS 前端 API 使用)此 API 还会将 LBaaS 作为 Barbican 存储库中的容器的消费者“注册”。

  • 从证书的 X509 中提取 SubjectCommonName 和 SubjectAltName 信息(由 LBaaS 前端 API 使用)目前,仅从 SubjectAltName 序列中提取 dNSName 和 directoryName 类型,而 directoryName 类型的用法是进一步讨论的问题。

  • 从 Barbican TLS 容器中提取证书数据(由提供程序/驱动程序代码使用)

  • 当不再有任何 listener 使用容器时,取消注册 LBaaS 作为容器的消费者(由 LBaaS 前端 API 使用)

该模块将使用 pyOpenSSL 和 PyASN1 包。只有这个新的通用模块才应由 Neutron LBaaS 代码用于 Barbican 容器交互。

前端 LBaaS API(插件)代码将使用新开发的模块来验证 Barbican TLS 容器。驱动程序反过来可以通过通用模块 API 从证书的 X509 中提取 SubjectCommonName 和 SubjectAltName 信息,并将其用于其特定的 SNI 实现。

注意

特定的后端驱动程序不必使用 SubjectAltName 信息。此外,特定的驱动程序可能会抛出异常,说明 SubjectAltName 不受其提供程序的支持

任何特定的驱动程序实现都可以仅使用上述通用模块 API 从证书中提取主机名信息(如果需要)。

SNI 冲突

使用证书列表的顺序不是所有后端实现的要求。特定的后端代码(例如 Radware 的代码)可以使用证书列表的顺序来指定证书之间的优先级。顺序旨在用作解决冲突的提示,当 2 个或多个证书与 SNI 客户端问候中请求的 DNS 名称匹配时。特定的后端可以选择忽略此顺序,并可能采用自己的机制来选择一个冲突的证书。例如,NetScaler 采用最佳匹配算法,不需要顺序来解决冲突。也可能特定的驱动程序抛出异常,说明存在冲突,并且此特定的 SNI 设置将不受后端支持。

数据模型影响

数据模型更改

  • lbaas_listeners 表将使用新的

    • default_tls_container_id(nullable string 36)- Barbican 的 TLS 容器 ID

  • 将创建新的 lbaas_sni 表,用于存储与 listener 关联的 TLS 容器的有序列表,以实现 SNI 功能。关联对象由以下组成:

    • id(不可变的 string 36)- 生成的对象 ID

    • listener_id(string 36)- 关联的 listener ID

    • tls_container_id(string 36)- 关联的 Barbican TLS 容器 ID

    • position - (integer) 用于保留顺序的索引

所需的数据库迁移

  • lbaas_isteners 表添加新列

  • 创建新的 lbaas_sni

新的数据初始设置

  • lbaas_listeners 表现有条目的新列将设置为默认值

REST API 影响

Listener 属性

属性名称

类型

访问

默认值

验证/转换

描述

default-tls- container-id

UUID

RW,tenant

NULL

UUID

用于卸载的默认 TLS 证书 ID

sni_container _ids

UUID 列表

RW,tenant

NULL

UUID 列表

用于 SNI 的 TLS 容器的有序列表。

功能

  • create_listener

    • 创建新的 listener

    • 请求 POST /v2.0/lbaas/listeners Accept: application/json { “listener”:{ <…usual listener 参数>, “protocol”: “TERMINATED_HTTPS” “default_tls_container_id”: “7804a0de-7f6b-409a-a47c-a1cc7bc77b4j”, “sni_container_ids”: None } }

    • 响应 { “listener”:{ “id”: “8604a0de-7f6b-409a-a47c-a1cc7bc77b2e” <…usual listener 参数>, “default_tls_container_id”: “7804a0de-7f6b-409a-a47c-a1cc7bc77b4c”, “sni_container_ids”: None “tenant_id”:”6b96ff0cb17a4b859e1e575d221683d3” } }

  • create_listener(带有 SNI 列表)

    • 创建新的 listener

    • 请求 POST /v2.0/lbaas/listeners Accept: application/json { “listener”:{ <…usual listener 参数>, “protocol”: “TERMINATED_HTTPS” “default_tls_container_id”: “7804a0de-7f6b-409a-a47c-a1cc7bc77b4j”, “sni_container_ids”: [5404a0de-7f6b-409a-a47c-a1ccgbc77b3j, 1206a0de-7f6b-409a-a47c-a1ccgbc7bgf3] } }

    • 响应 { “listener”:{ “id”: “8604a0de-7f6b-409a-a47c-a1cc7bc77b2e” <…usual listener 参数>, “default_tls_container_id”: “7804a0de-7f6b-409a-a47c-a1cc7bc77b4c”, “sni_container_ids”:[5404a0de-7f6b-409a-a47c-a1ccgbc77b3j, 1206a0de-7f6b-409a-a47c-a1ccgbc7bgf3] “tenant_id”:”6b96ff0cb17a4b859e1e575d221683d3” } }

  • update_listener

    • 更新 VIP listener

    • 请求 PUT /v2.0/lbaas/listeners/<listener-id> Accept: application/json { “listener”:{ <…usual listener 参数>, “protocol”: “TERMINATED_HTTPS” “default_tls_container_id”: “7804a0de-7f6b-409a-a47c-a1cc7bc77b4c”, “sni_container_ids”: None } }

    • 响应 { “listener”:{ “id”: “8604a0de-7f6b-409a-a47c-a1cc7bc77b2e” <…usual listener 参数>, “default_tls_container_id”: “7804a0de-7f6b-409a-a47c-a1cc7bc77b4c”, “sni_container_ids”: None “tenant_id”:”6b96ff0cb17a4b859e1e575d221683d3” } }

安全影响

以下是安全要求

  • 从 Barbican 到 LBaaS 插件/驱动程序的 TLS 容器检索必须是安全的

  • 从驱动程序到后端系统的 TLS 容器内容传输必须是安全的

  • 禁止在 neutron 服务器上存储密钥

  • 后端系统可能需要确保密钥的安全存储,以满足某些安全合规性要求

通知影响

CLI 影响

  • 使用 TERMINATED_HTTPS 协议创建监听器(默认行为)lb-listener-create –protocol TERMINATED_HTTPS –protocol-port 443 –default_tls_container_id 9a96ff0cb17a4b859e1e575d2216cd23 …<常规 CLI 选项>

  • 使用 TERMINATED_HTTPS 协议和 SNI 证书列表创建监听器 lb-listener-create –protocol TERMINATED_HTTPS –protocol-port 443 –default_tls_container_id 9a96ff0cb17a4b859e1e575d2216cd23 –sni_container_ids list=true 6b96ff0cb17a4b859e1e575d221683d3 4596ff0cb17a4b859e1e575d22168ba1 …<常规 CLI 选项>

其他最终用户影响

性能影响

  • 在不修改 TLS 设置(默认容器 ID 或 SNI 列表)的情况下更新监听器 - 不应使用 Barbican API 来检索未实际更改的容器内容。 这将防止在向监听器使用的池中添加成员时等情况下不必要的资源消耗。 这意味着每个 Barbican TLS 容器仅在仍然被该监听器使用时才会被验证一次。

IPv6 影响

其他部署者影响

  • 为了使此功能正常工作,Barbican 需要被部署并处于运行状态。

  • 为 neutron、pyOpenSSL 和 PyASN1 添加了新的依赖项。 这些依赖项由用于 Barbican TLS 容器交互的新模块需要。

开发人员影响

社区影响

此更改自 Juno 以来一直在审查中。 IRC 和邮件列表中进行了大量讨论。

备选方案

实现

负责人

主要负责人

其他贡献者

Barbican TLS 容器交互模块 - https://launchpad.net/~carlos-garza

工作项

  • 使用 pyOpenSSL 和 PyASN1 包开发用于 Barbican TLS 容器交互的新模块。

  • 实现 LBaaS DB 模式 v2 中的更改

  • 实现 LBaaS 扩展 v2 中的更改

  • 实现所有必需的 CLI 更改

  • 实现所有必需的单元测试

  • 实现所有必需的 tempest 测试

  • 与 Barbican 证书存储 API 集成。 关于如何使用 Barbican 的容器 API 的详细规范位于 https://review.openstack.org/#/c/99516

  • 修改 LBaaS HA-Proxy 驱动程序以支持 TLS 功能。 此工作项的详细规范位于 https://review.openstack.org/#/c/100931

  • 使用 HA-Proxy 版本 1.5

  • 实现此规范的 horizon 部分,不作为 Juno 版本的发布内容。

依赖项

  • Barbican API 要求

  • 带有新监听器对象实现的 Neutron LBaaS API v2

  • 将添加 neutron、pyOpenSSL 和 PyASN1 的新依赖项。 这些依赖项由用于 Barbican TLS 容器交互的新模块需要。

测试

Tempest 测试

监听器单元测试域

  • REST API 和属性验证测试

  • DB mixin 和模式测试

  • 带有模拟驱动程序的 LBaaS 插件端到端测试

  • 支持 TLS 卸载的每个现有驱动程序的特定驱动程序测试

  • Tempest 测试

  • CLI 测试

  • 使用 TERMINATED_HTTPS 作为协议创建新的监听器

    • 未提供终止的默认 TLS 容器。 检查错误生成

    • 提供了终止的默认 TLS 容器。 测试预期的默认配置是否生效。

    • 提供了默认 TLS 容器。 提供了 SNI TLS 容器列表。 测试预期的配置是否生效

  • 使用 TERMINATED_HTTPS 作为协议更新现有的监听器

    • 更改默认 TLS 容器。 测试预期的配置

    • 添加/修改 SNI 容器列表。 测试预期的配置

CLI 测试应测试不一致问题,例如

  • 在创建具有 TERMINATES_HTTPS 协议的监听器时未指定默认卸载 TLS 容器

功能测试

如上所述。

API 测试

如上所述。

文档影响

用户文档

  • Neutron CLI 应使用 TLS 选项修改为具有更新的监听器命令

开发人员文档

  • Neutron API 应使用新的监听器 TLS 属性进行修改

参考资料