【发布时间】:2019-01-25 09:44:52
【问题描述】:
我在 AWS 中运行了几个微服务,其中一些相互通信,其中一些具有外部客户端或作为外部服务的客户端。
为了实现我的服务,我需要一些秘密(用于签名/验证令牌的 RSA 密钥对、对称密钥、API 密钥等)。我为此使用 AWS SecretsManager,它工作正常,但我现在正在实施对密钥轮换的适当支持,我有一些想法。
- 我正在使用 AWS SecretsManager,定期(约 5 分钟)获取密钥并在本地缓存它们。
- 我正在使用 AWS SecretsManager 的版本阶段功能来根据需要引用 AWSCURRENT 和 AWSPREVIOUS 版本。
假设服务 A 需要服务 B 的密钥 K:
- 假设在开始时,K 具有当前值 K1 和先前值 K0。
- 服务 A 将始终使用(并在本地缓存)K 的 AWSCURRENT 版本与 B 通信,因此在本例中为 K1
- 服务 B 将 AWSCURRENT 和 AWSPREVIOUS 版本保留在其本地缓存中,并同时接受 [K1, K0]
- 在旋转 K 时,我首先确保服务 B 使用的密钥被旋转,这样在刷新间隔过去后,服务 B 的所有实例都接受 [K2, K1] 而不是 [K1, K0]。在刷新间隔过去之前,A 的所有实例仍使用 K1。
- 当刷新间隔过去后,这意味着 B 的所有实例都必须获取 K2,我轮换服务密钥,以便 A 将使用 K1 或 K2,直到刷新间隔结束,然后只使用 K2。
- 这样就完成了密钥轮换(但如果认为 K1 被泄露,我们可以再次轮换 B 的密钥以推出 K1 并得到 [K3, K2])。
这是最好的方法还是需要考虑其他方法?
然后,在某些情况下,我有一个在同一服务中使用的对称密钥 J,例如用于加密某些会话的密钥。因此,在对服务 C 的一次请求中,会话使用密钥 J1 加密,然后需要在稍后阶段使用 J1 解密。我有多个 C 服务实例。
这里的问题是,如果加密和解密都使用相同的密钥,旋转它会变得更加混乱 - 如果密钥旋转到具有值 J2 并且一个实例已刷新以便它将使用 J2 加密,而另一个实例仍然看不到J2,解密将失败。
我可以在这里看到一些方法:
使用单独的轮换方案将密钥拆分为两个密钥,并一次轮换一个,与上述类似。这增加了要处理的额外机密的开销,具有相同的值(除了它们之间有一段时间轮换)
-
让解密在失败时强制刷新秘密:
- 加密始终使用 AWSCURRENT(J1 或 J2,取决于是否刷新)
- 解密将尝试 AWSCURRENT 然后 AWSPREVIOUS,如果两者都失败(因为另一个实例使用 J2 和 [J1, J0] 进行加密)将请求手动刷新密钥([J2, J1] 现在已存储),然后再次尝试 AWSCURRENT 和 AWSPREVIOUS。
在密钥窗口中使用三个密钥并始终使用中间的一个加密,因为它应该始终位于所有其他实例的窗口中(除非它被旋转多次,比刷新间隔更快)。这增加了复杂性。
还有哪些其他选择?这似乎是一个标准用例,但我仍然在努力寻找最佳方法。
编辑 ------------------
根据 JoeB 的回答,到目前为止我提出的算法是这样的: 假设最初秘密的 CURRENT 值为 K1,PENDING 值为 null。
正常操作
- 所有服务定期(每 T 秒)向 SecretsManager 查询
AWSCURRENT、AWSPENDING和自定义标签ROTATING并全部接受(如果存在)-> 所有服务都接受 [AWSCURRENT=K1]李> - 所有客户端都使用
AWSCURRENT=K1
按键轮换
- 为 PENDING 阶段设置一个新值 K2
- 等待 T 秒 -> 现在所有服务都接受 [
AWSCURRENT=K1,AWSPENDING=K2] - 将
ROTATING添加到K1 版本+ 将AWSCURRENT移动到K2 版本+ 从K2 中删除AWSPENDING标签(似乎没有标签的原子交换)。直到 T 秒过去,一些客户端将使用 K2 和一些 K1,但所有服务都接受两者 - 等待 T 秒 -> 所有服务仍然接受 [
AWSCURRENT=K2,AWSPENDING=K1] 并且所有客户端使用AWSCURRENT=K2 - 从 K1 中移除
ROTATING阶段。请注意,K1 仍将具有AWSPREVIOUS阶段。 - T 秒后,所有服务将只接受 [
AWSCURRENT=K2],K1 实际上已死。
这应该适用于单独的秘密和用于加密和解密的对称秘密。
不幸的是,我不知道如何为此使用内置的旋转机制,因为它需要几个步骤,中间有延迟。一种想法是发明一些自定义步骤并让setSecret 步骤创建一个 CloudWatch cron 事件,该事件将在 T 秒后再次调用该函数,并使用步骤 swapPending 和 removePending 调用它。如果 SecretsManager 可以自动支持这一点,那就太棒了,例如支持函数返回一个值,指示应该在 T 秒后调用下一步。
【问题讨论】:
标签: encryption secret-key aws-secrets-manager shared-secret