RustFS KMS 管理 API 契约:路由、IAM 动作与密钥列表分页规则全解
2026/9/11 20:38:06 网站建设 项目流程

RustFS KMS 管理 API 契约:路由、IAM 动作与密钥列表分页规则全解

【免费下载链接】rustfs🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting migration and coexistence with other S3-compatible platforms such as MinIO and Ceph.项目地址: https://gitcode.com/GitHub_Trending/rus/rustfs

导读:本文以 RustFS 官方运维文档 docs/operations/kms-admin-contract.md 为骨架,系统讲解 KMS 管理面(Admin API)的完整契约:每一个/rustfs/admin/v3/kms/*端点对应的 IAM 动作、风险等级、是否为 per-key 授权,以及GET /kms/keys密钥列表的严格分页规则。无论你是要接入 CLI、控制台还是自动化脚本,还是需要编写 IAM 策略来收紧 KMS 权限,读完后都能准确判断每个路由的授权语义,并写出可正确翻页、可容忍损坏密钥记录的客户端。

适用范围与事实来源

本文适用于将客户端(CLI、控制台、自动化脚本)接入 RustFS KMS 管理端点的场景,核心需要明确三件事:每条路由所需的 IAM 动作、风险等级、以及密钥列表的分页规则。

文档的事实来源(均可直接在本仓库中核对):

  • rustfs/src/admin/route_policy.rs:每个路由的 action 与风险等级定义,由 rustfs/src/admin/route_registration_test.rs 断言保证路由注册与策略一致;
  • crates/kms/src/backends/mod.rs:DEFAULT_LIST_KEYS_PAGE_SIZEMAX_LIST_KEYS_PAGE_SIZElist_keys_page_size等分页常量与切页逻辑;
  • crates/kms/src/snapshots/ 与 rustfs/src/admin/handlers/snapshots/:各端点的响应形状由快照测试锁定。

所有 KMS 管理端点的 wire 前缀均为/rustfs/admin/v3。其中GET /kms/statusGET /kms/service-status返回不同类型的响应;/kms/status上的capabilities字段是增量式(additive)且可选的。Per-key 列表示该路由是否针对其命名的密钥进行授权(详见 Per-key KMS 授权);值为no表示该路由匹配调用者策略中的任意 KMS 资源。

端点矩阵:完整路由、动作与风险等级

下表是全部 KMS 管理端点的权威清单,来自 rustfs/src/admin/route_policy.rs 中ADMIN_ROUTE_POLICY_SPECS的 KMS 段落(route_policy.rs 第 816-939 行),与原文档逐条对应:

Method and endpointIAM actionRiskPer-keyNotes
POST /kms/configurekms:Configurehighno持久化到集群存储、切换本节点、向对端广播尽力而为的重载
POST /kms/reconfigurekms:Configurehighno与 configure 契约相同
POST /kms/startkms:ServiceControlhighno
POST /kms/stopkms:ServiceControlhighno
POST /kms/reloadkms:ServiceControlhighno重新读取持久化配置而不重新提交密钥;复用 configure 的响应形状
GET /kms/statuskms:ServiceControlsensitiveno后端类型加能力矩阵
POST /kms/statuskms:ServiceControlhighno兼容路由;不是客户端命令
GET /kms/service-statuskms:ServiceControlsensitiveno携带cluster_config指纹与consistent标志
GET /kms/configkms:Configuresensitiveno包含运维路径;展示前必须脱敏
POST /kms/clear-cachekms:ClearCachehighno返回KmsClearCacheResponse{status,message}
POST /kms/keyskms:Configurehighno创建密钥与配置共用 Configure 动作
GET /kms/keyskms:ListKeyssensitiveno见下文密钥列表契约
GET /kms/keys/{key_id}kms:DescribeKeysensitiveyes?impact=true可选返回配置引用报告
DELETE /kms/keys/deletekms:DeleteKeycriticalyesJSON body;force_immediate还需要confirm_key_id和服务端RUSTFS_KMS_ALLOW_IMMEDIATE_DELETION开关
POST /kms/keys/cancel-deletionkms:DeleteKeyhighyes
POST /kms/keys/enablekms:EnableKeyhighyes
POST /kms/keys/disablekms:DisableKeyhighyes
POST /kms/keys/rotatekms:RotateKeyhighyes受 KMS 后端安全属性 中的轮换约束约束
POST /kms/keys/rekeykms:Rekeyhighno批量 DEK 重包裹扫描;集群范围,见 KMS 批量 Rekey 契约
GET /kms/keys/rekey/statuskms:Rekeysensitiveno
POST /kms/keys/rekey/cancelkms:Rekeyhighno
POST /kms/keys/update-descriptionkms:UpdateKeyDescriptionhighyes
POST /kms/keys/tagkms:TagResourcehighyes
POST /kms/keys/untagkms:UntagResourcehighyes
POST /kms/generate-data-keykms:GenerateDataKeyhighyes响应携带 base64 明文数据密钥;绝不可在 UI 或 CLI 中展示
GET /kms/backupkms:Backupsensitiveno仅状态与就绪信息;不含 KEK 材料
POST /kms/backupkms:Backuphighno仅返回backup_id与元数据
POST /kms/restore/dry-runkms:Restoresensitiveno预检;不写任何数据
POST /kms/restorekms:Restorehighno需要confirm_backup_idconfirm_conflict_policy
POST /kms/restore/abortkms:Restorehighno需要confirm_target_key_dir
POST /kms/create-key,POST /kms/key/createkms:Configurehighnomc遗留别名,等价POST /kms/keys;密钥名来自key-id查询参数(mc的形态)或name标签,两者同时携带且值不同时以400拒绝
GET /kms/describe-key,GET /kms/key/statuskms:DescribeKeysensitiveyesGET /kms/keys/{key_id}的遗留别名
GET /kms/list-keyskms:ListKeyssensitivenoGET /kms/keys的遗留别名;列表契约相同

注意上表中的端点均省略了统一前缀/rustfs/admin/v3,实际请求形如POST /rustfs/admin/v3/kms/configure

风险等级背后的设计意图

风险等级不是随意标注的,源码注释直接给出了理由,理解它有助于在接入时正确对待每个端点:

  • DELETE /kms/keys/delete是唯一一个critical级别的 KMS 路由。源码注释(route_policy.rs 第 868-878 行)明确指出:销毁主密钥会让所有在其下加密的对象永久不可读,且服务端没有任何机制能恢复这些对象。等待窗口(pending-deletion)与 cancel-deletion 是唯一的恢复路径——这正是POST /kms/keys/cancel-deletion只保持high级别的原因;
  • POST /kms/keys/rekey使用独立的集群范围kms:Rekey动作,而不是复用某个 per-key 动作。源码注释(route_policy.rs 第 900-901 行)说明:rekey 扫描会跨 bucket 遍历并重写对象元数据,因此需要独立的集群级授权;
  • kms:Backupkms:Restore同样使用独立动作,因为它们作用于所有密钥的材料,而非某个具体密钥(route_policy.rs 第 915-916 行);
  • 密钥创建与后端配置共用kms:Configure,这意味着“创建密钥”在权限模型上是集群管理员的职责,而不是密钥管理者的职责(见 Per-key KMS 授权 的说明)。

各端点组的职责划分

从端点矩阵可以清晰地划分出四组职责:

  1. 服务控制组kms:ServiceControl):start/stop/reload/status/service-status,负责 KMS 服务的启停、配置重载与状态查看。其中service-status返回的cluster_config携带每个节点的配置指纹与consistent标志,可用于检测集群内 KMS 配置分叉(详见 KMS 后端安全属性);
  2. 密钥生命周期组(per-key 动作):创建(kms:Configure)、DescribeKeyEnableKeyDisableKeyRotateKeyDeleteKeyUpdateKeyDescriptionTagResource/UntagResource,以及批量Rekey
  3. 数据密钥组generate-data-keykms:GenerateDataKey),是 SSE-KMS 数据路径的核心动作;
  4. 备份恢复组kms:Backup/kms:Restore):backup、restore/dry-run、restore、restore/abort,以及clear-cachekms:ClearCache)。

Per-key 授权:谁可以对哪个密钥做什么

端点矩阵中的Per-key列是本契约的核心概念之一:值为yes的路由会针对请求命名的那个密钥进行授权。密钥标识取自请求体的key_id字段,回退到keyId查询参数。而值为no的路由(如GET /kms/keys)匹配调用者策略中的任意 KMS 资源。

RustFS 的 KMS 授权基于身份策略(identity policy),一条语句可以限定其适用的密钥,因此授予kms:DisableKey不再意味着对集群内所有密钥生效。KMS 资源使用与 S3 相同的空账号 ARN 形态:

模式匹配
arn:aws:kms:::key/<key_id>恰好该密钥
arn:aws:kms:::key/app-*所有以app-开头的密钥 id
arn:aws:kms:::*所有密钥
arn:aws:kms:::alias/<name>保留;别名解析落地前不匹配任何内容

编写策略时有几条硬规则:混用kms:s3:动作的语句会被拒绝;携带 KMS 资源但动作不是 KMS 动作的语句会被拒绝;Deny优先于Allow。仓库内置了三个 KMS 角色模板:KMSKeyAdministrator(密钥生命周期治理)、KMSKeyUser(读写 SSE-KMS 对象的工作负载)、KMSAuditor(仅可见性)。三者均不授予kms:Configurekms:ServiceControlkms:ClearCachekms:Backupkms:Restore,这些集群管理权限保留给consoleAdmin——这与本文端点矩阵中 per-key 动作与集群动作的划分完全一致。详细的资源语法、模板清单与 SSE-KMS 数据路径强制(RUSTFS_KMS_ENFORCE_SSE_KEY_POLICY)参见 Per-key KMS 授权。

密钥列表契约:GET /kms/keys

GET /kms/keys(以及遗留别名GET /kms/list-keys)共享同一个列表契约。这条契约是接入 KMS 客户端时最容易出错的部分,下面逐条展开。

limit:缺省、非法值与上限

  • limit可选参数。缺省时服务端应用DEFAULT_LIST_KEYS_PAGE_SIZE100);
  • 一旦提供,就必须能解析为非负整数:limit=abclimit=-1以及无值的limit都会以400拒绝,而不会静默按缺省值处理;
  • limit=0是合法的“请求空页”请求,返回空页;
  • 任何超过MAX_LIST_KEYS_PAGE_SIZE1000)的页大小都被按 1000 提供——响应带truncated和可用的next_marker,因此只要客户端一直翻页直到truncated为 false,仍能到达每一个密钥;
  • 客户端绝不能假设返回的页就是它请求的大小

源码实现印证了这些规则。在 crates/kms/src/backends/mod.rs 第 163-172 行 中,两个常量被明确定义:

pub(crate) const DEFAULT_LIST_KEYS_PAGE_SIZE: u32 = 100; pub(crate) const MAX_LIST_KEYS_PAGE_SIZE: u32 = 1_000;

list_keys_page_size(mod.rs 第 244-249 行)实现了解析逻辑:Some(0)返回None表示“请求了零个密钥”,大于上限的值被 clamp 到上限而非拒绝。该函数带有单元测试覆盖(mod.rs 第 1001-1041 行),包括limit=0u32::MAXclamp 到 1000 等边界。

常量注释解释了为何必须设上限:一页并不是廉价的切片——列出的每个标识符都要消耗后端一次元数据查找(Local 上是磁盘读,Vault Transit 上是 HTTP 往返),无界的limit会把一次请求变成对密钥存储的无界扇出(fan-out)。上限在切页处统一应用,任何后端都无法绕过。

marker:不透明的游标

marker对客户端是不透明的:应把它当作一个原样回传的游标,绝不能当作可以自行构造的值。具体语义因后端而异:

  • Local、Vault KV2、Vault Transit、Static后端上,它恰好是密钥标识符的排他下界(exclusive lower bound)——这正是分页能在列表过程中经受密钥创建/销毁而不出错的原因;
  • AWS后端上,它是 AWS 自己的分页令牌,向其发送密钥 id 会被拒绝;
  • marker等价于没有 marker

分页的实现位于paginate_keys(mod.rs 第 201-231 行):通过partition_point找到第一个大于 marker 的标识符作为起点,next_marker取当前页最后一个标识符。注释特别强调:marker 是标识符上的排他下界而非序列索引,因此密钥在排序中的任何位置被新增或删除——包括 marker 指向的密钥本身被删除——都不会导致列表跳过密钥或从头开始。

过滤器(filter)在切页之后应用,因此被过滤后的页可能很短——甚至为空——而后面仍有更多密钥。客户端必须翻页直到truncated为 false,而不是直到某页返回变短为止。

unreadable_key_ids:损坏密钥的诚实报告

unreadable_key_ids仅当服务端列出了某个密钥但其记录无法描述时出现——例如由更新版本构建写入的记录,或已损坏的材料。关键设计原则是:

  • 这些标识符被报告而非省略,因此列表永远不会悄悄低估密钥集合;展示清单的客户端应将其标记为损坏而不是丢弃;
  • 分页总是越过损坏密钥继续前进;
  • 与具体密钥无关的失败(超时、5xx、权限拒绝)仍会使整个列表失败,而不会出现在此字段中。

该字段的定义位于 crates/kms/src/types.rs 第 491-510 行 的ListKeysResponse结构:包含keysnext_markertruncatedunreadable_key_ids四个字段。类型注释解释了其存在理由:无法解释的密钥记录绝不能从keys中悄然消失,否则库存会误读为“你没有这个密钥”,而删除扫描的普查也会基于一个从未完整看到的密钥集合进行。后端层面对应的分类逻辑在 mod.rs 第 266-276 行 的ListedKeyFailure枚举中:Vanished(密钥在扫描与读取之间消失,正常现象,丢弃并前进)与Unreadable(记录仍在存储中但当前构建无法解释,通过unreadable_key_ids上报而非省略或变成整页失败)。

响应形状由快照锁定:参见 rustfs__admin__handlers__kms_keys__tests__kms_admin_list_keys_response_with_unreadable_keys.snap 与 rustfs__admin__handlers__kms_keys__tests__kms_admin_list_keys_api_response.snap。

一个刻意的错误而非报告:全空且不可读

有一个场景被刻意设计为错误而不是报告:一次覆盖了整个密钥集合的列表——即没有markertruncated为 false——其中没有任何密钥可读。此时若返回空的keys数组,任何在此字段出现之前编写的客户端都无法区分“没有密钥的部署”和“全部损坏的部署”,而前者通常的处理方式是去新建密钥。因此这种情况返回500,并指名第一个失败;具体标识符记录在服务端日志中。

而截断的页或从 marker 恢复的页总是报告而非失败,所以损坏的密钥永远不会“卡住”它后面的密钥。

相关文档导航

本契约与以下运维文档紧密关联,接入或排障时可组合阅读:

  • KMS 管理 API 契约(本文档):路由、动作与分页规则;
  • Per-key KMS 授权:资源语法、内置角色模板、SSE-KMS 数据路径强制与迁移路径;
  • KMS 后端安全属性:主密钥轮换、保留、销毁与升级顺序,各后端的能力与保密边界;
  • KMS 批量 Rekey 契约:POST /kms/keys/rekey批量重包裹作业的完整验收标准;
  • Vault KMS 认证手册:Vault 凭证来源、刷新与 fail-closed 窗口;
  • KMS 可观测性手册:KmsKeyRotationOverdue等告警与监控指标;
  • KMS 灾难恢复演练:密钥目录与备份恢复的演练流程。

接入时建议遵循的实践要点:客户端永远按truncated翻页;对unreadable_key_ids以“损坏”呈现而非丢弃;对GET /kms/statusGET /kms/service-status分别处理两种不同的响应类型;在展示GET /kms/config结果前先脱敏;generate-data-key返回的明文数据密钥绝不落入 UI 或日志。

【免费下载链接】rustfs🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting migration and coexistence with other S3-compatible platforms such as MinIO and Ceph.项目地址: https://gitcode.com/GitHub_Trending/rus/rustfs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询