Keystone Fernet Token 实现¶
Fernet token 被添加到 OpenStack 中,是为了解决 keystone 需要将 token 持久化到通用数据库(集群)如 UUID token 的问题,并解决 PKI 或 PKIZ token 的大小问题。
Fernet token 是一种承载 token,代表用户身份验证。Fernet token 在 MessagePacked payload 中包含有限的身份和授权数据。然后,该 payload 作为 Fernet 消息进行传输,其中 Fernet 提供了在 URL 和 header 中使用的必要 web 安全特性。Fernet token 内部的数据使用对称加密密钥或 fernet 密钥进行保护。
问题描述¶
Keystone 自 Kilo 版本以来就支持 Fernet token,因此所有服务都支持 fernet token 授权。在即将发布的 Rocky 版本中,sql token driver 和 uuid token provider 将被移除。这项任务的主要工作是更改 keystone charm 以启用 fernet token 的配置,提供 fernet token 的初始化,提供 fernet 密钥的轮换以及它们后续同步到其他 keystone units 的功能。
还有一些关于应该配置哪些方面与由 charm 控制的方面的问题。 Proposed Change 部分提供了更多细节。
最后,讨论了将现有的 OpenStack 实现从其他 token 系统升级到 Fernet token 的方法,以及 charm 需要实现以支持此操作的功能,以及文档。
提议的变更¶
工作原理¶
keystone-charm 将在适当的配置选项下,配置 keystone 以生成 fernet token。
为了生成 token,fernet 密钥被使用。这些密钥由 keystone 生成,并具有过期日期。密钥仓库是一个目录,每个密钥都是一个整数,最高的数字是主密钥。密钥 ‘0’ 是暂存密钥,将成为下一个主密钥。其他密钥是辅助密钥。
新 token 仅从主密钥生成,而辅助密钥用于验证现有 token。暂存密钥不用于生成 token,但可用于验证 token,因为暂存密钥可能是由于轮换导致的主密钥,并且密钥尚未同步到所有 units。
Fernet 密钥需要定期轮换,并且密钥需要同步到每个其他 keystone unit。密钥应仅在主 keystone unit 上轮换,并且必须在再次轮换之前同步。如果在另一个 unit 上无法解码在主 unit 上生成的 token,则会发生“过度轮换”,如果主 unit 上执行了两次密钥轮换,但尚未成功执行同步,就会发生这种情况。应避免这种情况。过度轮换也可能导致在 token 过期之前删除验证密钥,从而导致验证失败。
密钥轮换策略 有 3 个部分
轮换频率
token 的生命周期(使用
[token] expiration设置)活动密钥的数量:(使用
[fernet_tokens] max_active_keys设置)
至少需要 3 个密钥。密钥的实际数量由token 生命周期和轮换频率决定。max_active_keys 必须大于token 生命周期 / 轮换频率 的值加一。
引用自 FAQ
部署中 max_active_keys 的数量可以通过将 token 生命周期(以小时为单位)除以轮换频率(以小时为单位)并加上二来确定。更形象地表达为
token_expiration = 24
rotation_frequency = 6
max_active_keys = (token_expiration / rotation_frequency) + 2
在 keystone charm 中,已经存在 token-expiration 配置参数(以秒为单位),并且将提出一个新的配置项 fernet-max-active-keys。因此,轮换频率将计算如下:
token_expiration = 24 # actually 3600, as it's in seconds
max_active_keys = 6
rotation_frequency = token_expiration / (max_active_keys - 2)
因此,fernet-max-active-keys 绝不能小于 3(将在 charm 中强制执行),这将使轮换频率与 token 过期时间相同。
升级现有系统¶
要将现有系统升级为使用 Fernet token,应首先升级 keystone charm。 (新的) 配置选项 token-provider 没有设置默认值,这意味着在 rocky 之前的安装中,token 类型将保持为 UUID。为了将 rocky 之前的安装迁移到 Fernet,应将 token-provider 选项设置为 fernet。
请注意,如果将 rocky 之前的系统升级到 rocky,则默认 token 类型将为 fernet。Rocky 周期删除了对 UUID token 的支持。因此,将系统升级到 rocky 将自动使用 fernet 作为唯一的 token 类型。 token-provider 选项仅对 rocky 之前的系统有效。
请注意,尽管 charm 默认启用使用 memcache 进行 token 缓存,但这仅适用于默认的 300 秒,因为没有设置 token_cache_time(有关更多详细信息,请参阅 (Keystone) Middleware Architecture: Improving response time)。其影响是,一些服务可能会尝试在升级期间重新进行身份验证,并且取决于它们“选择”的 keystone unit 以及升级的阶段,将决定操作是否成功。由于不同的服务可能属于同一操作,这可能会导致奇怪的故障模式。但是,一旦系统升级完成,在默认的 300 秒之后,所有服务将继续正常运行。
因此,可能存在 openstack 控制平面的感知中断。已经运行的实例不受影响,并且所有服务在从 keystone 请求新 token 后将继续正常运行。
其他配置项¶
keystone charm 需要以下配置项。
token-provider - 要使用的 token 系统:可以是 ‘uuid’ 或 ‘fernet’。默认值将不会设置。Rocky 之前的系统默认值为
uuid。在 rocky 系统上,配置选项无效。由于 rocky 之前的系统的默认值为uuid,因此除非操作员设置配置值为fernet,否则 token-provider 不会更改。fernet-max-active-keys - keystone 中配置的最大活动密钥数。这基于此配置项和配置项 token-expiration 控制密钥轮换触发时间。
Keystone 操作¶
将需要以下操作
purge-tokens – 从数据库中清除现有 token。这用于从
UUID升级到Fernettoken 后使用。
内部 Cron 作业¶
charm 将设置一个 cron 作业来轮换密钥,然后将它们同步到其他对等 unit。cron 作业将从 charm 内部调用 juju run 来轮换密钥,然后将密钥同步到其他对等 unit。它还将仅在它是 leader 时才执行此操作。cron 作业将在所有对等 unit 上运行,但仅对 leader 有效。
Fernet 密钥的同步将通过 Juju leader 设置进行。密钥很小,“leader 设置”提供了一种方便且安全的机制,可以在所有 keystone 对等 unit 之间同步密钥,而无需显式提供所有 keystone 对等 unit 的网络。使用 hooks 传输密钥的延迟不是问题,因为同步不需要立即进行;实际上,在最坏的情况下,它可能只是在下一次密钥轮换之前,尽管,这不太可能发生。
备选方案¶
在 Openstack rocky 版本中,fernet 是唯一可用的 token 提供程序。因此,没有其他选择。
实现¶
负责人¶
- 主要负责人
ajkavanagh
- 次要分配人
fnordahl
Gerrit Topic¶
使用 Gerrit topic “fernet-keystone-charm” 用于与此规范相关的所有补丁。
git-review -t fernet-keystone-charm
工作项¶
将 fernet token 功能添加到 keystone-charm 中。包括:* 设置 * 升级 * 轮换/同步操作 * 自动轮换/同步的 cron 作业。
将 Fernet token 信息添加到文档中:* keystone charm 的 charm-store 文本 * charm 指南中关于 uuid 与 Fernet 的说明。
更新测试:* Amulet/bundle 用于操作/验证安装。* 更新其他 bundle 以确保默认值 * 从 uuid 升级到 Fernet token。
仓库¶
不需要新的 git 仓库。
文档¶
文档将作为 keystone charm 的一部分提供,并在 charm 指南中提供说明。
安全性¶
更改 token 提供程序具有安全影响,并且将实施经过充分测试和证明的最佳实践,以使用 fernet token 提供程序。
测试¶
将开发单元测试以及新代码。将实施功能测试。还将编写更改 token 提供程序的场景测试。
依赖项¶
没有外部依赖项。