Terraform – 数据源 aws_ssm_parameter 引发神秘的 “type” 错误。

huangapple go评论68阅读模式
英文:

Terraform - data source aws_ssm_parameter causing enygmatic "type" errors

问题

以下是您要翻译的部分:

我在尝试运行 terraform plan 时遇到了这个错误:

Error: Invalid dynamic for_each value
│   on .terraform/modules/k8s_resources.nginx_controller/main.tf line 69, in resource "helm_release" "application":
│   69:     for_each = var.additional_set
│ Cannot use a set of object value in for_each. An iterable collection is
│ required.
Operation failed: failed running terraform plan (exit 1)

我真的不明白为什么在 nginx-controller 模块内部会触发这个错误,因为我确信我传递的是一个字符串。

我正在使用这个 AWS 提供程序版本:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0.1"
    }
  }
}

我正在使用 terraform required_version = ">= 0.14.0"

我将值传递为字符串,如下所示:

data "aws_ssm_parameter" "acm_arn" {
  name = "/terraform/dev/fs1/acm_arn"
}

locals {
  nginx_controller_values = [
    # 我有更多的对象,现在都被注释掉了,因为这个对象导致了失败。
    {
      name  = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-ssl-cert"
      value = data.aws_ssm_parameter.acm_arn.value
      type  = "string"
    }
  ]
}

module "nginx_controller" {
  source  = "terraform-iaac/nginx-controller/helm"
  version = "2.2.0"
  namespace = var.namespace
  additional_set = local.nginx_controller_values
  depends_on = [
    kubernetes_namespace.nmsp
  ]
}

如果我在本地变量中硬编码 arn,它可以正常运行。

如果我传递 data.aws_ssm_parameter.acm_arn.arn(SSM 的 arn,而不是我需要的值),它也可以正常运行。

我使用 terraform console 测试了 data.aws_ssm_parameter.acm_arn.value 的值:

  • 它与硬编码的字符串完全相同;
  • 对此值使用 type() 会得到 string,与硬编码的字符串完全相同。

我真的不知道到底发生了什么,这肯定与 aws_ssm_parameter 有关。

显然,我可以避免使用 AWS SSM 参数存储,尽管在我的情况下看起来非常方便,可以在不同的 Terraform 应用程序之间共享一些东西(我遵循了 Hashicorp 关于避免加载另一个应用程序的整个状态的最佳实践);我当然会欣赏关于更好处理这个问题的建议,但是在这个问题中,我的目标是理解为什么出现了这个问题,以及如何正确使用这个 SSM,即使最终我可能不使用 aws_ssm_parameter。

谢谢。

添加关于 SSM 处理部分的更多细节:

我从一个 Terraform 状态中像这样写入 SSM:

# 简而言之,arn 由 acm 模块生成
module "acm" {
  source  = "terraform-aws-modules/acm/aws"
  version = "~> 4.3.2"
  zone_id     = local.zone_id
}

# 并且像这样写入 SSM
resource "aws_ssm_parameter" "acm_arn" {
  name   = "/terraform/dev/fs1/acm_arn"
  type   = "String"
  value  = module.acm.acm_certificate_arn
}

#terraform output 提供了: "arn:aws:acm:eu-west-1:000000000000:certificate/0000aaaa-aa00-0000-000a-00000000aaaa"

编辑:如何在您的系统上复制此问题

我成功地使用一个容易复制粘贴并运行的代码片段复制了这个问题:

# 设置您的区域信息
provider "aws" {
  region = "eu-west-1"
}

# 放置所需的模块版本和您的后端
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0.1"
    }
  }

  required_version = ">= 0.14.0"
}

# 复制我的示例
resource "aws_ssm_parameter" "test_key_wr_1" {
  name   = "/terraform/fs1/test_key_1"
  type   = "String"
  value  = "paperino"
}

data "aws_ssm_parameter" "test_key_rd_1" {
  name = "/terraform/fs1/test_key_1"
  depends_on = [ aws_ssm_parameter.test_key_wr_1 ]
}

output "ssm_stored_value_1" {
  value     = data.aws_ssm_parameter.test_key_rd_1.value
  sensitive = true
}

locals {
  nginx_controller_values = [
    {
      name  = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-ssl-cert"
      value = data.aws_ssm_parameter.test_key_rd_1.value
      type  = "string"
    },
    {
      name  = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-ssl-ports"
      value = "443"
      type  = "string"
    }
  ]
}

module "nginx_controller" {
  source  = "terraform-iaac/nginx-controller/helm"
  version = "2.2.0"

  namespace = "pippo"

  additional_set = local.nginx_controller_values
}

计划失败,如上所述,我错过了如何使用这个 SSM 模块的一些东西。

编辑2:临时解决方法

这不是一个真正的答案,因为仍然不清楚为什么会发生这种情况,但将 nginx-controller 版本更改为 2.1.0 问题就消失了。在版本 2.1.1 中,问题会再次出现。

我可能会在他们的 Git 存储库上提出一个问题,让

英文:

I am struggling with this error when trying to terraform plan:

Error: Invalid dynamic for_each value
│ 
│   on .terraform/modules/k8s_resources.nginx_controller/main.tf line 69, in resource "helm_release" "application":
│   69:     for_each = var.additional_set
│ 
│ Cannot use a set of object value in for_each. An iterable collection is
│ required.
╵
Operation failed: failed running terraform plan (exit 1)

I don't really understand why this gets triggered internally in the nginx-controller module since I am sure I am passing a string.

I am using this AWS provider version:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0.1"
    }
  }
}

I am using terraform required_version = ">= 0.14.0"

I am passing the value as string like this:

data "aws_ssm_parameter" "acm_arn" {
  name = "/terraform/dev/fs1/acm_arn"
}

locals {
  nginx_controller_values = [
    # I have more objects that now are commented-out for testing since this one causes the failure.
    {
      name  = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-ssl-cert"
      value = data.aws_ssm_parameter.acm_arn.value
      type  = "string"
    }
  ]
}

module "nginx_controller" {
  source  = "terraform-iaac/nginx-controller/helm"
  version = "2.2.0"
  namespace = var.namespace
  additional_set = local.nginx_controller_values
  depends_on = [
    kubernetes_namespace.nmsp
  ]
}

If I hardcode the arn in the local varaible it "plans" fine.

If I pass data.aws_ssm_parameter.acm_arn.arn (the arn of SSM, not what I need) instead of data.aws_ssm_parameter.acm_arn.value it "plans" fine.

I tested with terraform console the value of data.aws_ssm_parameter.acm_arn.value and:

  • It is absolutely identycal to the hardcoded string;
  • using type() on this value gives me string exactly as the hardcoded string.

I honestly have no clue on what the hell is going on, it must be something with the aws_ssm_parameter that I cannot understand.

Obviously I could avoid using AWS SSM Parameter Store that looked quite convenient in my case to share few things between different Terraform applications (I followed the best practice from Hashicorp about avoiding to load the whole state of another application); I would obviously appreciate suggestions on better ways to handle this, but, in this question, my goal is to understand why this fails and how to use this SSM correctly even if I will end up not using aws_ssm_parameter.

Thanks


Adding more details on the SSM handling part:

I write to SSM from one Terraform state like this:

# in short the arn gets generated by acm module
module "acm" {
  source  = "terraform-aws-modules/acm/aws"
  version = "~> 4.3.2"
  zone_id     = local.zone_id
}

# and gets written to SSM like this
resource "aws_ssm_parameter" "acm_arn" {
  name   = "/terraform/dev/fs1/acm_arn"
  type   = "String"
  value  = module.acm.acm_certificate_arn
}

#terraform output provides: "arn:aws:acm:eu-west-1:000000000000:certificate/0000aaaa-aa00-0000-000a-00000000aaaa"

Edit: How to replicate on your system

I managed to replicate this with an easy to copy-paste-and-run snippet:

# put your region stuff
provider "aws" {
  region = "eu-west-1"
}

# put the required module version and your backend
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0.1"
    }
  }

  required_version = ">= 0.14.0"
}

# Replicate my example
resource "aws_ssm_parameter" "test_key_wr_1" {
  name   = "/terraform/fs1/test_key_1"
  type   = "String"
  value  = "paperino"
}

data "aws_ssm_parameter" "test_key_rd_1" {
  name = "/terraform/fs1/test_key_1"
  depends_on = [ aws_ssm_parameter.test_key_wr_1 ]
}

output "ssm_stored_value_1" {
  value     = data.aws_ssm_parameter.test_key_rd_1.value
  sensitive = true
}

locals {
  nginx_controller_values = [
    {
      name  = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-ssl-cert"
      value = data.aws_ssm_parameter.test_key_rd_1.value
      type  = "string"
    },
    {
      name  = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-ssl-ports"
      value = "443"
      type  = "string"
    }
  ]
}

module "nginx_controller" {
  source  = "terraform-iaac/nginx-controller/helm"
  version = "2.2.0"

  namespace = "pippo"

  additional_set = local.nginx_controller_values
}

Plan fails as described, there is something I am missing on how to use this ssm module.


Edit2: Temporary Fix

It's not really an answer since it remains unclear why this happens, but changing the nginx-controller version to 2.1.0 the problem disappears. In version 2.1.1 the problem reappears.

I might open an issue on their git repository to make them check.

答案1

得分: 0

将以下内容翻译为中文:

不太确定为什么,但是将此部分更改:

data.aws_ssm_parameter.test_key_rd_1.value

为此部分:

tostring(data.aws_ssm_parameter.test_key_rd_1.value)

在本地块中抑制了错误(我没有应用更改到我的基础架构)。

希望这能解决你的问题!

英文:

Not entirely sure why but changing this:

data.aws_ssm_parameter.test_key_rd_1.value

to this

tostring(data.aws_ssm_parameter.test_key_rd_1.value)

in the locals block suppressed the error (I was not applying changes to my infrastructure).

Hope this fixes the problem for you!

答案2

得分: 0

Turns out that the problem arises after commit a15dd3c and happens when injecting a sensitive string variable in one of the objects in the additional_set variable that now has a type declaration.

Basically, before they didn't define a type for that additional_set while after that commit they did and, I don't know why, with a type definition providing a sensitive value makes everything fail with a meaningless error.

Moreover, as Dawid pointed out, converting tostring() sometimes solves the issue, making everything weirder.

Just to clarify something else, aws_ssm_parameter reads from SSM and marks the data as sensitive; that is why hardcoding a string makes it work, while fetching from aws_ssm breaks it.

It seems to me a weird behavior and a difficult to understand error but that is not caused by this module.

Using nonsensitive() fixes everything.

Not sure if this is a wanted behavior (so just a misleading error) or some issue within Terraform (that should be notified).


Definitive fix

In case others will experience the same problem, after opening an issue on github, problem has been fixed in version 2.2.1 by undoing the change in commit a15dd3c.

英文:

Turns out that the problem arises after commit a15dd3c and happens when injecting a sensitive string variable in one of the objects in the additional_set variable that now has a type declaration.

Basically, before they didn't define a type for that additional_set while after that commit they did and, I don't know why, with a type definition providing a sensitive value makes everything fail with a meaningless error.

Moreover, as Dawid pointed out, converting tostring() sometimes solves the issue, making everything weirder.

Just to clarify something else, aws_ssm_parameter reads from SSM and marks the data as sensitive; that is why hardcoding a string makes it work, while fetching from aws_ssm breaks it.

It seems to me a weird behavior and a difficult to understand error but that is not caused by this module.

Using nonsensitive() fixes everything.

Not sure if this is a wanted behavior (so just a misleading error) or some issue within Terraform (that should be notified).


Definitive fix

In case others will experience the same problem, after opening an issue on github, problem has been fixed in version 2.2.1 by undoing the change in commit a15dd3c.

huangapple
  • 本文由 发表于 2023年6月13日 18:22:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76463908.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定