Search code examples
terraformvault

Terraform Nested Loop. Iterate a list of objects


Hi I am trying to iterate a list of objects, then within that loop, iterate using a dynamic block a list, which is the object value in Terraform. My end goal us to create a Vault Policy based on a list of policies, key being the path name, and value containing a list of paths.


╷
│ Error: Incorrect attribute value type
│
│   on ..\..\modules\policy_new\vault_policy.tf line 36, in data "vault_policy_document" "ad_hoc_policy_content":
│   36:       path         = each.value.paths
│     ├────────────────
│     │ each.value.paths is list of string with 2 elements
│
│ Inappropriate value for attribute "path": string required.
╵
╷
│ Error: Incorrect attribute value type
│
│   on ..\..\modules\policy_new\vault_policy.tf line 36, in data "vault_policy_document" "ad_hoc_policy_content":
│   36:       path         = each.value.paths
│     ├────────────────
│     │ each.value.paths is list of string with 2 elements
│
│ Inappropriate value for attribute "path": string required.
locals {
  vault_adhoc_readonly_policies_capabilities = ["read", "list"]
}
 
 
 
variable "vault_adhoc_readonly_policies" {
  type = list(object({
    policy_name = string
    paths = list(string)
    })
   )
  description = "This is a list of paths and capabilities to generate policy dynamically."
  default = [
    {
        policy_name = "demo_adhoc"
        paths = [
          "static-secrets/data/infrastructure/platform-showcase/rabbitmq",
          "static-secrets/data/infrastructure/platform-showcase/redis",
        ]
    }
 ]
}
 
 
# Create Ad-Hoc Policies
data "vault_policy_document" "ad_hoc_policy_content" {
 for_each = {for policy in var.vault_adhoc_readonly_policies: policy.policy_name => policy}
 
  dynamic "rule" {
    for_each = each.value.paths  #each.value.paths # range(length(each.value))
    content {
      path         = each.value.paths
      capabilities = local.vault_adhoc_readonly_policies_capabilities
    }
  }
}
 
resource "vault_policy" "vault_adhoc_policies" {
  for_each = {for index, policy in var.vault_adhoc_readonly_policies: policy.policy_name => policy.paths}
 
  name     = "${each.key}"
  policy   = data.vault_policy_document.ad_hoc_policy_content["${each.key}"].hcl
}  ╷
│ Error: Incorrect attribute value type
│
│   on ..\..\modules\policy_new\vault_policy.tf line 36, in data "vault_policy_document" "ad_hoc_policy_content":
│   36:       path         = each.value.paths
│     ├────────────────
│     │ each.value.paths is list of string with 2 elements
│
│ Inappropriate value for attribute "path": string required.
╵
╷
│ Error: Incorrect attribute value type
│
│   on ..\..\modules\policy_new\vault_policy.tf line 36, in data "vault_policy_document" "ad_hoc_policy_content":
│   36:       path         = each.value.paths
│     ├────────────────
│     │ each.value.paths is list of string with 2 elements
│
│ Inappropriate value for attribute "path": string required.
locals {
  vault_adhoc_readonly_policies_capabilities = ["read", "list"]
}
 
 
 
variable "vault_adhoc_readonly_policies" {
  type = list(object({
    policy_name = string
    paths = list(string)
    })
   )
  description = "This is a list of paths and capabilities to generate policy dynamically."
  default = [
    {
        policy_name = "demo_adhoc"
        paths = [
          "static-secrets/data/infrastructure/demo/test1",
          "static-secrets/data/infrastructure/demo/test2",
        ]
    }
 ]
}
 
 
# Create Ad-Hoc Policies
data "vault_policy_document" "ad_hoc_policy_content" {
 for_each = {for policy in var.vault_adhoc_readonly_policies: policy.policy_name => policy}
 
  dynamic "rule" {
    for_each = each.value.paths  #each.value.paths # range(length(each.value))
    content {
      path         = each.value.paths
      capabilities = local.vault_adhoc_readonly_policies_capabilities
    }
  }
}
 
resource "vault_policy" "vault_adhoc_policies" {
  for_each = {for index, policy in var.vault_adhoc_readonly_policies: policy.policy_name => policy.paths}
 
  name     = "${each.key}"
  policy   = data.vault_policy_document.ad_hoc_policy_content["${each.key}"].hcl
}


Solution

  • My reference to each.value at line 29 is a reference to the temporary iterator created at line 24. Updating the reference the temporary iterator that is created at line 27 fixed the issue. That reference would be the label of the dynamic block, so "rule", not "each".

    From the Terraform documentation on dynamic blocks. The iterator argument (optional) sets the name of a temporary variable that represents the current element of the complex value. If omitted, the name of the variable defaults to the label of the dynamic block ("setting" in the example above).

    data "vault_policy_document" "ad_hoc_policy_content" {
     for_each = {for policy in var.vault_adhoc_readonly_policies: policy.policy_name => policy}
     
      dynamic "rule" {
        for_each = each.value.paths 
        content {
          path         = rule.value
          capabilities = local.vault_adhoc_readonly_policies_capabilities
        }
      }
    }