Create handful of DNS records in multiple domains AWS Route 53

Hello

We have a 1000+ defensive registrations domains. All these domains only require a couple records.
We want to manage all these domains from Terraform.

I’m passing the list of domains via CSV.

Creating the domains works perfectly but we need to create the records at the same time.

Here is the code:

locals {
csv_data = <<-CSV
zone_name
domain1.com
domain2.com
domain3.com
CSV

zones = csvdecode(local.csv_data)
}

provider “aws” {
profile = “default”
region = “eu-west-2”
}

resource “aws_route53_zone” “allzones” {
for_each = { for inst in local.zones : inst.zone_name => inst }
name = (each.value.zone_name)
}

resource “aws_route53_record” “spf” {
zone_id = aws_route53_zone.allzones.zone_id
name = “ssl”
type = “TXT”
records = “v=spf1 -all”
ttl = “21600”
}

resource “aws_route53_record” “dmarc” {
zone_id = aws_route53_zone.allzones.zone_id
name = “@”
type = “TXT”
records = “v=DMARC1; p=reject; fo=1; ri=3600; rua=mailto:test@test.com; ruf=mailto:test@test.com
ttl = “21600”
}

The error I’m getting is:

Error: Missing resource instance key

│ on main.tf line 24, in resource “aws_route53_record” “spf”:
│ 24: zone_id = aws_route53_zone.allzones.zone_id

│ Because aws_route53_zone.allzones has “for_each” set, its attributes must be accessed on specific instances.

│ For example, to correlate with indices of a referring resource, use:
│ aws_route53_zone.allzones[each.key]

In summary: looking for a way to do the following:

for each domain name in CSV
(create zone)

then

for each created zone_id
(create records)

Problem is that zone_id is only generated after apply.

Any suggestions will be most welcomed.

Thanks,

Hi @VictorCreed7,

It sounds like you could get the result you want by chaining together the for_each arguments here:

resource “aws_route53_zone” “allzones” {
  for_each = { for inst in local.zones : inst.zone_name => inst }

  name = each.value.zone_name
}

resource “aws_route53_record” “spf” {
  for_each = aws_route53_zone.allzones

  zone_id = each.value.zone_id
  name    = “ssl”
  type    = “TXT”
  records = “v=spf1 -all”
  ttl     = “21600”
}

resource “aws_route53_record” “dmarc” {
  for_each = aws_route53_zone.allzones

  zone_id = each.value.zone_id
  name    = “@”
  type    = “TXT”
  records = “v=DMARC1; p=reject; fo=1; ri=3600; rua=mailto:test@test.com;ruf=mailto:test@test.com”
  ttl     = “21600”
}

A resource with for_each set appears in expressions as a map of objects where the keys match the keys given in its own for_each, so you can use such a resource as the for_each of another resource as I did above, telling Terraform directly that you want to have one aws_route53_record.spf and one aws_route53_record.dmarc instance for each aws_route53_zone.allzones instance.

By coincidence I wrote a new section in the for_each docs about this earlier in the week. It’s not published on the website yet but you can view the content that we’ll publish on the website soon. (For the benefit of those who might find this answer later, once the content is published on the website, the final home of this documentation will be Chaining for_each Between Resources.)

Many thanks! Works perfectively… :+1: