1
votes

I am trying to create multiple alias DNS records in terraform using for_each. I am getting an error when specifying the name and zone ID of the Alias name. My question is how do I read from a variable defined as a set of strings? Below is my code block and variables defined:

    resource "aws_route53_record" "alias_records" {
      for_each = var.alias_names
      zone_id  = aws_route53_zone.zone.zone_id
      name     = each.key
      type     = "A"
    
      alias {
        name                   = var.alias_dns_names[each.key]
        zone_id                = var.alias_zone_ids[each.key]
        evaluate_target_health = false
      }
    }

    variable "alias_names" {
      type = set(string)
    }
    variable "alias_dns_names" {
      type = set(string)
    }
    variable "alias_zone_ids" {
      type = set(string)
    }
    Error: Invalid index

      on alias.tf line 8, in resource "aws_route53_record" "alias_records":
       8:     name                   = var.alias_dns_names[each.key]
    
    This value does not have any indices.
    
    
    Error: Invalid index
    
      on alias.tf line 9, in resource "aws_route53_record" "alias_records":
       9:     zone_id                = var.alias_zone_ids[each.key]
    
    This value does not have any indices.
    alias_names = [
      "alias1",
      "alias2",
      "alias3"
    }

    alias_dns_names = [
      "alias_dns_1",
      "alias_dns_2",
      "alias_dns_3"
    }

    alias_zone_ids = [
      "alias_zone_1",
      "alias_zone_2",
      "alias_zone_3"
    }
1
What do your variable inputs look like for this situation? - Matt Schuchard
I have my inputs in a .tfvars file. I will update with the inputs. - Dave Michaels
So you are iterating through one list and trying to access values from another two lists. It seems like you want a Map instead. - Matt Schuchard

1 Answers

0
votes

A set data structure is not ordered and its elements don't have any identifiers other than their values, so the set type is not appropriate for your use-case here.

Since you seem to be describing three different aspects of the same underlying object here, I think the most convenient way to expose that from your module would be as a map of objects, like this:

variable "aliases" {
  type = map(object({
    zone_id  = string
    dns_name = string
  }))
}

You can then use this variable alone to capture all three of the values you need for each alias record:

  aliases = {
    alias1 = {
      zone_id  = "alias_zone_1"
      dns_name = "alias_dns_1"
    }
    alias2 = {
      zone_id  = "alias_zone_2"
      dns_name = "alias_dns_2"
    }
    alias3 = {
      zone_id  = "alias_zone_3"
      dns_name = "alias_dns_3"
    }
  }

A map of any data type can be used directly with resource for_each, with each.key representing the map key and each.value representing the value. So you can then change your resource block like this:

resource "aws_route53_record" "alias_records" {
  for_each = var.aliases
  zone_id  = aws_route53_zone.zone.zone_id
  name     = each.key
  type     = "A"

  alias {
    zone_id                = each.value.zone_id
    name                   = each.value.dns_name
    evaluate_target_health = false
  }
}

Because the elements of the map are objects, you can access them from each.value to get the zone_id and dns_name values that correspond with each key in the original map.