JHH*_*JHH 4 encryption shared-secret secret-key aws-secrets-manager
我在 AWS 中运行多个微服务,其中一些相互通信,其中一些具有外部客户端或成为外部服务的客户端。
为了实现我的服务,我需要许多秘密(用于签名/验证令牌的 RSA 密钥对、对称密钥、API 密钥等)。我正在为此使用 AWS SecretsManager,它运行良好,但我现在正在实施对密钥轮换的适当支持,我有一些想法。
假设服务 A 需要服务 B 的密钥 K:
这是最好的方法还是还有其他方法需要考虑?
然后,在某些情况下,我有一个在同一服务中使用的对称密钥 J,例如用于加密某些会话的密钥。因此,在对服务 C 的一个请求中,会话使用密钥 J1 加密,然后需要在稍后阶段使用 J1 解密。我有多个 C 服务实例。
这里的问题是,如果相同的秘密用于加密和解密,则旋转它会变得更加混乱 - 如果密钥被旋转为具有值 J2 并且一个实例已刷新,以便它将使用 J2 加密,而另一个实例仍然没有看到J2,解密就会失败。
我可以在这里看到一些方法:
分成两个具有单独轮换方案的秘密,并一次轮换一个,与上面类似。这增加了要处理的额外秘密的开销,具有相同的值(除了它们之间有一些时间轮换之外)
让解密在失败时强制刷新秘密:
在密钥窗口中使用三个密钥,并始终使用中间的密钥进行加密,因为它应该始终位于所有其他实例的窗口中(除非它被旋转多次,比刷新间隔更快)。这增加了复杂性。
还有哪些其他选择?这似乎是一个标准的用例,但我仍然努力寻找最好的方法。
编辑 - - - - - - - - -
根据 JoeB 的回答,到目前为止我提出的算法是这样的:假设最初秘密的 CURRENT 值是 K1,PENDING 值是 null。
普通手术
AWSCURRENT并全部接受(如果存在) -> 所有服务接受 [ =K1]AWSPENDINGROTATINGAWSCURRENTAWSCURRENT=K1钥匙轮换
AWSCURRENT=K1, AWSPENDING=K2]ROTATING到K1版本+移动AWSCURRENT到K2版本+AWSPENDING从K2中删除标签(似乎没有标签的原子交换)。在 T 秒过去之前,一些客户端将使用 K2 和一些 K1,但所有服务都接受两者AWSCURRENT=K2, AWSPENDING=K1] 并且所有客户端都使用AWSCURRENT=K2ROTATING物台。请注意,K1 仍然会有舞台AWSPREVIOUS。AWSCURRENT=K2],K1实际上已死亡。这应该适用于单独的秘密和用于加密和解密的对称秘密。
不幸的是,我不知道如何使用内置的旋转机制来实现这一点,因为它需要几个步骤,中间有延迟。一种想法是发明一些自定义步骤,并让该setSecret步骤创建一个 CloudWatch cron 事件,该事件将在 T 秒后再次调用该函数,并使用 stepsswapPending和 来调用它removePending。如果 SecretsManager 能够自动支持这一点,那就太棒了,例如支持函数返回一个值,指示应在 T 秒后调用下一步。
对于您的凭据问题,只要服务 B 支持两个活动凭据,您就不必在应用程序中同时保留当前和以前的凭据。为此,您必须确保凭证在准备就绪之前不会被标记为 AWSCURRENT。然后应用程序始终获取并使用 AWSCURRENT 凭证。要在旋转 lambda 中执行此操作,您需要执行以下步骤:
这些是机密管理器创建多用户 RDS 轮换 lambda 时所采取的相同步骤。请务必使用 AWSPENDING 标签,因为 Secrets Manager 对此进行了特殊处理。如果服务 B 不支持两个活动凭据或多个用户共享数据,则可能无法执行此操作。请参阅有关此内容的秘密管理器轮换文档。
此外,Secrets Manager 轮换引擎是异步的,并且会在失败后重试(这就是每个 Lambda 步骤必须是幂等的原因)。有一组初始重试(大约 5 次),然后每天进行一些重试。您可以利用这一点,通过异常使第三步(测试秘密)失败,直到满足传播条件。或者,您可以将 Lambda 执行时间延长至15 分钟,并休眠适当的时间以等待传播完成。然而,睡眠方法的缺点是不必要地占用资源。
请记住,一旦您删除待处理阶段或将 AWSCURRENT 移至待处理阶段,轮换引擎就会停止。如果应用程序 B 接受当前和待处理(或者如果您想更加安全,则接受当前、待处理和上一个),如果添加您所描述的延迟,则上述四个步骤将起作用。您还可以查看AWS Secrets Manager 示例 Lambda,了解如何操作数据库轮换阶段的示例。
对于您的加密问题,我见过的最好方法是将加密密钥的标识符与加密数据一起存储。因此,当您使用密钥 J1 加密数据 D1 时,您可以存储或以其他方式传递给下游应用程序,例如应用程序的秘密 ARN 和版本(例如 V)。如果服务 A 在消息 M(...) 中向服务 B 发送加密数据,它将按如下方式工作:
请注意,密钥可以由 A 和 B 缓存。如果要长期存储加密数据,则必须确保密钥不会被删除,直到加密数据不再存在或使用以下命令重新加密:当前的密钥。您还可以通过传递不同的 ARN 来使用多个密钥(而不是版本)。
另一种选择是使用KMS进行加密。服务 A 将发送加密的 KMS 数据密钥,而不是密钥标识符以及加密的有效负载。B 可以通过调用 KMS 来解密加密的 KMS 数据密钥,然后使用该数据密钥来解密负载。