Terraform Route53 And DNS Fun

3 minute read     Updated:

Adam Gordon Bell %
Adam Gordon Bell

In my previous article about terraform I moved my lambda and all related infrastructure to Terraform. I even tested things by destroying everything and then recreating it.

Imagine my surprise then, when several days later I got this.

$ curl https://earthly-tools.com/text-mode
curl: (6) Could not resolve host: earthly-tools.com

In this post, I’ll show you how I fixed this and got my DNS records from AWS’s Route53 into terraform.

The Problem

So, I had a working lambda that was getting all requests to earthly-tools.com, but then it stopped working. What was going on?

First, lets check and see what dig says:

$ dig earthly-tools.com
;; QUESTION SECTION:
;earthly-tools.com.        IN    A

Dig is missing the IPs for the A record of my domain name. Here is what a DIG response should look like:

$ dig google.com 
;; QUESTION SECTION:
;google.com.                    IN      A

;; ANSWER SECTION:
google.com.             210     IN      A       172.217.1.14

I can also use dnschecker.org to validate that something is wrong:

This is strange, because if I look in AWS, under Route53, I can see the A record is setup to point to my HTTP API.

Route 53 A Record

But here lies the problem. The A value of DNS record points to an API Gateway domain name, but not the one I have setup in AWS.

API Gateway doesn’t match DNS

The problem is when I tore down my API gateway, I left a dangling DNS record pointing to a non-existent API Gateway endpoint. The surprising thing is it kept working for a while. Both the new value and the old must resolve to the same IP, and with all the caching that happens in DNS things just kept working for a while.

So the solution is simple, I need to pull my DNS records into Terraform, so that when I make changes to my HTTP API my DNS records also get updated.

Terraform Import

First thing I do is define my zone resource:

resource "aws_route53_zone" "primary" {
 name = "earthly-tools.com" 
}

The I import the existing zone:

$ terraform import aws_route53_zone.primary Z0907636HDO135DJDT7G

With the zone in place, I can create the resource for my A record:

resource "aws_route53_record" "A" {
    name    = "earthly-tools.com"
    type    = "A"
    zone_id = aws_route53_zone.primary.id
}

And then I import it.


$ terraform import aws_route53_record.A Z0907636HDO135DJDT7G_earthly-tools.com_A

Then, I need to configure it to point to the domain name and zone of my API gateway. To do that I add in an alias property.

 resource "aws_route53_record" "A" {
     name    = "earthly-tools.com"
     type    = "A"
     zone_id = aws_route53_zone.primary.id
 
+    alias {
+        evaluate_target_health = true
+        name                   = aws_api_gateway_domain_name.earthly-tools-com.regional_domain_name
+        zone_id                = aws_api_gateway_domain_name.earthly-tools-com.regional_zone_id
+    }
 }

And with that in place, I can just apply everything.

$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_route53_record.A will be created
  + resource "aws_route53_record" "A" {
      + allow_overwrite = (known after apply)
      + fqdn            = (known after apply)
      + id              = (known after apply)
      + name            = "earthly-tools.com"
      + type            = "A"
      + zone_id         = "Z0907636HDO135DJDT7G"

      + alias {
          + evaluate_target_health = true
          + name                   = "d-i2cdn11lkf.execute-api.us-east-1.amazonaws.com"
          + zone_id                = "Z1UJRXOUMOOFQ8"
        }
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_route53_record.A: Creating...
aws_route53_record.A: Still creating... [10s elapsed]
aws_route53_record.A: Still creating... [20s elapsed]
aws_route53_record.A: Still creating... [30s elapsed]
aws_route53_record.A: Creation complete after 38s [id=Z0907636HDO135DJDT7G_earthly-tools.com_A]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

And now everything is working.

$ curl https://earthly-tools.com/text-mode
Earthly.dev Presents:                                                                                              

  _____                 _       
 |_   _|   ___  __  __ | |_     
   | |    / _ \ \ \/ / | __|    
   | |   |  __/  >  <  | |_     
   |_|    \___| /_/\_\  \__|    
                                
  __  __               _        
 |  \/  |   ___     __| |   ___ 
 | |\/| |  / _ \   / _` |  / _ \
 | |  | | | (_) | | (_| | |  __/
 |_|  |_|  \___/   \__,_|  \___|

The code is on GitHub

While you’re here:

Earthly is the effortless CI/CD framework.
Develop CI/CD pipelines locally and run them anywhere!

Adam Gordon Bell %

Spreading the word about Earthly. Host of CoRecursive podcast. Physical Embodiment of Cunningham’s Law.
@adamgordonbell
✉Email Adam✉

Updated:

Get notified about new articles!

We won't send you spam. Unsubscribe at any time.