Terraform - 当模块的资源已经存在时,EntityAlreadyExists 错误 (409)

Rtm*_*tmY 5 amazon-web-services amazon-iam terraform

我正在编写一个模块,它应该在不同的环境中重复使用。

为了简单起见,这里有一个从环境根模块之一调用模块的基本示例:

##QA-resources.tf

module "some_module" {
  source = "./path/to/module" 
}

some_variable = ${module.some_module.some_output}
Run Code Online (Sandbox Code Playgroud)

问题是当一个模块已经被创建时,Terraform 会抛出一个错误:

创建 [resource-type] [resource-name] 时出错:EntityAlreadyExists:[resource-type] 与 [resource-name] 已经存在。状态码:409,请求 ID:...

当模块是在外部范围内创建的terraform.tfstate并且其中一个资源具有像“名称”这样的唯一字段时,就会发生这种情况。

在我的情况下,它发生在尝试使用已经创建具有该特定名称的角色的 IAM 模块时,但它可能发生在许多其他情况下(我不希望讨论特定于我的用例)。

我希望如果模块的资源之一存在,则不会发生故障并且模块的输出可供root模块使用

任何建议如何管理这个(可能使用特定的命令或标志)?


我发现了一些相关的线程:

Terraform 不会重用它刚刚创建的 AWS 角色并失败?

解决 terraform 中 EntityAlreadyExists 错误的最佳方法是什么?

Terraform 错误 EntityAlreadyExists:名为 iam_for_lambda 的角色已经存在


编辑

对于@Martin Atkins 请求,这里是导致错误的资源。

它是 AWS EKS 集群的基本角色,附加了 2 个策略(通过 传递var.policies):

resource "aws_iam_role" "k8s_role" {
  name = "k8s-role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "eks.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}


resource "aws_iam_role_policy_attachment" "role-policy-attach" {
  role  = "${aws_iam_role.k8s_role.name}"
  count = "${length(var.policies)}"
  policy_arn = "${element(var.policies, count.index)}"
}
Run Code Online (Sandbox Code Playgroud)

这个角色被包装成一个模块并传递给根模块。
上面blockquotes 中提到的错误是因为角色已经存在,而根模块试图创建它。

Mar*_*ins 8

在 Terraform 看来,每个对象要么由 Terraform 管理,要么不由 Terraform 管理。Terraform 避免隐式取得现有对象的所有权,因为如果这样做,那么当您随后运行时,terraform destroy您可能最终会无意中破坏了您不希望 Terraform 管理的东西。

在您的情况下,这意味着您需要决定命名的角色是否k8s-role由 Terraform 管理,如果您有多个 Terraform 配置,则需要选择一个配置来管理该对象。

在将管理对象的一个​​ Terraform 配置中,您可以使用 aresource "aws_iam_role"来指定它。如果任何其他配置需要访问它,或者根本不会使用 Terraform 管理它,那么您可以k8s-role在需要的情况下直接引用角色名称。如果您需要有关该角色的不仅仅是它的名字更多的信息,那么你可以使用aws_iam_role数据源没有宣布要管理对象来获取信息:

data "aws_iam_role" "k8s" {
  name = "k8s-role"
}
Run Code Online (Sandbox Code Playgroud)

例如,如果您需要使用此角色的 ARN,则可以使用 访问arn此数据资源的属性data.aws_iam_role.k8s.arn

最后,如果你的角色是不是目前由Terraform管理,但你希望把它下Terraform的所有权,你可以明确地告诉Terraform开始导入它来创建现有对象和你之间的关联管理,现有的对象resource块:

terraform import aws_iam_role.k8s_role k8s-role
Run Code Online (Sandbox Code Playgroud)