How to create DNS records in route53 using terraform by looping through a list?

I have a variable called “domains” in which I have these entries-

a.abc.com
b.def.com
c.hij.com
d.klmnop.com

All of these main domains (abc.com, def.com, hij.com, klmnop.com) are managed using route53.

I want to create below sub-domains using terraform

a.abc.com
b.def.com
c.hij.com
d.klmnop.com

Of course I do not want to hard code it. Because the entries under the variable/list “domains” can change with time. So, I’m looking for a solution that loops through the entries present in the variable/list “domains” and create the appropriate sub-domains.

variable.tf

variable "domains" {
  type = set(string)
  default = [
    "a.abc.com",
    "b.def.com",
    "c.hij.com",
    "d.klmnop.com"
  ]
}

data.tf

 data "aws_route53_zone" zone {
     for_each = var.domains
     name =
 }

Please help me fill/complete the third line name=
The challenge is- how to pick the primary domain name from the whole sub-domain
Eg- from a.abc.com, how to pick just abc.com
In this example, the zones should be for these domains- abc.com def.com hij.com and klmnop.com

main.tf

resource "aws_route53_record" "sub-domains" {
for_each = var.domains
zone_id = data.aws_route53_zone.zone[]
name = each.key
}

Please help me fill/complete the third line zone_id=
Here the challenge is to pick the right zone.
For example,
for a.abc.com, the zone is abc.com
for b.def.com, the zone is def.com

Thanks in advance :slight_smile:

Hi @terra-kube,

It seems like your requirement here is that you have a set of domains which already have Route53 zones created outside of Terraform (or in a different Terraform configuration) and you need to just create new records in those existing zones. To do that, you need to find the Route53 zone ID for each of the domains.

To me it seems like the main challenge here is the problem of finding the domain for each of these hostnames. That is, systematically solving the problem of concluding that a.abc.com belongs to abc.com but z.boop.co.uk belongs to boop.co.uk (as opposed to just .co.uk). There isn’t really a good general answer to that within Terraform because a general solution would require fetching all zones in your account and somehow deciding the closest match for each one, but perhaps there’s a simplification of the problem that works for your particular system, such as assuming that there’s only one level of nesting in each zone and so it’s sufficient to just split off the first name from the domain name. For example:

locals {
  records = {
    for name in var.domains :
    name => regex("^(?P<host>[^\\.]+)\\.(?P<domain>.+)$", name)
  }
}

Here I used regex as a simplistic way to “parse” the entries to separate the domain name from the hostname, giving a data structure something like this:

{
  "a.abc.com" = {
    domain = "abc.com"
    host   = "a"
  }
  "b.def.com" = {
    domain = "def.com"
    host   = "b"
  }
  # etc...
}

From that data structure we can write some relatively straightforward resources using for_each:

data "aws_route53_zone" "domain" {
  for_each = local.records

  name = each.value.domain
}

resource "aws_route53_record" "subdomain" {
  for_each = local.records

  zone_id = data.aws_route53_zone.domain[each.key].id
  name    = each.value.host
}

Hopefully that’s a useful starting point!

1 Like