Quick Links

Terraform is a popular infrastructure as code tool, and when paired with CloudFlare, makes managing complex configurations within CloudFlare much easier. For those not familiar, Terraform uses the HCL configuration language to define an infrastructure configuration that can then be used to apply the requested settings to the provider. CloudFlare offers DNS services, security, and edge computing services that pair perfectly with the Terraform tool.

Installing Terraform

Terraform can be used either on Windows or on Linux. The Terraform binary itself is a single executable, and merely needs to be downloaded and placed into the path of the system.

Windows Installation

First, you will need to download the Terraform executable for Windows. Once downloaded, place the executable in a Windows path location. If you need to put the executable in a different location but would like it accessible at any time, you can use the following PowerShell code to modify the user's PATH environmental variable.

        [System.Environment]::SetEnvironmentVariable("PATH",(($Env:PATH, "C:\Tools") -Join ";"),"User")

This can be used to modify the system PATH by changing User to Machine. You will need Administrative rights to do this.

Linux Installation

Much like Windows, you will download the latest release of Terraform. Because you might not always be using a GUI, you can do this via the following shell code. Replace {release} with the version of the code, like 0.13.0.

        wget <https://releases.hashicorp.com/terraform/{release}/terraform_{release}_linux_amd64.zip>
unzip terraform_{release}_linux_amd64.zip
mv terraform /usr/bin/

Setting Up Terraform for CloudFlare

To contain our Terraform configuration, we are going to make a directory to hold the .tf files, which are the extension of the Terraform configuration files. Create a new directory to hold the configuration.

PowerShell 7 on Windows

        New-Item -Name 'CF_Terraform' -Type 'Directory'
Set-Location -Path 'CF_Terraform'

Bash Shell on Linux

        mkdir cf_terraform
cd cf_terraform

Once you have created and navigated to the directory, we will need to initialize the Terraform configuration. We first need to create our configuration file. We are opting to not hardcode our credentials into the configuration file. Instead, a file will pass in those credentials that are excluded from version control. Speaking of which, Git is highly recommended to keep track of the changes.

cloudflare.tf

        variable "api_token" {}

provider "cloudflare" {
  version = "~> 2.9"
  api_token = var.api_token
}

The following .auto.tfvars file will contain the secrets that we pass into Terraform but do not want to commit to version control history.

cloudflare.auto.tfvars

        # Zone.DNS Permissions
# Example token below
api_token = "as3uo7WkxL6asdfasdfaME7IdLofKBG9C_Zi-gf"

The reason for the .auto section of the .tfvars filename is that this variable folder will be automatically read by Terraform on operations instead of explicitly passing it in via -var-file="cloudflare.tfvars".

Now that we have both of our files configured, it is time to initialize our configuration. This will install any providers that have been specified in the provider section of our Terraform configuration file.

        terraform init
    
Initializing our configuration will install any providers specified in provider section of our Terraform configuration file.

Defining the Terraform CloudFlare Configuration

Now that we have successfully connected to our domain, we need to create our configuration. The first thing we need to do is modify our cloudflare.auto.tfvars file to include the zone_id that we are going to be targeting the DNS records modifications to. Add the following line into the cloudflare.auto.tfvars file.

        # Zone.DNS Permissions
api_token = "as3uo7WkxL6asdfasdfaME7IdLofKBG9C_Zi-gf"
# Specific Domain Zone ID
zone_id = "fddd89b6e1d52ebdfdasdc8bc02186333"

Next, we need to define the records that we are going to add to CloudFlare. To do this, we are going to use the cloudflare_record resource to create the records. The format of this is the following: resource {type} {name}. The type will be cloudflare_record, and for the name we will use a_mydomain_com and cname_www. These names are arbitrary though, and they can be whatever you would like.

        resource "cloudflare_record" "a_mydomain_com" {
  zone_id = var.zone_id
  name = "mydomain.com"
  value = "133.145.220.110"
  type = "A"
  ttl = 1
  proxied = true
}

resource "cloudflare_record" "cname_www" {
  zone_id = var.zone_id
  name = "www"
  value = "mydomain.com"
  type = "CNAME"
  ttl = 1
  proxied = true
}

One caveat about the names. If you want to use terraform import to import state on a given record, you will have to match the name with the import record like so:

terraform import cloudflare_record.a_mydomain_com {zone_id}/{record_id}

Planning the Terraform Changes

Now that we have our configuration defined, we can run the terraform plan command, which will generate the changes between what is known by Terraform via the .tfstate file and the CloudFlare environment. If resources have not been imported, or this is the first time running the command, then Terraform will have no knowledge of the environment and all changes will be new.

        terraform plan
    
Run the terraform plan command

Applying the Terraform Changes

Once you are confident in your configuration, simply use the apply command. This will prompt for a confirmation, where you need to type yes. The output will show the configuration to apply and the state.

        terraform apply
    
Use apply command to prompt a confirmation, then type yes. The output shows the configuration to apply and the state.

Conclusion

Combining CloudFlare and Terraform is a potent combination. When you are able to architect your environment in code and track changes over time (using version control), you unlock new efficiencies and control. In the event that a configuration is incorrect, it is trivial to roll back to a prior configuration, which makes recovering from errors very quick and painless.