AWS Multiple DNS A record creation

Hi Team,

Am trying to create multiple DNS with appropriate IP in each workspace( like in dev workspace dns1 - 10.1.20.70 and dns2-10.1.20.40) . I’ve tried using the below method but getting the following error. Any suggestion?

resource "aws_route53_record" "onprem_api_record" {

  for_each = toset(local.vm_fqdn)
  zone_id = data.aws_route53_zone.dns_zone.zone_id
  name    = each.value
  type    = "A"
  records = [lookup(var.api_ips, terraform.workspace)]
  ttl     = "300"
}

locals {
  vm_fqdn = flatten(["dns1-${terraform.workspace}.${local.domain}", "dns2-${terraform.workspace}.${local.domain}"] )
}


variable "api_ips" {
  type    = map(any)
  default = {
    "dev"    = [ "10.1.20.70", "10.1.20.40" ]
    "qa"     = [ "10.1.22.80", "10.1.22.50" ]
    "test"  = [ "10.1.23.90", "10.1.23.60" ]
  }
}
Error:

Error: Incorrect attribute value type

  on dns.tf line 26, in resource "aws_route53_record" "onprem_api_record":
  26:   records = [lookup(var.api_ips, terraform.workspace)]
    |----------------
    | terraform.workspace is "dev"
    | var.dcloud_api_ips is object with 3 attributes

Inappropriate value for attribute "records": element 0: string required.


Error: Incorrect attribute value type

  on dns.tf line 26, in resource "aws_route53_record" "onprem_api_record":
  26:   records = [lookup(var.api_ips, terraform.workspace)]
    |----------------
    | terraform.workspace is "dev"
    | var.dcloud_api_ips is object with 3 attributes

Inappropriate value for attribute "records": element 0: string required.

I think the issue here is this expression:

records = [lookup(var.api_ips, terraform.workspace)]

This is equivalent to:

records = [var.api_ips[terraform.workspace]]

Which (with workspace dev) results in:

records = [ [ "10.1.20.70", "10.1.20.40" ] ]

That is, it’s not a list of string, but a nested list.

Try removing the outer square brackets, which are not needed:

records = var.api_ips[terraform.workspace]

One other suggestion: you can be more precise with your variable’s type, which may help Terraform to generate more useful error messages.

variable "api_ips" {
  type    = map(list(string))
  default = {
    "dev"    = [ "10.1.20.70", "10.1.20.40" ]
    "qa"     = [ "10.1.22.80", "10.1.22.50" ]
    "test"  = [ "10.1.23.90", "10.1.23.60" ]
  }
}
1 Like

Thanks a lot for the reply @alisdair. I’ve tried using the above code and getting the following output. Both the IP’s are getting assigned for both of the DNS(dns1 and dns2). I need to assign the first ip to the first DNS and the 2nd one to 2nd DNS. something like dns1 - 10.1.20.70 and dns2-10.1.20.40. Any suggestions ?
Code:

resource "aws_route53_record" "onprem_api_record" {
  for_each = toset(local.vm_fqdn)
  zone_id = data.aws_route53_zone.dns_zone.zone_id
  name    = each.value
  type    = "A"
  records = var.api_ips[terraform.workspace]
  ttl     = "300"
}

locals {
  vm_fqdn = flatten(["dns1-${terraform.workspace}.${local.domain}", "dns2-${terraform.workspace}.${local.domain}"] )
}

variable "api_ips" {
  type    = map(list(string))
  default = {
    "dev"    = [ "10.1.20.70", "10.1.20.140" ]
    "qa"     = [ "10.1.22.180", "10.1.22.150" ]
    "test"  = [ "10.1.23.190", "10.1.23.160" ]
  }
}

Output:

+ resource "aws_route53_record" "onprem_api_record" {
    + allow_overwrite = (known after apply)
    + fqdn            = (known after apply)
    + id              = (known after apply)
    + name            = "dns1.dev.ciscodcloud.com"
    + records         = [
        + "10.1.20.40",
        + "10.1.20.70",
      ]
    + ttl             = 300
    + type            = "A"
    + zone_id         = "Z30HW9VL6PYDXQ"
  }

aws_route53_record.onprem_api_record["dna2.dev.cisco.com"] will be created
+ resource "aws_route53_record" "onprem_api_record" {
    + allow_overwrite = (known after apply)
    + fqdn            = (known after apply)
    + id              = (known after apply)
    + name            = "dns2.dev.cisco.com"
    + records         = [
        + "10.1.20.40",
        + "10.1.20.70",
      ]
    + ttl             = 300
    + type            = "A"
    + zone_id         = "Z30HW9VL6PYDXQ"
  }

Plan: 2 to add, 0 to change, 1 to destroy.

Just a word of caution, DNS Is complex enough and causes enough problems as it is, and you’re breaking some of the major no-no-rules of DNS by doing this.

To update two different DNS servers with two different IPs (doesn’t matter if it’s the same host) then you would need to define them separately. I’m sure there is a trickery way of doing it with using the index of the server and the index of ip to get around this but that’s just going to cause issues down the line if anyone ever tries to figure out what in world is going on. I don’t recommend it.

1 Like

@aram, Thanks for the reply. Individual resources creation is applicable for creating the A records as well? [Am creating only the A record]

No within the same entity you can loop through and create your A records via a local variable.

@aram Thanks for pointing me to the link, @apparentlymart suggested using count in that case. Is that possible to use for_each for my case?.. I’ve tried to follow @alisdair suggestion but no luck so far. Still getting the same above output (Both DNS getting two IP’s).

It’s solved after using zipmap… Thanks, everyone.