跳至主要内容 跳至导航 跳至页脚

配置存储

支持通行密钥、主密码和恢复码解锁的客户端加密配置同步

配置存储

配置存储在各设备之间同步CLI配置。配置在设备端使用服务器永远不会持有的内容加密密钥(CEK)加密。安全性一节准确说明了这能防住什么、不能防住什么。

解锁方式(密钥槽)

每个存储只有一个CEK,但会为每种解锁方式独立包装,类似LUKS的密钥槽机制。任意一个密钥槽都能打开同一把密钥,且可以随时添加或移除密钥槽,无需重新加密您的数据:

方式说明备注
通行密钥支持PRF扩展的WebAuthn通行密钥最强选项;由硬件保障安全
主密码您自选的密码,经PBKDF2-SHA256拉伸(60万次迭代)无需支持PRF的硬件即可使用;同时支持无浏览器的CLI注册
恢复码系统生成的 RC1-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX 格式代码仅在创建时显示一次,请妥善保存

每种方式都走同一条流程:密钥槽产出一个密钥片段,与服务器持有的密钥片段结合后解开CEK。任何一方单独持有的片段都不足以解密,密钥槽的密钥片段永远不会到达服务器。三种方式中,主密码是最弱的一种:服务器掌握了离线尝试破解密码所需的一切,因此密码必须足够强。通行密钥和恢复码密钥槽没有这个弱点。

密钥槽在门户的配置存储页面统一管理。只希望允许硬件解锁的组织可以启用要求通行密钥策略,该策略会拒绝并撤销整个存储中所有非通行密钥的密钥槽。

解锁是按设备进行的:在新设备上解锁一次后,日常的CLI操作(push/pull)就无需再触碰通行密钥或输入密码。

先决条件

  • 您的账户已启用双因素认证
  • 若使用通行密钥方式:需要支持PRF的通行密钥提供商,例如FIDO2安全密钥(如YubiKey)、iCloud Keychain、Google Password Manager、1Password或Dashlane
  • 浏览器:Chrome 133+、Edge 133+、Firefox 130+或Safari 17+

PRF要求仅适用于通行密钥这一种密钥槽。主密码和恢复码方式在任何受支持的浏览器上均可使用。

设置

  1. 在侧边栏导航至配置存储,然后点击设置配置存储
  2. 需求检查表验证您的浏览器、双因素认证和会话状态
  3. 选择第一种解锁方式,然后点击 创建配置存储:
    • 通行密钥:适用于支持 PRF 的提供商。你需要触碰安全密钥两次,一次用于注册,一次用于派生加密密钥。
    • 主密码:适用于任何浏览器,也适用于 Bitwarden 等不支持 PRF 的通行密钥提供商。
    • 可选的 恢复码:只显示一次,需要在创建存储前保存好。
  4. 设置完成。CLI 会把解锁密钥保存在操作系统的钥匙串中。

通行密钥可以稍后在 Config Storage 页面添加。请至少保留两种解锁方式,以免丢失或不受支持的验证器把你锁在外面。

PRF提供商兼容性

提供商PRF支持平台
YubiKey / FIDO2安全密钥✅Windows 11、macOS、Linux
iCloud Keychain✅macOS 15+、iOS 18+
Google Password Manager✅Android
1Password✅Android、iOS
Dashlane✅跨平台
Bitwarden扩展❌请改用主密码
Windows Hello❌不支持

无浏览器的CLI注册

没有浏览器的机器(服务器、CI运行器、执行器守护进程)可以通过主密码方式注册到已有的存储中:

rdc config remote enable --password

前提条件:

  • 已通过门户配置好主密码密钥槽(配置过程需要浏览器持有密钥,因此这一步本身无法在无浏览器环境下完成)
  • 拥有具备 config:enroll 权限范围的API令牌,用于验证此次调用

注册操作只读取数据:CLI获取该密钥槽的公开KDF参数和已包装的密钥,在本地推导出密码密钥片段,并在设备上解开CEK。该操作只授予设备解密和同步配置的能力,不会修改存储本身。

启用与离线读取

rdc config remote enable 会将当前配置连接到存储。如果存储为空,启用操作会用您当前的本地配置为存储播种:本地资源会作为存储的第一个版本被推送上去,然后再拉取回来,以验证这一往返过程无误。如果存储中已有内容,启用操作会与其进行协调,而不是直接覆盖(如果确实存在分歧,除非您传入 --force,否则操作会中止)。

启用之后,配置会保留一份完整的读取缓存,采用与任何本地配置相同的机制进行静态加密,因此即使无法连接账户服务器,存储依然可用:

  • 读取可离线进行。 缓存内容会附带过期警告输出到stderr,并标注缓存版本和时间戳(cachedVersion / cachedAt)。
  • 写入需要服务器,且在无法连接时会安全失败(fail closed)。 不存在离线写入队列:无法到达服务器的写入会直接报错并指明该服务器。只要写入命令成功返回,改动就已经在服务器上了。
  • 来自两台机器的并发编辑通过拉取-重放-再推送(pull-replay-repush)解决:服务器只接受建立在被替换版本之上的推送,落败的推送会在最新副本上重放,因此别处的同时编辑不会覆盖您的更改。
  • 本地配置(没有remote块的配置)不受此影响,完全可以离线工作。

同步内容

配置中的所有内容都会同步,包括每个仓库的网络ID,但以下几个设备本地字段除外:schemaVersion、version、remote、encryption、renetPath、credentials.masterPasswordVerifier,以及登录相关字段account.accountServer和account.e2ePublicKey。登录和退出登录是按设备进行的。

版本与恢复

服务器为每个配置保留最近50个版本。

rdc config remote versions
rdc config remote restore <version>

恢复操作会把旧内容作为新版本发布在当前版本之上,版本号绝不会倒退。每台设备会在下次拉取时获得恢复后的内容,恢复操作也会记录在审计日志中。

密钥轮换

轮换存储的CEK会以新的世代重新包装密钥:

  • 恢复码在轮换后总是失效,请在轮换完成后重新生成并保存新的恢复码
  • 主密码密钥槽只有在轮换向导中重新输入密码才能保留
  • 停留在旧世代的密钥槽会被报告为过期,而不是报出难以理解的解密错误
  • 其他成员的配置令牌会被吊销,仍持有旧密钥的设备会被提示通过rdc config remote enable重新启用

成员管理

配置存储按组织划定范围。成员通过Web门户管理:

  • 查看成员:配置存储 → 成员
  • 添加成员:目前仅通过CLI(Web界面计划中)
  • 移除成员:点击成员页面上的移除按钮(需要双因素认证 + 重新认证)

安全保护措施防止移除最后一个活跃成员或移除自己。

存储中的配置还会按团队划定范围,但这种划分是服务器端的访问控制,而非加密隔离:整个组织共用同一个CEK加密所有团队的配置,而某个成员能读取哪些团队的配置,由服务器强制执行。

安全性

受保护的内容。 存储的配置能够抵御服务器存储遭到入侵,以及被动的运营者。每个blob都绑定到其所属的存储、配置、团队和版本,因此服务器无法把某个配置的blob替换成另一个的,也无法在不被察觉的情况下篡改它。

不受保护的内容。 若运营者提供了恶意的门户代码,就能在浏览器中读取密钥。运营者还可以对从未见过更新版本的设备,扣留其最新版本。

服务器能做的服务器不能做的
查看配置ID、团队、版本号、时间戳、blob大小、某个配置提交了多少字段及每个字段的类型,以及客户端IP地址查看机器、仓库或存储的名称(这些已被隐去)或任何配置值
拒绝、延迟或删除配置及其历史记录在设备察觉不到的情况下,把一个配置的内容当作另一个提供,或对其进行编辑
向从未见过更新版本的设备提供旧版本向CLI提供比它已经见过的版本更旧的版本(CLI会拒绝)
离线尝试破解主密码打开通行密钥或恢复码密钥槽

其他防护措施:

  • 分割密钥:解密需要密钥槽的密钥片段(设备端)和服务器的密钥片段两者兼备
  • 删除需要知情:从配置中移除一个已提交的值,需要证明曾经知道该值,因此只有部分访问权限的代理无法悄悄删除字段
  • 轮换令牌:每次请求都会轮换配置令牌;令牌绑定到首次使用时的IP地址,并在7天后过期
  • 撤销:移除成员会同时删除其密钥槽和令牌;对方已经拉取过的内容仍留在其设备上,而CEK轮换会让其保留的密钥无法再打开之后的版本

故障排除

错误原因修复方法
PRF not supported认证器缺少PRF扩展使用YubiKey、iCloud Keychain、1Password或Dashlane,或添加一个主密码密钥槽
X25519 not supported浏览器版本过旧更新至Chrome 133+、Edge 133+、Firefox 130+或Safari 17+
Already configured您的组织已存在存储访问/account/config-storage进行管理
Config storage not configured服务器缺少blob存储联系管理员配置R2/RustFS
Token expired7天无活动,或设备更换了网络会通过登录自动刷新;如果没有已保存的登录,请运行rdc subscription login或rdc config remote enable
Config came back at an older version服务器返回的副本比该设备已经见过的版本更旧本地没有任何改动;请重试,如果持续出现请报告
Cannot remove last member将永久锁定存储先添加另一个成员
Stale slot密钥槽早于上一次密钥轮换重新添加该密钥槽(恢复码必须在每次轮换后重新生成)