secret-manager 存储加密的应用程序密钥,并将其暴露给经过身份验证的用户和显式授权的插件。
它是一个 WASM 插件,因此它使用与其他 WASM 插件相同的插件契约和主机回调。
插件标识
插件名称用于插件配置、插件消息的目标以及各个密钥的访问策略。
配置
标准插件设置在[Plugins.secret-manager] 下配置:
Params 通过插件的 RegisterRequest 传递给插件。插件使用以下参数名称:
插件会将更改保存到其自身的显式
Params 部分。它不会将这些值写入共享的 KV 存储。宿主程序会将参数补丁应用到当前配置,并刷新插件管理器的配置快照;插件也会更新其内存中的副本。
请将 secretmgr.identity 和所有 secretmgr.secret.* 值视为敏感信息。
identity 是一个私钥,而 secret 参数包含加密的秘密信息,这些信息不应在日志或常规配置诊断中暴露。
通过环境变量提供 identity
identity 参数支持内核的环境变量引用语法。为了避免将私钥写入配置文件,请将私钥的值存储在环境变量中,并在Params 中引用它:
Params 传递给插件之前解析 env://SECRET_KEY。
引用时必须不带尾随的 ?,这样如果未设置 SECRET_KEY,
参数解析将失败,并且 secret-manager 无法启动。这比在加密数据已存在时静默生成新 identity 要好。
首次安装且未设置 secretmgr.identity 参数时,插件会生成一个 X25519 identity,并通过 PatchParams 将其持久化。
然后,您可以将生成的身份验证信息移动到受保护的环境变量中,设置 secretmgr.identity = env://SECRET_KEY,并使用 SECRET_KEY 启动应用程序。
请务必使用相同的 identity:使用新生成的密钥无法解密经过 identity 加密的密钥。
如果 identity 必须直接存储在配置中,则仍然可以使用 scrypt 加密和密码短语保护各个密钥值,这样配置中包含的将是密文而不是明文密钥值。
当前插件不接受使用密码短语包装的 secretmgr.identity 值;该参数必须解析为原始 identity。解密经过密码短语加密的密钥仍然需要 identity。
密钥元数据
每个secretmgr.meta.<name> 值都具有以下格式:
encryption 可以是 identity 或 scrypt。
allowed_plugins 和 updated_at 字段也保留在 HTTP API 返回的元数据中。
策略中的插件名称将与内核中经过身份验证的源名称进行比较。
密钥名称
密钥名称在截断后必须为 1-128 个字符。它们可以包含 ASCII 字符: 字母、数字、/、_、- 和 .,但不能包含 ..。
空名称以及包含任何其他字符的名称将被拒绝。
加密
插件存储使用标准 Base64 编码的密文。
密码永远不会被持久化。忘记密码会导致
scrypt 密钥无法恢复。Scrypt 使用故意耗时且内存密集型的计算从密码派生加密密钥。
这使得每次离线密码猜测的成本更高,因此基于密码短语的加密方式比使用存储的 X25519 身份信息要慢。当额外的延迟可以接受时,请选择这种方式。
经过身份验证的 HTTP API 和插件间的 IPC 接口都可以在调用者提供密码短语时检索 scrypt 加密的密钥。
如果没有正确的 secretmgr.identity,则无法解密使用 identity 加密的密钥。
密文不足以恢复密钥。
解密过程中接受的最大明文大小为 1 MiB。
HTTP API
所有已注册的 HTTP 路由都需要经过身份验证的用户。该插件返回的 JSON 数据包含:Content-Type: application/json; charset=utf-8 和 Cache-Control: no-store。
列出密钥
添加密钥
passphrase 为可选。空值表示选择 identity 加密。
非空值表示选择 scrypt 加密。allowed_plugins 可以为空,
这意味着任何插件都无法通过进程间通信 (IPC) 获取密钥。
成功返回 HTTP 201 Created:
400 Bad Request;如果密钥已存在,则返回 409 Conflict;如果加密或持久化失败,则返回 500 Internal Server Error。
更新密钥
/keys/add 相同的字段。name 用于标识现有的密钥,且无法更改。
要在更改元数据或访问策略的同时保留现有密文,请将 value 设置为单个字符*,并将 passphrase 留空。
如果提供带有此标记的密码短语,则请求将被拒绝。
成功返回 HTTP 200 OK,格式与 { "success": true, "name": "..." } 相同。
未知密钥返回 404 Not Found;格式错误的输入或无效的策略返回 400 Bad Request。
揭示密钥
scrypt 加密时,必须填写密码短语;对于 identity 密钥,密码短语必须为空。成功返回明文:
400 Bad Request。
如果缺少密钥或其他解密失败,则返回 404 Not Found。
删除密钥
200 OK:
400 Bad Request 错误。
插件消息 API
插件间消息检索使用内核的同步插件消息传输。目标插件名称为secret-manager,支持的主题为:
allowed_plugins 列表中。对于 identity 密钥,密码短语可以为空;对于 scrypt 密钥,密码短语是必需的。
内核会将消息的 source 设置为发送者的注册名称;调用者无法伪造此字段。
成功后,回复会将明文内容放入 message 中:
error 中放置描述,并且不会返回密钥值:
scrypt 密码短语以及无效的密码短语。
有关通用消息信封和主机认证来源的行为,请参阅
插件消息。
KV 和其他插件接口
secret-manager 不使用共享的 KV 存储来存储密钥数据。
使用者不得在 KV 命名空间中查找密钥;请使用 HTTP。 API 或插件上述消息主题。
该插件未声明 Socket.IO 命名空间或事件。其与宿主的交互仅限于:
- 在注册期间接收
Params; - 使用宿主的
PatchParams回调来持久化身份和密钥的更改; - 处理已认证的 HTTP 请求;
- 接收已认证的插件消息。
安全注意事项
- 仅将 HTTP 端点用于已认证的管理访问。
- 优先使用插件消息进行服务间访问,并将每个密钥仅授予需要它的插件名称。
- 将插件消息回复视为明文密钥材料。
- 为每次
scrypt检索提供密码短语,并且绝不将其记录或持久化到调用插件中。 - 不要在日志中附加请求正文、密码短语、解密值、身份或密文参数。