响应封装(Response Wrapping)

注意:本节中介绍的一些响应封装机制只有在 Vault 0.8 之后才被引入,更早期的版本无法使用该功能。

总览

在许多 Vault 使用场景中,客户端可以直接访问 Vault 并使用返回的机密,但同时也存在我们希望只有少数受信任的实体能够访问 Vault ,由它负责将机密传递给需要使用机密的客户端的场景。

但是,经手机密的中继越多,意外泄露的可能性就越大,尤其是在机密以明文形式传输的情况下。例如,我们可能希望为一台刚刚冷启动的机器配发一个 TLS 私钥,但由于我们不想在持久存储中保存一个相应的加密密钥,导致我们无法在传输私钥到这台机器的过程中加密这个 TLS 私钥。

为帮助解决这个问题,Vault 引入了一种称为响应封装的功能。收到读取机密的请求时,Vault 可以选择不通过 HTTP 返回响应,而是将其插入一个临时的一次性令牌的 cubbyhole,并且返回这个一次性令牌。有关 cubbyhole 的知识我们会在后面的 Cubbyhole 章节进行详细介绍。

从逻辑上讲,响应被一个临时的令牌封装了,读取其中的机密需要对这个令牌进行解封操作。从功能上讲,该令牌提供了使用 Vault 中存储的的加密密钥来解密数据的授权。

在许多环境中响应封装机制提供了强大的信息共享能力。在此类场景类型中,通常最好的可行方法是为机密信息提供掩护,能够检测不当行为(拦截、篡改机密)的发生,并限制机密暴露的生命周期。响应封装执行所有这三个职责:

  1. 它通过确保通过线路传输的值不是实际的机密,而是对机密的引用(即响应封装令牌)来提供掩护。日志或信息传递链路中途被拦截的信息不会直接暴露敏感信息。
  2. 它通过确保令牌只能被打开一次来查看其中的内容,这提供了对异常行为的检测。收到无法解封的令牌的客户端可以立即触发安全警告。此外,客户端可以在解封之前检查收到的令牌,以确保其来源来自 Vault 中的预期位置。
  3. 它限制了秘密暴露的生命周期,因为响应封装令牌的生命周期与包裹其中的机密的生命周期是分离的(并且通常可以短得多),所以如果客户端未能打开并解封令牌,令牌可可以迅速过期失效。

响应封装令牌

当使用响应封装时,调用 Vault 的普通的 API 的响应不再包含原有的机密,而是与响应封装令牌有关联的一组信息:

  • TTL:响应封装令牌自身的 TTL
  • 令牌:实际的令牌值
  • 创建时间:响应封装令牌的创建时间
  • 创建路径:原请求中的 API 路径
  • 封装访问器:如果封装的响应包含的是 Vault 令牌的身份验证信息,则这是一条指向封装令牌的访问器。这使得一些任务编排系统(例如 Nomad)可以根据他们对任务生命周期的了解来控制对应机密的生命周期非常有用(在任务继续运行时持续续期所需的机密租约),而无需实际解封响应封装令牌或获取封装中的令牌 ID 的信息。

Vault 目前不支持对响应封装令牌进行签名,所以它几乎没有提供额外的保护。如果我们使用的是正确的 Vault 服务器,则通过与服务器本身交互足以验证令牌;对令牌进行签名并不能消除与服务器验证令牌的需要,因为令牌不携带数据而只是一种访问机制,服务器不会在没有验证的情况下返回数据。如果我们受到某种攻击,被欺骗使用了错误的 Vault 服务器,则同一攻击者也可以为这个伪造的 Vault 服务器提供伪造的证书。您可以缓存过去有效的密钥,也可以缓存过去有效的地址(并且在大多数情况下,Vault 地址不会更改,或是将通过服务发现机制进行配置)。因此,我们把令牌设计成本身不携带能够自证身份的数据,并且不对其进行签名。

响应封装令牌的操作

通过 sys/wrapping 路径,我们可以对响应封装令牌进行如下操作:

  • 查询(sys/wrapping/lookup):该操作可以获取响应封装令牌的创建时间、创建路径和 TTL。此路径无需身份验证,可用于查询响应包装令牌。换句话说,响应封装令牌的持有者总是可以查询令牌的信息来验证令牌有效性。
  • 解封(sys/wrapping/unwrap):解封令牌,返回内部包含的响应信息。该操作返回的内容就是原先 API 调用的响应值的原始格式,可以被 API 客户端直接使用。
  • 重新封装(sys/wrapping/rewrap):允许将封装的数据迁移到新的响应封装令牌。该操作适用于长生命周期的机密。例如,组织可能希望(或是合规要求)将 pki 后端返回的根 CA 密钥在长生命周期的响应封装令牌中返回,以确保没有人看到该 CA 密钥(通过查询响应封装信息即可确认这一点),同时也可以在证书吊销列表(CRL)发生变化时重新签署列表,或是防止 pki 挂载点意外丢失。通常来说合规要求定期轮替机密,因此这有助于实现合规目标,而无需暴露实际的内部内容。
  • 封装(sys/wrapping/wrap):一个把发送给它的数据封装进一个响应封装令牌的帮助方法。请注意,屏蔽此端点并不会关闭封装任意数据的能力,因为该功能也可以在 Vault 的其他地方完成。

创建响应封装令牌

响应封装是按请求返回的,通过向 Vault 提供一个该请求的响应封装令牌所需的 TTL 来触发,由客户端使用 X-Vault-Wrap-TTL 标头来设置,可以是整数秒或字符串持续时间,包括秒 (15s)、分钟 (20m) 或小时 (25h)。使用 Vault CLI 时,您可以通过 -wrap-ttl 参数进行设置。当使用 Go API 时,包装是通过设置一个辅助函数来触发的,该函数通过将操作和路径映射到所需的 TTL 来告诉 API 如何封装。

如果客户端请求响应封装:

  1. 原来的 HTTP 响应会被序列化
  2. 一个一次性的令牌会被创建,其 TTL 被设定为客户端提交的值
  3. 原始的 HTTP 响应被序列化后会被保存进这个一次性令牌对应的用户的 cubbyhole 存储中
  4. 一个新的 HTTP 响应会被生成,带有这个一次性令牌的 ID、TTL 以及新响应中存储信息的路径
  5. 返回这个新的响应

注意,我们可以通过策略来控制封装的最大/最小 TTL。

验证响应封装令牌

对响应封装令牌进行必要的验证可以确保及时发现入侵行为,验证过程非常直接。

验证最好由以下步骤构成:

  1. 如果客户端一直等待的传递响应封装令牌始终没有到达,可能是有攻击者拦截了令牌,然后阻止它进一步传播。这应该触发警报并立即调查。
  2. 对响应封装令牌执行查找操作。这会立即告诉我们令牌是否已被解封或已过期(或以其他方式吊销)。如果查找表明令牌无效,不一定意味着数据被拦截了(例如可能是客户端启动时间过长且 TTL 已过期),但应触发警报以立即进行调查,可以借助 Vault 的审计日志来查看令牌是否真的已经被解封。
  3. 使用所拥有的令牌信息,验证创建路径是否符合预期。如果我们希望在其中得到的是 TLS 密钥/证书,那么路径很可能应该类似于 pki/issue/...。如果创建路径与预期的不一致时(特别是以 cubbyholesys/wrapping/wrap 开头),有可能是原先的响应已被读取,然后被重新封装进一个响应封装发送给了我们。应特别注意读取 kv 机密引擎的响应,创建路径应精确匹配。例如,如果你期望一个秘密来自于 secret/foo 并且入侵者拦截的响应,并返回了一个以 secret/bar 作为路径的令牌,那么仅仅检查 secret/ 的前缀是不够的。
  4. 验证了路径前缀后,解封令牌。如果令牌解封失败,和第一步中查询令牌信息失败一样,应立即出发警报并开始调查。

results matching ""

    No results matching ""