Using Terraform on Cloudflare

I wanted to use Terraform on Cloudflare for quite a while. Unfortunately, I could not find an example that shows how to loop through multiple zones in my account. I used some general examples and some queries in ChatGPT to assist with the looping aspect. I now have a generic template set up.

Getting Started With Terraform

You first need the initial blocks to set up the provider and your account information. My example uses the Global API Key, since I created it to configure all settings in all zones. Remember that a Global API Key is somewhat equivalent to your account password that controls all settings in the dashboard. Protect that key as you would a password.

terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 4.0"
    }
  }
}

provider "cloudflare" {
  email   = "me@example.com"
  api_key = "global_api_key_goes_here"
}

Setting Up The List

Next is the logic for the automation. It needs to set a local variable for the list of domains, count them to set up the array, then put their Zone IDs into that array.

### Domain Names List
locals {
  domains = ["example1.com", "example2.com"]
}

### Domain Name Count
data "cloudflare_zones" "zones" {
  count = length(local.domains)
  filter {
    name = element(local.domains, count.index)
  }
}

### Zone ID Array
locals {
  zones_ids = { for k, v in data.cloudflare_zones.zones : k => v.zones[0].id }
}

Setting Your Cloudflare Resources

Now that you have set the array of zones, you can begin to define settings that use the loop created above to apply those settings to each zone. Each resource will run through a for_each loop, dynamically setting the Zone ID. Therefore, if you need to reference the domain name, you can use the ${element(local.domains, each.key)} variable.

The following example creates a Cache Rule to bypass cache for a specific hostname.

resource "cloudflare_ruleset" "cache_rules_example" {
  for_each    = local.zones_ids
  zone_id     = each.value
  name        = "Bypass cache settings"
  description = "Set cache settings for incoming requests"
  kind        = "zone"
  phase       = "http_request_cache_settings"

  rules {
    action = "set_cache_settings"
    action_parameters {
      cache = false
    }
    expression  = "(http.host eq \"bypass.${element(local.domains, each.key)}\")"
    description = "Bypass cache rule for ${element(local.domains, each.key)}"
    enabled     = true
  }
}

Importing Current Settings

If you’ve already looked into Terraform, then you’ll know you can not use Terraform on Cloudflare for existing settings. Nor can you manually control those settings in the dashboard if Terraform is set up for that. Terraform keeps a state file of the existing settings, and will not run if its state file does not match the current settings.

Cloudflare has a tool called cf-terraforming, which can dump your existing settings into your .tf file. To get started, you’ll need the Getting Started blocks I described earlier. Then you can use the following command to dump the configuration for a specific resource into Terraform format:

cf-terraforming generate -e ME@EXAMPLE.com -k GLOBAL_API_KEY -z ZONE_ID --resource-type RESOURCE_TYPE