Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help


id: ADR-013 title: 主密钥获取使用一个已配置的密钥源权威 date: 2026-07-25 status: 提议 relates-to:

  • https://github.com/zeroclaw-labs/zeroclaw/issues/9127
  • https://github.com/zeroclaw-labs/zeroclaw/pull/9194
  • docs/book/src/security/model.md
  • docs/book/src/architecture/config-lifecycle.md
  • crates/zeroclaw-config/src/secrets.rs

ADR-013:主密钥获取使用单一已配置的密钥源权威

上下文

启用机密加密后,ZeroClaw 通常会以 enc2: 格式持久化非空的 #[secret] 值,并为每个配置根目录使用一个主密钥。当前实现从 .secret_key 获取该密钥;这是一个由文件系统权限保护的明文十六进制文件。对于本地开发以及挂载受保护密钥材料的部署,这一默认方式很实用,但无法支持操作系统密钥链、由口令派生的密钥或外部机密系统。

密钥位置只是契约的一部分。每个生产使用方都必须明确哪个来源负责管理密钥、首次使用时的配置与暂时不可用有何不同,以及配置的来源无法提供预期密钥时应如何处理。在规范的机密信息边界之外直接读取 .secret_key、隐式回退到其他来源,或不安全地切换后端,都可能导致现有密文无法读取,或削弱部署预期的保护措施。

RFC #9127 定义了分阶段的密钥来源架构。初始实现 #9194 提取了文件来源,并强化了原子性、不可替换且不跟随符号链接的密钥文件发布,同时保留配置和密文语义。此强化可能需要特定目标平台的底层依赖;#9460 跟踪剩余的 Windows 创建时 ACL 边界。本记录记录了长期目标,但不声称已交付已配置的非文件来源或迁移支持。

决策

使用一个规范的密钥源边界

主密钥的获取由配置和机密子系统中的 KeySource 边界负责。SecretStore 以及实际生产中使用部署密钥材料的所有其他组件都必须使用该边界,而不能直接读取 .secret_key、调用平台存储,或缓存独立获取的密钥。

一次部署中,只有一个已配置的源是权威源。文件源仍是向后兼容的默认源。添加其他源不得更改 enc2: 密文格式或 ChaCha20-Poly1305 加密契约。

源选择通过规范的类型化 Config 解析,并以 Config::install_root_dir() 为锚点。二进制和运行时组装层为每一代进程构建一个共享的源权威对象,并将其注入 SecretStore 以及其他所有密钥使用方。使用方可以克隆该权威对象,但不得选择根目录、从保留的密钥配置快照重建权威对象,也不得直接读取后端材料。独立进程以确定性方式解析相同的已配置权威;后端缓存仍为进程本地。

非加密使用方是获得对源的限定范围访问权限,还是派生用于特定目的的子密钥,这是一个独立的安全决策。本 ADR 要求采用规范化的获取方式,但不为 TUI 身份签名或其他协议选择派生方案或兼容性契约。在该决策被记录之前,非加密使用方不得静默重用原始加密主密钥。

边界可能仅在同步操作期间暴露密钥字节。这是正确性和生命周期约束,而非沙箱:在该操作内执行的代码仍可能复制这些字节。实现必须尽量减少复制,并在平台和依赖模型允许的情况下清除临时数据。

此原始密钥边界仅适用于能够返回可导出的 32 字节密钥材料的源。不可导出的安全元件提供的是加密操作而非密钥字节,因此需要单独基于操作的边界和架构决策。

将预配状态与可用性分离

源必须区分以下状态:

  • 本地密钥材料存在且可以验证;
  • 本地密钥材料需要初始化;或者
  • 密钥材料由外部提供,本地无法进行有意义的存在性检查。

本地预配探测不得意外执行辅助程序、联系网络服务、提示用户或解锁钥匙串。实际的密钥访问是单独的操作,可能会因配置的来源不可用、已锁定、配置错误或返回错误的密钥而失败。

初始化仅会为明确支持创建密钥材料的源创建新的密钥材料。文件初始化必须发布一个完整的限制性文件,不能替换现有材料,也不能接受符号链接重定向。轮换不是初始化,而是需要单独执行的受保护操作。

故障时默认拒绝,但不改变权限

当启用的功能需要已配置的密钥而密钥源无法提供该密钥时,该功能的启动或凭据操作必须失败,并提供安全的、特定于密钥源的诊断信息。ZeroClaw 不得静默回退到 .secret_key、生成替代材料或尝试其他后端。原始密钥字节以及可能包含这些字节的辅助程序输出不得出现在日志或返回的错误中。

配置源获取失败不得隐式选择未签名的 TUI 身份。如果仍支持未签名的 TUI 身份,则必须将其作为由操作员显式选择的策略,并拥有自身的威胁模型、诊断和测试。当配置了签名身份时,无法获取其密钥必须导致受影响的启动或连接失败。TUI 签名是获得受限范围的源访问权限,还是派生用途专用密钥,仍属于独立的安全决策。

源实现必须说明其威胁模型和运行依赖项。操作系统密钥链无法保护已遭入侵的 ZeroClaw 进程;密码短语来源依赖于用户交互和密码强度;外部辅助程序依赖于其可执行文件、环境、传输机制以及上游机密系统。仅凭后端名称并不能构成安全保证。

外部辅助程序在实现后,会运行显式配置的绝对路径可执行文件,且不经过 shell 中间层。初始契约不接受任何参数;后续支持参数需要单独审查,并且必须分别表示各个值,而不是解析 shell 命令。执行受超时限制,实现会在超时或退出时保留并回收子进程。辅助程序恰好返回一个 32 字节的密钥,格式为 64 个小写十六进制字符;原始 stdout 和 stderr 绝不会写入日志或返回的错误。初始契约会继承进程环境,并且必须记录这一暴露。重试和缓存均有界,过期的密钥材料会被清除,刷新失败仍保持失败关闭。

将迁移与轮换分开

将同一个主密钥移动到另一个来源称为迁移。生成新密钥并重新加密每个受保护值称为轮换。两者具有不同的失败和回滚规则,不得表示为一个通用的后端变更。

在存在加密值时更改已配置的源需要一条经过验证的迁移路径。在迁移工具发布之前,ZeroClaw 必须拒绝无法证明能够访问用于解密现有 enc2: 值的密钥的源更改。迁移必须保留旧源,直到新源已成功写入并读回。轮换必须保留旧密钥和原始配置,直到所有值都已重新加密且新配置以原子方式提交。

zeroclaw secrets migrate 必须随使第一个非文件源可供选择的变更一起或更早发布。每个后续源都必须具备受支持的迁移路径,然后操作员才能选择它。无法导入现有主密钥的源(例如纯粹由口令短语派生的源)需要采用单独审查的轮换路径,而不能假装可以进行相同密钥迁移。

迁移和轮换必须清点所有持久化保存 SecretStore 密文的位置。初始清单包括配置 TOML 以及生成或迁移的配置输出、<install>/auth-profiles.json<install>/auth-<provider>-pending.json<install>/otp-secret<data>/webauthn_credentials.json。未来写入 enc2: 值的持久化存储也应纳入同一清单。构造存储时如果不添加持久化密文格式,则不会产生另一个迁移存储方。

密钥源选择不会通过本决策实时生效。已保存的源更改只有在迁移验证完成并完整重载守护进程或重启进程后才会生效。任何未来的实时移交都必须在单独的实现决策中定义代际隔离机制。

按安全顺序采用该边界

文件源提取首先落地,且不改变配置或密文语义。它可以在保留文件后端作为兼容性基线的同时,加强密钥文件的创建和发布,并引入特定目标的底层依赖。接下来,生产使用方和故障关闭式源选择将移到该边界之后。迁移工具必须不晚于首个可选择的非文件源落地。随后,非文件源将逐一落地,并配备源特定的威胁模型、过渡支持和测试。通用密钥轮换仍将作为单独审查的流程。

此 ADR 在满足以下所有条件之前仍处于提议状态:

  • 文件源保留了与现有 .secret_keyenc2: 数据的兼容性,可针对字面形式的提取前密钥和密文测试固定数据进行验证,并在发布新的密钥文件时不替换现有文件或跟随符号链接;
  • 规范的类型化配置选择源和安装根目录,二进制或运行时组装层会在每个进程代中向所有生产消费者注入一个共享的权威;
  • 配置恰好选择一个来源,默认采用文件来源以保持兼容,并在没有回退或生成替代密钥的情况下安全失败;
  • 配置源失败不得隐式启用未签名的 TUI 身份;任何保留的未签名模式都是操作员的显式策略,具有自身的威胁模型、诊断和测试;
  • 预配探针区分材料缺失与检查失败,而成功的 with_key 访问会准确调用其回调一次,边界测试涵盖回调调用零次或多次,以及权限或暂时性检查失败;
  • 在首个非文件源可供选择之前,zeroclaw secrets migrate 即已可用,并且每个后续源在启用前都有经过验证的迁移或轮换路径;
  • 至少有一个受支持的非文件源证明该边界在文件实现之外同样有效;并且
  • 除非完整的持久化密文清单可以解密,或已成功完成有文档记录、具备原子性且支持回滚的迁移,否则不允许进行源切换。

后果

积极后果:

  • 桌面、服务器和容器部署可以选择与其运行环境相匹配的可导出密钥授权机构。
  • 所有凭据使用方共享唯一事实来源,并遵循同一套失败即关闭的生命周期。
  • 现有的基于文件的部署仍是兼容性基线。
  • 不得静默地混淆迁移、轮换和普通启动。

负面后果:

  • 现在,启动需要为每个源明确的预配和可用性语义。
  • 非文件源会引入文件源没有的平台依赖、提示、外部进程行为或服务可用性。
  • 当已存在加密值时,切换后端不能仅通过简单修改配置来完成。
  • 在边界完成之前,必须在所有生产使用方中查找并移除直接读取密钥文件的操作。

参考文献