如何使用 Terraform 使用已经 KMS 加密的字符串在 AWS Secrets Manager 中存储新秘密?

How to use Terraform to store a new secret in AWS Secrets Manager using already KMS-encrypted string?

我需要编写 Git 修订版 Terraform 代码以将秘密字符串放入 AWS Secrets Manager。给定文本文件中的秘密字符串:

% cat /tmp/plaintext-password
my-super-secret-password

我可以使用 KMS 密钥制作它的加密版本:

# Prints base64-encoded, encrypted string.
aws kms encrypt --key-id my_kms_uuid --plaintext fileb:///tmp/plaintext-password --output text --query CiphertextBlob
# abcdef...123456789/==

可以编写什么 Terraform 代码来获取 AWS Secrets Manager 中的 base64 字符串,以便 AWS 知道它是用 my_kms_uuid 加密的?我尝试了以下方法:

resource "aws_secretsmanager_secret" "testing-secrets-secret" {
  name = "secret-for-testing"
  kms_key_id = "<my_kms_uuid>"
}

resource "aws_secretsmanager_secret_version" "testing-secrets-version" {
  secret_string = "abcdef...123456789/=="
}

问题是我无法找到一种方法来告诉 AWS Secrets Manager 该字符串已被 KMS 加密,因此它不必再次加密。这能做到吗?

如果您的目标是将秘密值保留在状态文件之外,那么您有两个选择:

  1. 在 Terraform 外部加密密钥,然后将加密值存储在 Secrets Manager 中。

    这将强制秘密的所有消费者在使用前对其进行解密。由于加密密钥包含用于加密它的 CMK,因此您无需单独跟踪密钥 ID。

    这种方法有几个缺点。一方面,您必须执行两个步骤才能使用任何秘密:检索它并解密它。如果你使用ECS,你不能提供secret的名称,让ECS提供解密后的值给你的容器。

    一个更大的缺点是很容易忘记哪个 CMK 用于哪个秘密,并且不小心删除了 CMK(此时秘密变得不可用)。相关的是知道向消费者授予哪些权限,尤其是当您有很多 CMK 时。

  2. 在 Terraform 中创建秘密,并手动设置其值。

    这会将实际值保留在 Secrets Manager 中,因此您无需使用两个步骤来解密它。

    可以使用 local-exec 在 Terraform 配置中生成密钥:编写生成随机数据的脚本,然后调用 AWS CLI 来存储值。但是,此技术更常用于在 Terraform 供应过程之外创建的 SSH 私钥等内容。

比这两种解决方案更好的方法是将您的状态文件存储在通常无法访问的地方。有很多 backends 可以为您做这件事。

使用 KMS 加密秘密字符串时,所使用的密钥实际上在生成的密文输出中指定。这意味着我们可以通过以下方式做到这一点:

  1. 使用 AWS 中现有的 KMS 密钥加密秘密字符串 aws kms encrypt --key-id arn:aws:kms:us-east-1:<account_id>:key/mrk-blahblahblah --plaintext fileb://<(printf 'SOME_SECRET_TEXT') --output text --query CiphertextBlob --region us-east-1
  2. 然后在 Terraform 中使用 aws_kms_secrets 解密 (something like this)。
  3. 然后使用 aws_secretsmanager_secret_version.
  4. 将解密的秘密推送到 AWS Secrets Manager

最终结果是版本控制中只保留了编码的秘密,但实际存储在 Secrets Manager 中的密码是解码后的字符串。