幕后的故事:我们如何构建密码角色
我们最近发布了一项新功能,使你可以为数据库密码定义更加精细化的角色。当你生成一个新密码时,可以选择以下角色:**只读 (read-only)**、**只写 (write-only)**、**读写 (read/write)** 和 **管理员 (admin)**。
我们使用 Vitess 的访问控制列表 (Access Control Lists) 和 VTTablet 实现了密码角色,但在开发途中遇到了一些挑战。在本文中,我们将回顾实现过程中面临的问题,以及我们如何克服这些问题。
Vitess 如何处理用户授权
Vitess 通过一个静态配置文件为其 vttablet 提供授权支持。以下显示了这个文件的示例:
{ "table_groups": [ { "name": "planetscale user groups", "table_names_or_prefixes": ["%"], "readers": ["planetscale-reader", "planetscale-writer", "planetscale-admin"], "writers": ["planetscale-writer", "planetscale-writer-only", "planetscale-admin"], "admins": ["planetscale-admin"] } ] }
分析 ACL 配置文件
- table_names_or_prefixes:适用于该策略的表列表。
%
表示所有表。 - readers:可以从数据库中的表和视图读取数据及架构的用户集合。
- writers:可以向数据库中的表写入数据的用户集合。
- admins:可以读取、更新数据并修改数据库架构的用户集合。
虽然这个配置是静态的,但 Vitess 允许你通过使用 --table-acl-config-reload-interval
参数,在特定时间间隔下从磁盘重新加载此文件,从而在 vttablet 的运行时动态调整此列表。
这种静态文件方式适合以下情况的用户:
- 用户已预先定义:数据库访问的用户集是已知的,并且维护配置文件中的访问组比较简单。
- ACL 配置文件数量较少:每个 Vitess 集群有少量定制的 ACL 配置文件。
- 维护时间表可控:更新 Vitess 部署的 pod/共享卷上的文件有明确的维护计划。
为什么这方法不适合 PlanetScale?
上述条件并不适用于 PlanetScale 的客户。作为设计原则,我们尽量避免在 vttablet pod 自身上存储认证和授权状态。
依赖 vttablet pod 上文件的刷新间隔可能会导致多种问题。以下是一些示例:
- 无法立即启用新密码
我们希望能够实现”客户创建带角色的密码,并立即生效”的用户故事,这要求密码无需依赖 vttablet 的定时刷新循环。由于无法预测文件的下次刷新时间,我们无法保证新凭证能够立即生效。
- 不同 pod 的状态可能冲突
负责管理 vttablet 的操作人员需要向 pod 写入文件,但可能无法同时更新所有 vttablet pod,这可能导致使用某个凭证时出现竞态条件。例如,同一密码在一个 pod 上可能是管理员角色,而在另一个 pod 上可能是只读角色。
- 服务重启后的状态恢复问题
如果 pod 出现故障并需要重启,我们没有外部 ACL 存储来确定每个数据库应该具有的 ACL 状态,从而在启动之前无法恢复权限状态。
- 独立维护每个数据库的状态
我们需要为每个客户数据库维护一套单独的状态,无法与其他 PlanetScale 数据库共享统一状态。
考虑到这些问题,我们提出了一个解决方案,为客户提供他们期望的无缝 PlanetScale 用户体验。
我们如何使用静态 ACL 文件实现密码角色
对于用户创建的每个密码,我们会在凭证数据库中存储以下信息:
| 显示名称 (Display name) | 角色 (Role) | password_sha1_hash | password_sha2_hash |
角色属性决定你将映射到的三个 vttablet ACL 角色(**readers**、**writers** 或 **admins**)中的哪个。
例如,如果你创建了只写的密码并连接到你的 PlanetScale 数据库,查询将通过用户查询前端(一个负责 PlanetScale 数据库用户交互功能的服务)。如下图所示,我们的解决方案能够解决之前部分中讨论的所有问题:
ACL 转换示意图
我们的解决方案优势
- 动态用户凭证存储
动态用户凭证存储允许我们即时创建或删除用户角色映射,无需依赖刷新间隔。
- 预定义用户名与角色映射
我们已预定义一组用户名,这些用户名描述了各角色支持的权限,例如 planetscale-reader
仅能读取数据和架构。通过将所有 PlanetScale 用户的角色映射到 Vitess ACL 配置中的用户名,我们可以”即时”重写安全主体,让数据库连接获得正确的访问级别。
- 统一的 ACL 状态
由于所有认证和授权数据都存储在外部数据存储中,我们为某个数据库创建的所有 pods 都会拥有相同的 ACL 状态。
- 简化问题调试
由于基础 ACL 配置在所有 PlanetScale 数据库中都是统一的,因此调试 ACL 执行中的问题以及修复过程变得更加简单。
关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台
除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接
本文链接:http://www.choupangxia.com/2025/09/07/behind-the-scenes/