AWS Key Management Service
开发人员指南
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

AWS Secrets Manager 如何使用 AWS KMS

AWS Secrets Manager 是一项 AWS 服务,可加密和存储您的密钥,以透明方式解密密钥并将明文密钥返回给您。它专门用于存储定期更改且不应硬编码或以明文形式存储在应用程序中的应用程序密钥,如登录凭证。作为对硬编码凭证或表查找的替代,您的应用程序调用了 Secrets Manager。

Secrets Manager 也支持定期轮换与常用数据库关联的密钥的功能。它总是先对新轮换的密钥加密,然后再进行存储。

Secrets Manager 与 AWS Key Management Service (AWS KMS) 集成,以便使用受 AWS KMS 客户主密钥 (CMK) 保护的唯一数据加密密钥对每个密钥的每个版本进行加密。这种集成可根据从不会使 AWS KMS 处于未加密状态的加密密钥来保护您的密钥。它还允许您设置对主密钥的自定义权限,并审核用于保护密钥的生成、加密和解密数据密钥的操作。

保护密钥值

为了保护密钥,Secrets Manager 会对密钥中的密钥值 进行加密。

在 Secrets Manager 中,密钥密钥值(也称为受保护的密钥文本加密的密钥数据)和相关的元数据及版本信息组成。该密钥值可以是最多包含 4096 字节的任何字符串或二进制数据,但它通常是组成服务器或数据库登录信息的名称-值对的集合。

Secrets Manager 始终先对整个密钥值加密,然后再存储密钥。每当您获取或更改密钥值时,它便以透明方式解密密钥值。没有启用或禁用加密的选项。Secrets Manager 使用 AWS KMS 来加密和解密密钥值。

加密和解密密钥

为了保护密钥,Secrets Manager 将信封加密与 AWS KMS 客户主密钥 (CMKs) 和数据密钥结合使用。

Secrets Manager 使用唯一的数据密钥来保护每个密钥值。每当密钥中的密钥值更改时,Secrets Manager 便会生成新的数据密钥来保护它。该数据密钥根据 AWS KMS CMK 进行加密,并存储在密钥的元数据中,如下图所示。要解密密钥,Secrets Manager 必须首先使用 AWS KMS 中的 CMK 解密已加密的数据密钥。


        加密某个密钥版本中的密钥值

每个密钥的 AWS KMS CMK

每个密钥都与一个 AWS 托管或客户托管的客户主密钥 (CMK)。客户托管的 CMK 允许授权用户通过策略和授权来控制对 CMK 的访问、管理自动轮换并使用导入的密钥材料

在创建新密钥时,您可以在账户和区域中指定任何客户托管 CMK 或指定用于 Secrets Manager 的 AWS 托管 CMK (aws/secretsmanager)。如果您未指定 CMK 或选择控制台默认值 DefaultEncryptionKey,Secrets Manager 将创建 aws/secretsmanager CMK(如果它不存在)并将其与密钥关联。可对您账户中的每个密钥使用相同的 CMK 或不同的 CMK。

可在 Secrets Manager 控制台中或使用 UpdateSecret 操作随时更改密钥的 CMK。当您更改 CMK 时,Secrets Manager 不会根据新 CMK 对现有密钥值重新加密。但是,下次密钥值更改时,Secrets Manager 将根据新 CMK 对其加密。

要查找与密钥关联的 CMK,请使用 ListSecretsDescribeSecret 操作。当密钥与用于 Secrets Manager 的 AWS 托管 CMK (aws/secretsmanager) 关联时,这些操作不会返回 CMK 标识符。

Secrets Manager 不使用 CMK 直接对密钥值加密。而是使用 CMK 生成并加密唯一的数据密钥,并使用该数据密钥来加密密钥值。

每个密钥值的唯一数据密钥

每当您创建或更改密钥中的密钥值时,Secrets Manager 都会使用与该密钥关联的 CMK 来生成并加密一个唯一的 256 位高级加密标准 (AES) 对称数据密钥。Secrets Manager 使用明文数据密钥在 AWS KMS 之外对密钥值加密,然后将其从内存中删除。它将数据密钥的加密副本存储在密钥的元数据中。

该密钥值最终受 CMK 保护,它永远不会使 AWS KMS 处于未加密状态。Secrets Manager 必须先让 AWS KMS 解密已加密的数据密钥,然后它才能解密该密钥。

加密密钥值

为了对密钥中的密钥值加密,Secrets Manager 使用以下过程。

  1. Secrets Manager 使用密钥 CMK 的 ID 和 256 位 AES 对称密钥的请求来调用 AWS KMS GenerateDataKey 操作。AWS KMS 返回明文数据密钥以及根据 CMK 加密的数据密钥的副本。

  2. Secrets Manager 使用明文数据密钥和高级加密标准 (AES) 算法在 AWS KMS 之外对密钥值加密。然后,它将尽快从内存中删除明文密钥。

  3. Secrets Manager 将加密的数据密钥存储在密钥的元数据中,使其可用于解密密钥值。但是,任何一个 Secrets Manager API 均不会返回加密的密钥或加密的数据密钥。

解密密钥值

要解密已加密的密钥值,Secrets Manager 必须先解密已加密的数据密钥。由于数据密钥根据 AWS KMS 中密钥的 CMK 来加密,因此 Secrets Manager 必须向 AWS KMS 发出请求。

对已加密的密钥值解密:

  1. Secrets Manager 调用 AWS KMS Decrypt 操作并传入已加密的数据密钥。

  2. AWS KMS 使用密钥的 CMK 来解密数据密钥。它将返回明文数据密钥。

  3. Secrets Manager 使用该明文数据密钥来解密密钥值。然后,它会尽快从内存中删除数据密钥。

使用您的 AWS KMS CMK

Secrets Manager 使用与密钥关联的客户主密钥 (CMK) 来为每个密钥值生成数据密钥。当它需要对加密的密钥值解密时,还使用 CMK 来解密该数据密钥。可在 AWS CloudTrail 事件、Amazon CloudWatch Logs 和审核跟踪中跟踪请求和响应。

以下 Secrets Manager 操作将触发使用 AWS KMS CMK 的请求。

GenerateDataKey

Secrets Manager 将调用 AWS KMS GenerateDataKey 操作来响应以下 Secrets Manager 操作。

  • CreateSecret – 如果新密钥包含密钥值,Secrets Manager 将请求新数据密钥来对其加密。

  • PutSecretValue– Secrets Manager 请求新数据密钥来对指定的密钥值加密。

  • UpdateSecret – 如果更新更改了密钥值,Secrets Manager 将请求新数据密钥来对新密钥值加密。

注意

RotateSecret 操作不会调用 GenerateDataKey,因为它不更改密钥值。但是,如果 RotateSecret 调用的 Lambda 函数更改了密钥值,则其调用 PutSecretValue 操作时将触发 GenerateDataKey 请求。

Decrypt

为对加密的密钥值解密,Secrets Manager 将调用 AWS KMS Decrypt 操作,来对密钥中的已加密数据密钥解密。然后,它使用明文数据密钥来对已加密密钥值解密。

Secrets Manager 将调用 Decrypt 操作来响应以下 Secrets Manager 操作。

  • GetSecretValue – Secrets Manager 解密密钥值,然后将其返回给调用方。

  • PutSecretValueUpdateSecret – 大多数 PutSecretValueUpdateSecret 请求不会触发 Decrypt 操作。但是,当 PutSecretValueUpdateSecret 请求尝试更改现有密钥版本中的密钥值时,Secrets Manager 将对现有密钥值解密并将其与请求中的密钥值比较,以确认两者是否相同。此操作可确保 Secrets Manager 操作为幂等操作。

 

验证对 CMK 的访问权限

当您建立或更改与密钥关联的 CMK 时,Secrets Manager 将用指定的 CMK 调用 GenerateDataKeyDecrypt 操作。这些调用确认调用方是否有权将该 CMK 用于这些操作。Secrets Manager 将放弃这些操作的结果;它不在任何加密操作中使用这些结果。

您可以识别这些验证调用,因为这些请求中 SecretVersionId 密钥加密上下文的值为 RequestToValidateKeyAccess

注意

过去,Secrets Manager 验证调用不包含加密上下文。在较早的 AWS CloudTrail 日志中可能会找到没有加密上下文的调用。

授权使用 CMK

当 Secrets Manager 在加密操作中使用客户主密钥 (CMK) 时,它代表创建或更改密钥中的密钥值的用户执行操作。

要代表您将 AWS KMS 客户主密钥 (CMK) 用于密钥,用户必须拥有以下权限。您可以在 IAM 策略或密钥策略中指定这些所需的权限。

  • kms:GenerateDataKey

  • kms:Decrypt

要仅允许将 CMK 用于源自 Secrets Manager 的请求,可将 kms:ViaService 条件密钥secretsmanager.<region>.amazonaws.com 值结合使用。

您还可以在加密上下文中将密钥或值用作将 CMK 用于加密操作的条件。例如,可在 IAM 或密钥策略文档中使用字符串条件运算符,或在授权中使用授权约束

AWS 客户主密钥的密钥策略

仅当 Secrets Manager 代表用户发出请求时,用于 Secrets Manager 的 AWS 托管 CMK 的密钥策略才向用户授予将 CMK 用于指定操作的权限。密钥策略不允许任何用户直接使用 CMK。

此密钥策略与所有 AWS 托管密钥的策略类似,均由该服务来建立。您无法更改它,但可以随时查看它。要获取您的账户中 Secrets Manager 的密钥策略,请使用 GetKeyPolicy 操作。

密钥策略中的策略语句具有以下影响:

  • 仅当 Secrets Manager 代表账户中的用户发出请求时,才允许这些用户使用 CMK 执行加密操作。kms:ViaService 条件密钥可强制实施此限制。

  • 允许 AWS 账户创建 IAM 策略以允许用户查看 CMK 属性和撤销授权。

  • 尽管 Secrets Manager 不使用授权来获得对 CMK 的访问权限,该策略也允许 Secrets Manager 代表用户为 CMK 创建授权,并允许账户撤销任何授权(该授权允许 Secrets Manager 使用该 CMK)。这些是 AWS 托管 CMK 的策略文档的标准元素。

下面是用于 Secrets Manager 的 AWS 托管 CMK 示例的密钥策略。

{ "Version" : "2012-10-17", "Id" : "auto-secretsmanager-1", "Statement" : [ { "Sid" : "Allow access through AWS Secrets Manager for all principals in the account that are authorized to use AWS S ecrets Manager", "Effect" : "Allow", "Principal" : { "AWS" : "*" }, "Action" : [ "kms:Encrypt", "kms:Decrypt", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:CreateGrant", "kms:Describ eKey" ], "Resource" : "*", "Condition" : { "StringEquals" : { "kms:ViaService" : "secretsmanager.us-west-2.amazonaws.com", "kms:CallerAccount" : "111122223333" } } },{ "Sid" : "Allow direct access to key metadata to the account", "Effect" : "Allow", "Principal" : { "AWS" : "arn:aws:iam::111122223333:root" }, "Action" : [ "kms:Describe*", "kms:Get*", "kms:List*", "kms:RevokeGrant" ], "Resource" : "*" } ] }

Secrets Manager 加密上下文

加密上下文 是一组包含任意非机密数据的键值对。在请求中包含加密上下文以加密数据时,AWS KMS 以加密方式将加密上下文绑定到加密的数据。要解密数据,您必须传入相同的加密上下文。

在发送给 AWS KMS 的 GenerateDataKeyDecrypt 请求中,Secrets Manager 使用具有两个用于标识密钥及其版本的名称–值对的加密上下文,如以下示例所示。名称不会变化,但与其组合的加密上下文会因每个密钥值而异。

"encryptionContext": { "SecretARN": "arn:aws:secretsmanager:us-west-2:111122223333:secret:test-secret-a1b2c3", "SecretVersionId": "EXAMPLE1-90ab-cdef-fedc-ba987SECRET1" }

您可以使用加密上下文在审核记录和日志中标识这些加密操作(例如 AWS CloudTrail 和 Amazon CloudWatch Logs),并将加密上下文用作在策略和授权中进行授权的条件。

Secrets Manager 加密上下文包含两个名称–值对。

  • SecretARN – 第一个名称–值对标识密钥。密钥是 SecretARN。该值是密钥的 Amazon 资源名称 (ARN)。

    "SecretARN": "ARN of an Secrets Manager secret"

    例如,如果密钥的 ARN 是 arn:aws:secretsmanager:us-west-2:111122223333:secret:test-secret-a1b2c3,加密上下文将包括以下对。

    "SecretARN": "arn:aws:secretsmanager:us-west-2:111122223333:secret:test-secret-a1b2c3"
  • SecretVersionId – 第二个名称–值对标识密钥的版本。密钥是 SecretVersionId。该值为版本 ID。

    "SecretVersionId": "<version-id>"

    例如,如果密钥的版本 ID 是 EXAMPLE1-90ab-cdef-fedc-ba987SECRET1,加密上下文将包括以下对。

    "SecretVersionId": "EXAMPLE1-90ab-cdef-fedc-ba987SECRET1"

当您建立或更改密钥的 CMK 时,Secrets Manager 会将 GenerateDataKeyDecrypt 请求发送到 AWS KMS,以验证调用方是否有权将 CMK 用于这些操作。它将放弃响应,并且不对密钥值使用这些响应。

在这些验证请求中,SecretARN 的值是密钥的实际 ARN,但 SecretVersionId 值为 RequestToValidateKeyAccess,如以下加密上下文示例中所示。此特殊值可帮助您在日志和审核跟踪中标识验证请求。

"encryptionContext": { "SecretARN": "arn:aws:secretsmanager:us-west-2:111122223333:secret:test-secret-a1b2c3", "SecretVersionId": "RequestToValidateKeyAccess" }

注意

在过去,Secrets Manager 验证请求不包含加密上下文。在较早的 AWS CloudTrail 日志中可能会找到没有加密上下文的调用。

监控 Secrets Manager 与 AWS KMS 的交互

您可以使用 AWS CloudTrail 和 Amazon CloudWatch Logs 来跟踪 Secrets Manager 代表您向 AWS KMS 发送的请求。

GenerateDataKey

当您在密钥中创建或更改密钥值时,Secrets Manager 将向 AWS KMS 发送 GenerateDataKey 请求,该请求可为密钥指定 CMK。

记录 GenerateDataKey 操作的事件与以下示例事件类似。该请求由 secretsmanager.amazonaws.com 调用。参数包括密钥的 CMK 的 Amazon 资源名称 (ARN)、需要 256 位密钥的密钥说明符以及标识密钥和版本的加密上下文

{ "eventVersion": "1.05", "userIdentity": { "type": "IAMUser", "principalId": "AROAIGDTESTANDEXAMPLE:user01", "arn": "arn:aws:sts::111122223333:assumed-role/Admin/user01", "accountId": "111122223333", "accessKeyId": "AKIAIOSFODNN7EXAMPLE", "sessionContext": { "attributes": { "mfaAuthenticated": "false", "creationDate": "2018-05-31T23:23:41Z" } }, "invokedBy": "secretsmanager.amazonaws.com" }, "eventTime": "2018-05-31T23:23:41Z", "eventSource": "kms.amazonaws.com", "eventName": "GenerateDataKey", "awsRegion": "us-west-2", "sourceIPAddress": "secretsmanager.amazonaws.com", "userAgent": "secretsmanager.amazonaws.com", "requestParameters": { "keyId": "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", "keySpec": "AES_256", "encryptionContext": { "SecretARN": "arn:aws:secretsmanager:us-west-2:111122223333:secret:test-secret-a1b2c3", "SecretVersionId": "EXAMPLE1-90ab-cdef-fedc-ba987SECRET1" } }, "responseElements": null, "requestID": "a7d4dd6f-6529-11e8-9881-67744a270888", "eventID": "af7476b6-62d7-42c2-bc02-5ce86c21ed36", "readOnly": true, "resources": [ { "ARN": "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", "accountId": "111122223333", "type": "AWS::KMS::Key" } ], "eventType": "AwsApiCall", "recipientAccountId": "111122223333" }
Decrypt

每当您获取或更改密钥的密钥值时,Secrets Manager 都会向 AWS KMS 发送 Decrypt 请求,以对已加密数据密钥进行解密。

记录 Decrypt 操作的事件与以下示例事件类似。用户是您的 AWS 账户中正在访问表的委托人。参数包括加密表密钥(作为密文 blob)以及标识表和 AWS 账户的加密上下文。AWS KMS 从密文中派生 CMK 的 ID。

{ "eventVersion": "1.05", "userIdentity": { "type": "IAMUser", "principalId": "AROAIGDTESTANDEXAMPLE:user01", "arn": "arn:aws:sts::111122223333:assumed-role/Admin/user01", "accountId": "111122223333", "accessKeyId": "AKIAIOSFODNN7EXAMPLE", "sessionContext": { "attributes": { "mfaAuthenticated": "false", "creationDate": "2018-05-31T23:36:09Z" } }, "invokedBy": "secretsmanager.amazonaws.com" }, "eventTime": "2018-05-31T23:36:09Z", "eventSource": "kms.amazonaws.com", "eventName": "Decrypt", "awsRegion": "us-west-2", "sourceIPAddress": "secretsmanager.amazonaws.com", "userAgent": "secretsmanager.amazonaws.com", "requestParameters": { "encryptionContext": { "SecretARN": "arn:aws:secretsmanager:us-west-2:111122223333:secret:test-secret-a1b2c3", "SecretVersionId": "EXAMPLE1-90ab-cdef-fedc-ba987SECRET1" } }, "responseElements": null, "requestID": "658c6a08-652b-11e8-a6d4-ffee2046048a", "eventID": "f333ec5c-7fc1-46b1-b985-cbda13719611", "readOnly": true, "resources": [ { "ARN": "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", "accountId": "111122223333", "type": "AWS::KMS::Key" } ], "eventType": "AwsApiCall", "recipientAccountId": "111122223333" }