<p>I have a yaml file which is similar to the following (FYI: <em>ssm_secrets</em> can be an empty array):</p>
<pre><code>rabbitmq:
  repo_name: bitnami
  namespace: rabbitmq
  target_revision: 11.1.1
  path: rabbitmq
  values_file: charts/rabbitmq/values.yaml
  ssm_secrets: []
app_name_1:
  repo_name: repo_name_1
  namespace: namespace_1
  target_revision: target_revision_1
  path: charts/path
  values_file: values.yaml
  ssm_secrets:
    - name: name-dev-1
      key: .env
      ssm_path: ssm_path/dev
name-backend:
  repo_name: repo_name_2
  namespace: namespace_2
  target_revision: target_revision_2
  path: charts/name-backend
  values_file: values.yaml
  ssm_secrets:
    - name: name-backend-app-dev
      ssm_path: name-backend/app/dev
      key: app.ini
    - name: name-backend-abi-dev
      ssm_path: name-backend/abi/dev
      key: contractTokenABI.json
    - name: name-backend-widget-dev
      ssm_path: name-backend/widget/dev
      key: name.ini
    - name: name-abi-dev
      ssm_path: name-abi/dev
      key: name_1.json
    - name: name-website-dev
      ssm_path: name/website/dev
      key: website.ini
    - name: name-name-dev
      ssm_path: name/name/dev
      key: contract.ini
    - name: name-key-dev
      ssm_path: name-key/dev
      key: name.pub
</code></pre>
<p>And using External Secrets and EKS Blueprints, I am trying to generate the yaml file necessary to create the secrets</p>
<pre><code>resource &quot;kubectl_manifest&quot; &quot;secret&quot; {
  for_each   = toset(flatten([for service in var.secrets : service.ssm_secrets[*].ssm_path]))
  yaml_body  = &lt;&lt;YAML
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: ${replace(each.value, &quot;/&quot;, &quot;-&quot;)}
  namespace: ${split(&quot;/&quot;, each.value)[0]}
spec:
  refreshInterval: 30m
  secretStoreRef:
    name: ${local.cluster_secretstore_name}
    kind: ClusterSecretStore
  data:
  - secretKey: .env
    remoteRef:
       key: ${each.value}
YAML
  depends_on = [kubectl_manifest.cluster_secretstore, kubernetes_namespace_v1.namespaces]
}
</code></pre>
<p>The above works fine, but I <strong>also</strong> need to use the <strong>key</strong> value from the yaml into <strong>secretKey: &lt;key_value from yaml&gt;</strong>.</p>
<p>If I try with <code>for_each   = toset(flatten([for service in var.secrets : service.ssm_secrets[*]]))</code></p>
<pre><code>resource &quot;kubectl_manifest&quot; &quot;secret&quot; {
  for_each   = toset(flatten([for service in var.secrets : service.ssm_secrets[*]]))
  yaml_body  = &lt;&lt;YAML
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: ${replace(each.value[&quot;ssm_path&quot;], &quot;/&quot;, &quot;-&quot;)}
  namespace: ${split(&quot;/&quot;, each.value[&quot;ssm_path&quot;])[0]}
spec:
  refreshInterval: 30m
  secretStoreRef:
    name: ${local.cluster_secretstore_name}
    kind: ClusterSecretStore
  data:
  - secretKey: .env
    remoteRef:
       key: ${each.value[&quot;ssm_path&quot;]}
YAML
  depends_on = [kubectl_manifest.cluster_secretstore, kubernetes_namespace_v1.namespaces]
}
</code></pre>
<p>It just gives me the following error:</p>
<blockquote>
<p>The given &quot;for_each&quot; argument value is unsuitable: &quot;for_each&quot; supports
maps and sets of strings, but you have provided a set containing type
object.</p>
</blockquote>
<p>I have tried converting the variable into a map, used lookup, but it doesn't work.
Any help would be much appreciated.</p>
<p><strong>Update 1:</strong></p>
<p>As per @MattSchuchard suggestion, changing the for_each into
<code>for_each   = toset(flatten([for service in var.secrets : service.ssm_secrets]))</code></p>
<p>Gave the following error:</p>
<pre><code>Error: Invalid for_each set argument
│ 
│   on ../../modules/02-plugins/external-secrets.tf line 58, in resource &quot;kubectl_manifest&quot; &quot;secret&quot;:
│   58:   for_each   = toset(flatten([for service in var.secrets : service.ssm_secrets]))
│     ├────────────────
│     │ var.secrets is object with 14 attributes
│ 
│ The given &quot;for_each&quot; argument value is unsuitable: &quot;for_each&quot; supports maps and sets of strings, but you have provided a set containing type object.
</code></pre>
<p><strong>Update 2:</strong><br />
@mariux gave the perfect solution, but here is what I came up with. It's not that cleaner, but definitely works (PS: I myself am going to use Mariux's solution):</p>
<pre><code>locals {
  my_list = tolist(flatten([for service in var.secrets : service.ssm_secrets[*]]))
}


resource &quot;kubectl_manifest&quot; &quot;secret&quot; {

  count      = length(local.my_list)
  yaml_body  = &lt;&lt;YAML
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: ${replace(local.my_list[count.index][&quot;ssm_path&quot;], &quot;/&quot;, &quot;-&quot;)}
  namespace: ${split(&quot;/&quot;, local.my_list[count.index][&quot;ssm_path&quot;])[0]}
spec:
  refreshInterval: 30m
  secretStoreRef:
    name: ${local.cluster_secretstore_name}
    kind: ClusterSecretStore
  data:
  - secretKey: ${local.my_list[count.index][&quot;key&quot;]}
    remoteRef:
       key: ${local.my_list[count.index][&quot;ssm_path&quot;]}
YAML
  depends_on = [kubectl_manifest.cluster_secretstore, kubernetes_namespace_v1.namespaces]
}
</code></pre>

johnny68
<h1>Assumptions</h1>
<p>Based on what you shared, i make the following assumptions:</p>
<ul>
<li>the service is not actually important for you as you want to create external secrets by <code>ssm_secrets.*.name</code> using the given <code>key</code> and <code>ssm_path</code> attributes.</li>
<li>each <code>name</code> is globally unique for all services and never reused.</li>
</ul>
<h1>terraform hacks</h1>
<p>Based on the assumptions you can create an array of ALL ssm_secrets using</p>
<pre><code>locals {
  ssm_secrets_all = flatten(values(var.secrets)[*].ssm_secrets)
}
</code></pre>
<p>and convert it to a map that can be used in <code>for_each</code> by keying the values by <code>.name</code>:</p>
<pre><code>locals {
  ssm_secrets_map = { for v in local.ssm_secrets_all : v.name =&gt; v }
}
</code></pre>
<h1>Full (working) example</h1>
<p>The example below works for me and makes some assumption where the variables should be used.</p>
<ul>
<li>Using <code>yamldecode</code> to decode your original input into <code>local.input</code></li>
<li>Using <code>yamlencode</code> to make reading the manifest easier and removing some string interpolcations. This also ensures that the indent is correct as we convert HCL to yaml.</li>
</ul>
<p>A <code>terraform init &amp;&amp; terraform plan</code> will plan to create the following resources:</p>
<pre><code> kubectl_manifest.secret[&quot;name-abi-dev&quot;] will be created
 kubectl_manifest.secret[&quot;name-backend-abi-dev&quot;] will be created
 kubectl_manifest.secret[&quot;name-backend-app-dev&quot;] will be created
 kubectl_manifest.secret[&quot;name-backend-widget-dev&quot;] will be created
 kubectl_manifest.secret[&quot;name-dev-1&quot;] will be created
 kubectl_manifest.secret[&quot;name-key-dev&quot;] will be created
 kubectl_manifest.secret[&quot;name-name-dev&quot;] will be created
 kubectl_manifest.secret[&quot;name-website-dev&quot;] will be created
</code></pre>
<pre><code>locals {
  # input = var.secrets
  ssm_secrets_all = flatten(values(local.input)[*].ssm_secrets)
  ssm_secrets_map = { for v in local.ssm_secrets_all : v.name =&gt; v }

  cluster_secretstore_name = &quot;not provided secretstore name&quot;
}

resource &quot;kubectl_manifest&quot; &quot;secret&quot; {
  for_each = local.ssm_secrets_map

  yaml_body = yamlencode({
    apiVersion = &quot;external-secrets.io/v1beta1&quot;
    kind       = &quot;ExternalSecret&quot;
    metadata = {
      name      = replace(each.value.ssm_path, &quot;/&quot;, &quot;-&quot;)
      namespace = split(&quot;/&quot;, each.value.ssm_path)[0]
    }
    spec = {
      refreshInterval = &quot;30m&quot;
      secretStoreRef = {
        name = local.cluster_secretstore_name
        kind = &quot;ClusterSecretStore&quot;
      }
      data = [
        {
          secretKey = &quot;.env&quot;
          remoteRef = {
            key = each.value.key
          }
        }
      ]
    }
  })

  # not included dependencies
  # depends_on = [kubectl_manifest.cluster_secretstore, kubernetes_namespace_v1.namespaces]
}

locals {
  input = yamldecode(&lt;&lt;-EOF
    rabbitmq:
      repo_name: bitnami
      namespace: rabbitmq
      target_revision: 11.1.1
      path: rabbitmq
      values_file: charts/rabbitmq/values.yaml
      ssm_secrets: []
    app_name_1:
      repo_name: repo_name_1
      namespace: namespace_1
      target_revision: target_revision_1
      path: charts/path
      values_file: values.yaml
      ssm_secrets:
        - name: name-dev-1
          key: .env
          ssm_path: ssm_path/dev
    name-backend:
      repo_name: repo_name_2
      namespace: namespace_2
      target_revision: target_revision_2
      path: charts/name-backend
      values_file: values.yaml
      ssm_secrets:
        - name: name-backend-app-dev
          ssm_path: name-backend/app/dev
          key: app.ini
        - name: name-backend-abi-dev
          ssm_path: name-backend/abi/dev
          key: contractTokenABI.json
        - name: name-backend-widget-dev
          ssm_path: name-backend/widget/dev
          key: name.ini
        - name: name-abi-dev
          ssm_path: name-abi/dev
          key: name_1.json
        - name: name-website-dev
          ssm_path: name/website/dev
          key: website.ini
        - name: name-name-dev
          ssm_path: name/name/dev
          key: contract.ini
        - name: name-key-dev
          ssm_path: name-key/dev
          key: name.pub
    EOF
  )
}

terraform {
  required_version = &quot;~&gt; 1.0&quot;

  required_providers {
    kubectl = {
      source  = &quot;gavinbunney/kubectl&quot;
      version = &quot;~&gt; 1.7&quot;
    }
  }
}
</code></pre>
<p>hint: you could also try to use the <a href="https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest" rel="nofollow noreferrer"><code>kubernetes_manifest</code> resource</a> instead of <code>kubectl_manifest</code></p>
<p>p.s.: We created <a href="https://terramate.io" rel="nofollow noreferrer">Terramate</a> to make complex creation of Terraform code easier. But this seems perfectly fine for pure Terraform.</p>
