使用 Amazon CLI,为 Amazon Secrets Manager 密钥设置自动轮换 - Amazon Secrets Manager
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

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

使用 Amazon CLI,为 Amazon Secrets Manager 密钥设置自动轮换

Rotation 是定期更新密钥的过程。轮换密钥时,会同时更新密钥以及拥有密钥的数据库或服务中的凭证。

Secrets Manager 会使用 Lambda 函数轮换密钥。有关概述,请参阅轮换的工作原理

您也可以使用控制台设置轮换。有关更多信息,请参阅 自动轮换(控制台)

要使用 Amazon CLI 设置轮换,如果您要轮换的是 Amazon RDS、Amazon Redshift 或 Amazon DocumentDB 密钥,首先需要选择 轮换策略。如果选择 alternating users strategy(交替用户策略),您必须存储一个单独密钥,其中包含数据库超级用户凭证。接下来,编写轮换函数代码。Secrets Manager 会提供模板,您可以基于该模板创建函数。然后,使用代码创建 Lambda 函数,并为 Lambda 函数和 Lambda 执行角色设置权限。下一步是确保 Lambda 轮换函数可以通过网络访问 Secrets Manager 和数据库或服务。最后,配置密钥以进行轮换。

要启用自动轮换,您必须具有创建 IAM 执行角色并向其附加权限策略的权限。您需要拥有 iam:CreateRoleiam:AttachRolePolicy 两个权限。

警告

授予身份 iam:CreateRoleiam:AttachRolePolicy 两个权限允许身份向自己授予任何权限。

(可选)步骤 1:创建超级用户密钥

对于 Amazon RDS、Amazon Redshift 和 Amazon DocumentDB,Secrets Manager 提供以下两种轮换策略:

单用户轮换策略

此策略在一个密钥中更新一个用户的凭证。对于 Amazon RDS Db2 实例,由于用户无法更改自己的密码,因此您必须在单独的秘密中提供管理员凭证。这是最简单的轮换策略,适用于大多数使用场景。具体而言,建议您为一次性(临时)用户或交互式用户的凭证使用此策略。

轮换密钥时,不会删除打开的数据库连接。在进行轮换时,在数据库中的密码更改后一小段时间,相应的密码才会更新。在此期间,数据库有较低的风险拒绝使用轮换凭证的调用。您可以使用适当的重试策略来降低风险。轮换后,新连接将使用新凭证。

交替用户轮换策略

此策略在一个密钥中更新两个用户的凭证。您创建第一个用户,然后在第一次轮换期间,轮换函数将进行克隆以创建第二个用户。每次轮换密钥时,轮换函数都会交替更新其更新的用户密码。由于大多数用户无权克隆自己,因此您必须在另一个密钥中为 superuser 提供凭证。如果数据库中的克隆用户与原始用户具有的权限不同,或者涉及一次性(临时)用户或交互式用户的凭证,我们建议使用单用户轮换策略。

此策略适用于具有权限模型的数据库,其中一个角色拥有数据库表,而另一个角色具有访问数据库表的权限。其也适用于需要高可用性的应用程序。如果应用程序在轮换期间检索密钥,则该应用程序仍会获得一组有效的凭证。轮换后,useruser_clone 凭证均有效。在这种类型的轮换期间,应用程序获得拒绝的可能性甚至比单用户轮换获得拒绝的可能性更小。如果数据库托管在服务器场中,密码更改需要时间传播到所有服务器,则存在数据库拒绝使用新凭证的调用的风险。您可以使用适当的重试策略来降低风险。

Secrets Manager 将创建权限与原始用户相同的克隆用户。如果您在创建克隆用户后更改了原始用户的权限,则还必须更改克隆用户的权限。

重要

如果选择 alternating users strategy(交替用户策略),您必须 创建数据库密钥 并在其中存储数据库超级用户凭证。您需要一个包含超级用户凭证的密钥,因为轮换会克隆第一个用户,而大多数用户没有该权限。

步骤 2:编写轮换函数代码

要轮换密钥,您需要轮换函数。轮换函数是 Secrets Manager 为轮换密钥而调用的 Lambda 函数。

对于可以轮换 Amazon RDS、Amazon Aurora、Amazon Redshift、Amazon DocumentDB 或 ElastiCache 亚马逊密钥的函数,您可以从 Secr ets Manager 提供的相应模板中复制代码。

对于所有其他类型的密钥,请使用常规轮换模板作为编写自己的轮换函数的起点。

将轮换函数连同任何所需的依赖项一同保存在 ZIP 文件 my-function.zip 中。

编写函数时,请谨慎包括调试或日志记录语句。这些语句可能会导致您的函数中的信息被写入 Amazon CloudWatch,因此您需要确保日志中不包含开发过程中收集的任何敏感信息。

出于安全考虑,Secrets Manager 仅允许 Lambda 轮换函数直接轮换密钥。轮换函数无法调用第二个 Lambda 函数来轮换密钥。

有关日志语句的示例,请参阅 Amazon Secrets Manager 旋转函数模板 源代码。

例如,如果您使用外部二进制文件和库来连接资源,则需要管理修补和保留它们。 up-to-date

有关调试建议,请参阅测试和调试无服务器应用程序

打开 Lambda 轮换函数以进行编辑
  1. 在 Secrets Manager 控制台中,选择您的密钥。

  2. Rotation configuration(轮换配置)部分下的 Lambda rotation function(Lambda 轮换函数)中,选择轮换函数。

    Lambda 控制台将打开。

    • 若要更改函数中的代码,请向下滚动到代码源部分。

    • 对于 MySQL 5.7 及更高版本,对于交替用户轮换,要更改用户名的最大长度,请在环境变量下更改 USERNAME_CHARACTER_LIMIT

如果您的函数还没有,请从中复制代码SecretsManagerRotationTemplate

轮换密钥包含四个步骤,分别对应 Lambda 轮换函数的以下四种方法。

create_secret

create_secret 中,请首先通过传入的 ClientRequestToken 调用 get_secret_value 来检查是否存在密钥。如果没有密钥,请使用 create_secret 创建一个新密钥,并将令牌作为 VersionId。然后您可以使用 get_random_password 生成新的密钥值。您必须确保新的密钥值仅包含对数据库或服务有效的字符。使用 ExcludeCharacters 参数排除字符。调用 put_secret_value 以将其与暂存标签 AWSPENDING 一起存储。将新的密钥值存储在 AWSPENDING 中有助于确保幂等性。如果由于任何原因轮换失败,您可以在后续调用中引用该密钥值。请参阅如何使我的 Lambda 函数具有幂等性

测试函数时,使用 Amazon CLI 查看版本阶段:调用 describe-secret 并查看 VersionIdsToStages

set_secret

set_secret 中,更改数据库或服务中的凭证,以匹配密钥 AWSPENDING 版本中的新密钥值。

如果将语句传递给数据库等语句解读服务,请使用查询参数化。有关更多信息,请参阅 OWASP 网站上的查询参数化备忘单

轮换函数作为特权代理,有权访问和修改 Secrets Manager 密钥和目标资源中的客户凭证。为防范潜在的混淆代理攻击,您需要确保攻击者无法使用该函数访问其他资源。在更新凭证之前:

  • 检查密钥 AWSCURRENT 版本中的凭证是否有效。如果 AWSCURRENT 凭证无效,请放弃轮换尝试。

  • 检查 AWSCURRENTAWSPENDING 密钥值是否适用于同一资源。对于用户名和密码,检查 AWSCURRENTAWSPENDING 用户名是否相同。

  • 检查目标服务资源是否相同。对于数据库,检查 AWSCURRENTAWSPENDING 主机名是否相同。

test_secret

test_secret 中,通过使用密钥的 AWSPENDING 版本访问数据库或服务,以对其进行测试。

finish_secret

finish_secret 中,使用 update_secret_version_stage 将暂存标签 AWSCURRENT 从早期密钥版本移动到新的密钥版本。Secrets Manager 会将 AWSPREVIOUS 暂存标签自动添加到早期版本,以便您保留上次已知良好的密钥版本。

步骤 3:创建 Lambda 函数和执行角色

Lambda 执行角色是 Lambda 在调用函数时担任的角色。

创建 Lambda 轮换函数和执行角色
  1. 为 Lambda 执行角色创建信任策略并将其另存为 JSON 文件。有关示例,请参阅轮换权限。该策略必须:

    • 允许角色对密钥调用 Secrets Manager 操作。

    • 如果密钥使用 aws/secretsmanager 以外的密钥进行加密,则允许角色使用 KMS 密钥。

    • 允许角色调用拥有密钥的服务。

  2. 创建 Lambda 执行角色并通过调用 iam create-role 应用信任策略。

    aws iam create-role \ --role-name rotation-lambda-role \ --assume-role-policy-document file://trust-policy.json
  3. (可选)对于包含 Amazon RDS 或 Aurora 凭证的密钥,如果您使用的是交替用户策略并且超级用户秘密由 Amazon RDS 管理,则必须允许轮换函数调用 Amazon RDS 上的只读 API,以便其获取数据库的连接信息。为此,请通过调用,将Amazon托管策略 AmazonRDS 附加ReadOnlyAccess到 Lambda 函数执行角色。iam attach-role-policy

    aws iam attach-role-policy \ --policy-arn arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess \ --role-name rotation-lambda-role
  4. 通过调用 lambda create-function 从 ZIP 文件创建 Lambda 函数。

    aws lambda create-function \ --function-name my-rotation-function \ --runtime python3.9 \ --zip-file fileb://my-function.zip \ --handler my-handler \ --role arn:aws:iam::123456789012:role/service-role/rotation-lambda-role
  5. 在 Lambda 函数上设置资源策略,以允许 Secrets Manager 通过调用 lambda add-permission 来调用该资源策略。示例命令应包括 source-account,以防止 Lambda 被用作混淆代理

    aws lambda add-permission \ --function-name my-rotation-function \ --action lambda:InvokeFunction \ --statement-id SecretsManager \ --principal secretsmanager.amazonaws.com \ --source-account 123456789012

步骤 4:设置网络访问

为了能够轮换密钥,Lambda 轮换函数必须能够访问密钥和数据库或服务。

访问密钥

Lambda 轮换功能必须能够访问 Secrets Manager 端点。如果您的 Lambda 函数可以访问互联网,则可以使用公共终端节点。若要查找端点,请参阅 Amazon Secrets Manager 端点

如果您的 Lambda 函数在不具备互联网访问权限的 VPC 中运行,我们建议您在 VPC 内配置 Secrets Manager 服务私有终端节点。然后,您的 VPC 可以拦截发往公共区域终端节点的请求并将其重定向到私有终端节点。有关更多信息,请参阅 VPC 端点

或者,您可以通过向 VPC 添加 NAT 网关互联网网关(这将允许来自您 VPC 的流量访问公有端点),允许 Lambda 函数访问 Secrets Manager 公有端点。这会使 VPC 面临一定的风险,因为网关的 IP 地址可能会受到来自公有 Internet 的攻击。

访问数据库或服务

如果数据库或服务在 VPC 中的 Amazon EC2 实例上运行,建议将 Lambda 函数配置为在同一 VPC 中运行。然后轮换功能可以直接与您的服务通信。有关更多信息,请参阅配置 VPC 访问

要允许 Lambda 函数访问数据库或服务,您必须确保附加到 Lambda 轮换函数的安全组允许与数据库或服务的出站连接。您还必须确保附加到数据库或服务的安全组允许来自 Lambda 轮换函数进行入站连接。

对于超级用户秘密由其他 Amazon 服务管理交替用户轮换,Lambda 轮换函数必须能够调用服务端点以获取数据库连接信息。我们建议您为数据库服务配置 VPC 端点。有关更多信息,请参阅:

步骤 5:配置密钥以进行轮换

要为密钥开启自动轮换功能,请调用 rotate-secret。您可以使用 cron()rate() 计划表达式设置轮换计划,也可以设置轮换时段持续时间。您可以每四小时轮换一次密钥。有关更多信息,请参阅计划表达式

aws secretsmanager rotate-secret \ --secret-id MySecret \ --rotation-lambda-arn arn:aws:lambda:Region:123456789012:function:my-rotation-function \ --rotation-rules "{\"ScheduleExpression\": \"cron(0 16 1,15 * ? *)\", \"Duration\": \"2h\"}"

后续步骤

请参阅排除 Amazon Secrets Manager 轮换故障