GNU/Linux, Open Source, Cloud Computing, DevOps and more...

How to quickly import all records from a Route53 DNS zone into Terraform

No comments

The terraform import command allows you to import into HashiCorp Terraform resources that already existed previously in the provider we are working with, in this case AWS. However, it only allows you to import those records one by one, with one run of terraform import at a time. This, apart from being extremely tedious, in some situations becomes impractical. This is the case for the records of a Route53 DNS zone. The task can become unmanageable if we have multiple DNS zones, each one with tens or hundreds of records. In this article I offer you a bash script that will allow you to import in Terraform all the records of a Route53 DNS zone in a matter of seconds or a few minutes.

Prerequisites

In order to perform the procedure described in this article you will need to have Amazon’s aws cli tool installed and configured and also the jq tool available in most Linux distributions.

Procedure

You can perform the import by following these simple steps. You can skip steps 1 and 2 and go directly to step 3 if you already have your Terraform project correctly configured:

1.- Create a new Terraform project folder and configure the provider through the following main.tf file:

provider "aws" {
    region = "eu-west-1"
    access_key = "XXXXXXXXXXXXXXXXXXXX"
    secret_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

2.- Initialize the new Terraform project:

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.74.1...
- Installed hashicorp/aws v3.74.1 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

3.- Run the following script:

Remember to set the appropriate value for the zone_name, zone_id variables beforehand, and also aws_profile if you use different profiles in the aws cli tool to manage different AWS accounts.

#! /bin/bash

# This script retrieves all DNS records from AWS Route53 DNS zone and imports all of them to Terraform

zone_name='example.com'
zone_id='XXXXXXXXXXXXXXXXXXXXX'
aws_profile='example_com'

# Get zone slug from zone name
zone_slug=$(echo ${zone_name} | tr '.' '-')

# Get DNS zone current data from AWS
zone="$(aws --profile=${aws_profile} route53 list-hosted-zones | jq '.HostedZones[] | select (.Id | contains("'${zone_id}'"))')"
# Another method to get DNS zone data searching by zone name instead of zone ID
#zone="$(aws --profile=${aws_profile} route53 list-hosted-zones | jq '.HostedZones[] | select (.Name=="'${zone_name}'.")')"
zone_comment="$(echo ${zone} | jq '.Comment')"
if [ "${zone_comment}" == 'null' ];then
    zone_comment="${zone_name} zone"
fi

# Write aws_route53_zone resource to terraform file
cat << EOF > dns-zone-${zone_name}.tf
resource "aws_route53_zone" "${zone_slug}" {
    name         = "${zone_name}"
    comment      = "${zone_comment}"
}
EOF

# Import DNS zone and records from file to terraform
terraform import "aws_route53_zone.${zone_slug}" "${zone_id}"

# Retrieve all regular records (not alias) from DNS zone and write them down to terraform file
IFS=$'\n'
for dns_record in $(aws --profile="${aws_profile}" route53 list-resource-record-sets --hosted-zone-id "${zone_id}" | jq -c '.ResourceRecordSets[] | select(has("AliasTarget") | not)');do
    name="$(echo ${dns_record} | jq -r '.Name')"
    type="$(echo ${dns_record} | jq -r '.Type')"
    name_slug="$(echo ${type}-${name} | sed -E 's/[\._\ ]+/-/g' | sed -E 's/(^-|-$)//g')"
    ttl="$(echo ${dns_record} | jq -r '.TTL')"
    records="$(echo ${dns_record} | jq -cr '.ResourceRecords' | jq '.[].Value' | sed 's/$/,/')"
    records="$(echo ${records} | sed 's/,$//')"

    cat << EOF >> dns-zone-${zone_name}.tf

resource "aws_route53_record" "${name_slug}" {
    zone_id = aws_route53_zone.${zone_slug}.zone_id
    name    = "${name}"
    type    = "${type}"
    ttl     = "${ttl}"
    records = [${records}]
}
EOF

    # Import DNS record to Terraform
    terraform import "aws_route53_record.${name_slug}" "${zone_id}_${name}_${type}"
done

# Retrieve all alias records from DNS zone and write them down to terraform file
IFS=$'\n'
for dns_record in $(aws --profile="${aws_profile}" route53 list-resource-record-sets --hosted-zone-id "${zone_id}" | jq -c '.ResourceRecordSets[] | select(has("AliasTarget"))');do
    name="$(echo ${dns_record} | jq -r '.Name')"
    type="$(echo ${dns_record} | jq -r '.Type')"
    name_slug="$(echo ${type}-${name} | sed -E 's/[\._\ ]+/-/g' | sed -E 's/(^-|-$)//g')"
    alias_name="$(echo ${dns_record} | jq -cr '.AliasTarget' | jq -r '.DNSName')"

    cat << EOF >> dns-zone-${zone_name}.tf

resource "aws_route53_record" "${name_slug}" {
    zone_id = aws_route53_zone.${zone_slug}.zone_id
    name    = "${name}"
    type    = "${type}"

    alias {
        name                   = "${alias_name}" 
        zone_id                = "${zone_id}"
        evaluate_target_health = true
    }
}
EOF

    # Import DNS record to Terraform
    terraform import "aws_route53_record.${name_slug}" "${zone_id}_${name}_${type}"
done

The script generates a .tf file in the directory from which it is executed containing all the DNS records existing in Route53. At the same time it imports them into Terraform to start managing these resources with Terraform when it finishes. The execution of the script can take several minutes depending on the number of records in the zone to be imported, Fortunately it is a totally unattended process that will not require any effort on your part. I hope you find it useful!

 

About the author

Daniel López Azaña
Freelance AWS Cloud Solution Architect & Linux Sysadmin

Entrepreneur, a generator of ideas and restless mind. Passionate about new technologies, especially Linux systems and Open Source Software. I also like to write about Technology News, Cloud Computing, AWS, DevOps, DevSecOps, System Security, Web Development and Programming, SEO, Science, Innovation, Entrepreneurship, etc.

DanielHow to quickly import all records from a Route53 DNS zone into Terraform

Related Posts

Leave a Reply

Your email address will not be published.