Terraform AWS Provider:SecretsManager 无法应用,因为版本已被删除

Terraform AWS Provider: SecretsManager can't apply because version was deleted

我们有一个创建过一次的 AWS SecretsManager Secret。该秘密将每小时由外部作业更新一次。 我遇到的问题是,有时 terraform plan/apply 会失败并显示以下消息:

AWS 提供商 2.48

    Error: Error refreshing state: 1 error occurred:

        * module.xxx.xxx: 1 error occurred:

        * module.xxx.aws_secretsmanager_secret_version.xxx: 
    aws_secretsmanager_secret_version.xxx: error reading Secrets Manager Secret Version: InvalidRequestException: You can't perform this operation on secret version 68AEABC3-34BE-4723-8BF5-469A44F9B1D9 because it was deleted.

我们尝试了两种解决方案: 1) 通过 aws cli 强制删除整个秘密,但这有副作用,我们的依赖资源之一也将被重新创建(ecs 模板定义取决于该秘密)。这可行,但我们不希望重新创建 ecs 事物的副作用。 2) 手动编辑后端.tfstate 文件并设置当前AWS secret 版本。然后运行再次计划。

这两种解决方案在某种程度上似乎都很老套。解决此问题的最佳方法是什么?

您可以使用 terraform import 来协调 运行 与 planapply 之前的状态差异。

在你的情况下,这看起来像:

terraform import module.xxx.aws_secretsmanager_secret_version.xxx arn:aws:secretsmanager:some_region:some_account_id:secret:example-123456|xxxxx-xxxxxxx-xxxxxxx-xxxxx

我认为您遇到的问题可能是默认情况下 AWS 尝试 "help you" 不让您自动删除机密,直到 7 天过去。 AWS 通过告诉您他们给您 7 天的宽限期来更新可能依赖于此的 "code" 来尝试 "help you"。这使得自动化更加困难。

我通过将恢复 window 期限设置为“0 天”来解决这个问题,有效地消除了 AWS 提供的宽限期。

然后您可以手动(通过 AWS CLI)或通过 terraform 任意地进行 terraform、重命名或删除您的密钥。

您可以通过首先输入此值来更新现有机密。然后更改秘密的名称(如果你愿意),或根据需要删除它(这个 terraform 部分)并 运行 在恢复 window days = 0 后再次应用 terraform。

这是一个例子:

resource "aws_secretsmanager_secret" "mySecret" {
    name = "your secret name"
    recovery_window_in_days = "0"

   // this is optional and can be set to true | false
    lifecycle {
    create_before_destroy = true
    }
}

*注意,还有一个选项"create before destroy"你可以在生命周期上设置。

https://www.terraform.io/docs/configuration/resources.html

另外,您可以像这样使用 terraform 资源来更新秘密值:

此示例将设置一次秘密值,然后告诉 terraform 在初始创建后忽略对值(本示例中的用户名、密码)所做的任何更改。

如果删除生命周期部分,Terraform 将跟踪秘密值本身是否已更改。如果它们发生了变化,它们将恢复为 terraform 状态下的值。

如果您将 tfstate 文件存储在受 s3 保护的存储桶中,这比不这样做更安全,因为它们在状态文件中是纯文本,因此任何有权访问您的 terraform 状态文件的人都可以看到您的秘密值。

我建议:1) 弄清楚是什么意外地删除了您的机密? 2) 让你的 "external job" 成为一个 terraform bash 脚本来使用资源更新值,如下例所示。

希望这能给你一些想法。

resource "aws_secretsmanager_secret_version" "your-secret-data" {
      secret_id     = aws_secretsmanager_secret.your-secret.id
      secret_string = <<-EOF
              {
          "username": "usernameValue",
          "password": "passwordValue"
        }
      EOF

      // ignore any updates to the initial values above done after creation. 
      lifecycle {
            ignore_changes = [
              secret_string
            ]
          }
}