terraformterraform-provider

Terraform use variable in array


I created a resource for a random password like this:

    resource "random_password" "secret1" {
      length = 12
      special = false
      numeric = true
    }

I want to use the result of this in an array 'fields' in tfvars file:

fields = [
    {
      fieldname = "Username"
      itemvalue = "terraform"
    },
    {
      fieldname = "Password"
      itemvalue = random_password.secret1.result
    }
  ]

This throws an error:

│ Error: Variables not allowed │ │ on terraform.tfvars line 17: │ 17: itemvalue = random_password.random_secret.result │ │ Variables may not be used here.

How can I achive to use the result of the random_password as itemvalue as I don´t want to use a static value.


Solution

  • You cannot reference anything in tfvars those are static value files, as @Marko E pointed out in its comment.

    A path forward to achieve your goal could be to rethink you you define your fields variable as I'll explain below.

    Fist, refactor the variable's definition to allow you to choose which entry you want to generate and which you want to statically set

    variable "fields" {
      type = list(object({
        field_name             = string
        field_value            = optional(string)
        randomically_generated = optional(bool, false)
      })
    }
    

    Change your tfvars accordingly:

      fields = [
        {
          field_name = "Username"
          item_value = "terraform"
        },
        {
          field_name             = "Password"
          randomically_generated = true
        }
      ]
    

    Generate a random value for each field that has randomically_generated set to true:

    resource "random_password" "generated" {
      for_each = {
        # we use the field_name as the key (I'm assuming it is unique)
        f in var.fields : field_name => f if randomically_generated
      }
      length  = 12
      special = false
      numeric = true
    }
    

    Use a local value to generate your final structure which will mix provided and randomically generated values:

    locals {
      fields = [
        for f in fields: {
          field_name  = f.field_name
          field_value = f.randomically_generated ?
            # select the value generated for that field, or the value if not generated
            random_password.generated[f.field_value].result : f.field_value
        }
      ]
    }
    

    In the places in which you needed to use var.fields you'll use instead local.fields.

    P.S. I've tried to follow your current fields definition which is an array, but maybe a map (indexed by field_name) would be a better approach (see references).


    References: