

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# Lambda 轮换函数
<a name="rotate-secrets_lambda-functions"></a>

在中[通过 Lambda 函数进行轮换](rotate-secrets_lambda.md)， AWS Lambda 函数轮换密钥。 AWS Secrets Manager 在轮换期间使用[暂存标签](whats-in-a-secret.md)来识别秘密版本。

如果 AWS Secrets Manager 没有为您的密钥类型提供[轮换函数模板](reference_available-rotation-templates.md)，则可以创建自定义轮换函数。编写轮换函数时请遵循以下准则：

**自定义轮换函数的最佳实践**
+ 使用[常规轮换模板](reference_available-rotation-templates.md#OTHER_rotation_templates)作为起点。
+ 谨慎使用调试或日志记录语句。他们可以将信息写入 Amazon CloudWatch 日志。确保日志不包含敏感信息。

  有关日志语句的示例，请参阅 [AWS Secrets Manager 旋转函数模板](reference_available-rotation-templates.md) 源代码。
+ 为了安全起见， AWS Secrets Manager 仅允许 Lambda 轮换函数直接轮换密钥。轮换函数无法调用另一个 Lambda 函数来轮换密钥。
+ 有关调试指南，请参阅[测试和调试无服务器应用程序](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-test-and-debug.html)。
+ 例如，如果您使用外部二进制文件和库来连接资源，则需要负责对其进行修补和更新。
+ Package 将旋转函数和所有依赖项打包到 ZIP 文件中，例如*my-function.zip*。

**警告**  
由于 Lambda 函数的执行线程不足，将预置的并发参数设置为低于 10 的值可能会导致节流。有关更多信息，请参阅《 AWS Lambda AWS Lambda 开发人员指南》中的[了解预留并发和预置并发](https://docs.aws.amazon.com/lambda/latest/dg/lambda-concurrency.html#reserved-and-provisioned)。

## 轮换函数的四个步骤
<a name="rotate-secrets_lambda-functions-code"></a>

**Topics**
+ [`createSecret`：创建密钥的新版本](#w2aac21c11c29c11b5)
+ [**setSecret**：更改数据库或服务中的凭证](#w2aac21c11c29c11b7)
+ [**testSecret**：测试新的密钥版本](#w2aac21c11c29c11b9)
+ [**finishSecret**：完成轮换](#w2aac21c11c29c11c11)

### `createSecret`：创建密钥的新版本
<a name="w2aac21c11c29c11b5"></a>

方法 `createSecret` 首先通过使用传入的 `ClientRequestToken` 调用 [https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value) 来检查密钥是否存在。如果没有密钥，它会使用 [https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.create_secret](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.create_secret) 创建一个新密钥，并将令牌作为 `VersionId`。然后它使用 [https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_random_password](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_random_password) 生成一个新的密钥值。接下来，它调用 [https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.put_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.put_secret_value) 以将其与暂存标签 `AWSPENDING` 一起存储。将新的密钥值存储在 `AWSPENDING` 中有助于确保幂等性。如果由于任何原因轮换失败，您可以在后续调用中引用该密钥值。请参阅[如何使我的 Lambda 函数具有幂等性](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-idempotent/)。

**编写自己的轮换函数的技巧**
+ 确保新的密钥值仅包含对数据库或服务有效的字符。使用 `ExcludeCharacters` 参数排除字符。
+ 在测试函数时，使用查看版本阶段：调用[https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/describe-secret.html](https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/describe-secret.html)并查看`VersionIdsToStages`。 AWS CLI 
+ 对于 Amazon RDS MySQL，在交替用户轮换中，Secrets Manager 会创建一个名称不超过 16 个字符的克隆用户。您可以修改轮换函数以允许使用更长的用户名。MySQL 5.7 及更高版本支持最多 32 个字符的用户名，但 Secrets Manager 会在用户名末尾附加“\$1clone”（六个字符），因此用户名最多必须保持在 26 个字符以内。

### **setSecret**：更改数据库或服务中的凭证
<a name="w2aac21c11c29c11b7"></a>

方法 `setSecret` 更改数据库或服务中的凭证以匹配密钥的 `AWSPENDING` 版本中的新密钥值。

**编写自己的轮换函数的技巧**
+ 如果将语句传递给解释语句的服务（如数据库），请使用查询参数化。有关更多信息，请参阅 *OWASP 网站*上的 [Query Parameterization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Query_Parameterization_Cheat_Sheet.html)。
+ 轮换函数作为特权代理，有权访问和修改 Secrets Manager 密钥和目标资源中的客户凭证。为防范潜在的[混淆代理攻击](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html)，您需要确保攻击者无法使用该函数访问其他资源。在更新凭证之前：
  + 检查密钥 `AWSCURRENT` 版本中的凭证是否有效。如果 `AWSCURRENT` 凭证无效，请放弃轮换尝试。
  + 检查 `AWSCURRENT` 和 `AWSPENDING` 密钥值是否适用于同一资源。对于用户名和密码，检查 `AWSCURRENT` 和 `AWSPENDING` 用户名是否相同。
  + 检查目标服务资源是否相同。对于数据库，检查 `AWSCURRENT` 和 `AWSPENDING` 主机名是否相同。
+ 在极少数情况下，您可能希望为数据库自定义现有轮换功能。例如，对于交替用户轮换，Secrets Manager 通过复制第一个用户的[运行时配置参数](https://www.postgresql.org/docs/8.0/runtime-config.html)来创建克隆用户。如果要包含更多属性，或更改授予克隆用户的属性，则需要更新 `set_secret` 函数中的代码。

### **testSecret**：测试新的密钥版本
<a name="w2aac21c11c29c11b9"></a>

然后，Lambda 轮换函数将使用该密钥来访问数据库或服务，从而测试密钥的 `AWSPENDING` 版本。基于 [轮换函数模板](reference_available-rotation-templates.md) 测试的轮换函数使用读取访问权限测试新的密钥。

### **finishSecret**：完成轮换
<a name="w2aac21c11c29c11c11"></a>

最后，Lambda 轮换函数将标签 `AWSCURRENT` 从之前的密钥版本移动到此版本，这将同时在同一 API 调用中移除 `AWSPENDING` 标签。Secrets Manager 添加 `AWSPREVIOUS` 暂存标注到以前的版本，以便您保留密钥的上次已知良好的版本。

方法 **finish\$1secret** 使用 [https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.update_secret_version_stage](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.update_secret_version_stage) 将暂存标签 `AWSCURRENT` 从早期密钥版本移动到新的密钥版本。Secrets Manager 会将 `AWSPREVIOUS` 暂存标签自动添加到早期版本，以便您保留上次已知良好的密钥版本。

**编写自己的轮换函数的技巧**
+ 在此之前请不要移除 `AWSPENDING`，也不要使用单独的 API 调用将其移除，因为这可能向 Secrets Manager 表明轮换未成功完成。Secrets Manager 添加 `AWSPREVIOUS` 暂存标注到以前的版本，以便您保留密钥的上次已知良好的版本。

成功轮换后，`AWSPENDING` 暂存标签可能附加到与 `AWSCURRENT` 版本相同的版本，也可能未附加到任何版本。如果 `AWSPENDING` 暂存标签存在但未附加到与 `AWSCURRENT` 相同的版本，则以后对轮换的任何调用都假定先前的轮换请求仍在进行中并返回错误。轮换不成功时，`AWSPENDING` 暂存标签可能会附加到空密钥版本。有关更多信息，请参阅 [轮换问题排查](troubleshoot_rotation.md)。