Terraform - setting up domain DNS with cloudflare.

I need to verify my domain name with google to confirm that I own it. To do that I need to create a TXT record in the DNS, which is currently hosted in Cloudflare. I’ve been wanting to get my Cloudflare DNS into Terraform for a while, so in this article we’re going to import my existing DNS settings into the Terraform state file, and then add a new TXT record to verify with google.

If you need to install Terraform check out my article on Getting Started with Terraform.

Our plan today

  1. Setup our new Terraform file
  2. Get our Cloudflare API key
  3. (Optional) Import our already existing DNS configuration from Cloudflare
  4. Create our DNS resources in our Terraform file
  5. Run our Terraform DNS configuration

1. Setup our new Terraform file

Create our new Terraform file in a new project directory

mkdir cloudflare-terraform
cd cloudflare-terraform
touch main.tf

Add the cloudflare provider to our terraform file

provider "cloudflare" {
  version = "~> 2.0"
  email = "[email protected]"
  api_key = "your-api-key"
}

Run terraform init

Run terraform init to setup the folder and download the providers declared in our main.tf terraform file.

terraform init

terraform init output

We can see that terraform has pulled down version 2.3 of the cloudflare provider.

2. Get our Cloudflare Global API key

  1. Login to Cloudflare with your credentials
  2. Click on My Profile at the top right
  3. Click on the 3rd tab “API Tokens”
  4. Click on View next to Global API Key
  5. Type in your password again to confirm it’s you
  6. Copy your API Key and store it somewhere super safe. Don’t give this to anyone that you don’t want to be able to access and modify your DNS.
  7. Add the generated token to your main.tf file.

3. (Optional) Import our already existing DNS configuration from Cloudflare

1. Add the Zone to our Terraform file

Let’s query the Cloudflare API to get the Zone ID of the domain that we want to import the DNS records for. By querying https://api.cloudflare.com/client/v4/zones/ it will output all zones information.

curl -X GET "https://api.cloudflare.com/client/v4/zones/"  -H "X-Auth-Key:YOUR_API_KEY" -H "X-Auth-Email:[email protected]" -H "Content-Type:application/json" | jq .

Find the domain (zone) that you want to import and copy the ID value, this is what we will use to import in to the state file.

2. Create a Zone entry in our Terraform file

Create a new resource with the type cloudflare_zone and name it something appropriate.

Mine looks like this:

resource "cloudflare_zone" "owendavies-net" {
 zone= "owendavies.net"
}

3. Import the zone in to the Terraform state file so that it knows about it.

Run the following command, replacing ZONE_ID with the ID that you copied in the first step.

terraform import cloudflare_zone.owendavies-net ZONE_ID

4. Check the Terraform file is correct

Now let’s run terraform plan and look at the output, if it complains and says that it’s going to make a change, that means that the cloudflare_zone resource you created in your terraform file is different to what terraform imported into the state file, it will tell you what changes there are, modify the resource until it says there are no changes to make when you run terraform plan.

terraform plan

5. Get DNS records from Cloudflare API

Run the following curl command replacing the YOUR_ZONE_ID and YOUR_API_KEY and email address.

curl -X GET "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/dns_records"  -H "X-Auth-Key:YOUR_API_KEY" -H "X-Auth-Email:[email protected]" -H "Content-Type:application/json" | jq . | tee importedcloudflare.json

This will query the Cloudflare api and return all the DNS records for the ZONE_ID that you specify, it will format it into JSON and save it to importedcloudflare.json

6. Create Terraform resource to match the above output

Open up the importedcloudflare.json file and create a new cloudflare_record resource matching the values in the importedcloudflare.json file.

When you have created the resource, find the id value in the importedcloudflare.json file.

7. Import the resource

Run the following command (replacing the ZONE_ID & DNS_RECORD_ID with your IDs) to import the resource into the terraform state file.

terraform import cloudflare_record.www-owendavies-net ZONE_ID/DNS_RECORD_ID

8. Test to see if the file matches the state

Run terraform plan which will show you what changes will be run (the differences between you state file and the main.tf file).

Make sure it says there are “No changes”, if there are any changes that it makes, go back and edit your resource in your main.tf file and try again.

terraform plan

My final terraform file:

In my case I have 2 CNAME records as well as the cloudflare zone itself (the domain).

provider "cloudflare" {
  version = "~> 2.0"
  email = "[email protected]"
  api_key = "your-api-key"
}

resource "cloudflare_zone" "owendavies-net" {
 zone= "owendavies.net"
}

resource "cloudflare_record" "owendavies-net" {
  zone_id = "ZONE_ID"
  name = "owendavies.net"
  value = "owen-davies.github.io"
  type = "CNAME"
  proxied = true
  ttl = 1
}

resource "cloudflare_record" "www-owendavies-net" {
  zone_id = "ZONE_ID"
  name = "www"
  value = "owen-davies.github.io"
  type = "CNAME"
  proxied = true
  ttl = 1
}

Now when I run terraform plan it says there are no changes to be applied

4. Create our DNS file in Terraform

Add a Cloudflare Zone resource

If you didn’t already do this during the (optional) import, you will need a cloudflare_zone resource.

resource "cloudflare_zone" "example" {
  zone = "example.com"
}

Add a record to the domain

In my case I’m adding a new TXT record to the domain that google wants to see to verify my domain ownership:

resource "cloudflare_record" "txt-owendavies-net" {
  zone_id = "ZONE_ID"
  name = "owendavies.net"
  value = "google-site-verification=JZMrzi_LveMVIyP8g5ZICIcPVYg39UPvyOjbLmRLuWU"
  type = "TXT"
  proxied = false 
  ttl = 1

5. Run our Terraform DNS configuration

Check the plan

Run terraform plan to see the changes that are going to happen

terraform plan

Check the output from the above terraform plan and make sure that all that terraform is going to do is add the new dns record, it shouldn’t be changing anything else if you added the resources correctly.

Make the changes

Now it’s time toe run terraform apply and make the change in Cloudflare.

terraform apply

Hopefully if everything has gone well, you now have your domain in Terraform, and a new record in the dns. You can now commit these changes to source control, and in the future can manage all your changes by Infrastructure as Code (IaC).