ScruffyDan
ScruffyDan

Reputation: 23

Apply cloudflare_zone_settings_override to multiple zones

I am just getting my feet wet with Terraform but I don't see an obvious way to keep me from repeating myself.

I have a bunch of zones in Cloudlfare that I want to manage. These zones will all have very similar settings and I want my .tf files to be both short and readable.

Lets say I have example1.com example2.com example3.com... I add them with the following code:

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

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

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

So far so good.

Now I want to apply some identical settings to all my zones using the cloudflare_zone_settings_override provider.

Looking at the documentation this is straight forward for one zone. But I would rather not have to do this for each zone:

resource "cloudflare_zone_settings_override" "example1" {
    name = "$example1.com"
    settings {
        brotli = "on"
        security_level = "high"
        opportunistic_encryption = "on"
        automatic_https_rewrites = "on"
        mirage = "on"
        waf = "on"
        minify {
            css = "on"
            js = "off"
            html = "off"
        }
    }
}

What is the best way to apply these to all (or some) of the zones in Cloudflare?

Thanks

Upvotes: 2

Views: 943

Answers (3)

fallincode
fallincode

Reputation: 509

Alternative solution using this module. Here is a ready-to-use example:

terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = ">= 3.12.1"
    }
  }
}

variable "cloudflare_api_token" {
  type      = string
  sensitive = true
}

provider "cloudflare" {
  api_token = var.cloudflare_api_token
}

locals {
  # All your zones go here
  zones = ["acme.com", "example.com"]
}

module "zones" {
  source  = "registry.terraform.io/alex-feel/zone/cloudflare"
  version = "1.7.0"

  for_each = toset(local.zones)

  zone = each.value

  brotli                   = "on"
  security_level           = "high"
  opportunistic_encryption = "on"
  automatic_https_rewrites = "on"
  mirage                   = "on"
  waf                      = "on"
  minify = {
    css = "on"
  }
}

Upvotes: 0

ydaetskcoR
ydaetskcoR

Reputation: 56887

Terraform has a couple of ways of minimising repeating yourself.

You could loop through a list, using the count meta-parameter creating resources as necessary:

variable "zones" {
  type = "list"
}

resource "cloudflare_zone" "zones" {
  count = "${length(var.zones)}"
  zone  = "${var.zones[count.index]}"
}

resource "cloudflare_zone_settings_override" "settings" {
  count = "${length(var.zones)}"
  name  = "${cloudflare_zone.zones.*.zone[count.index]}"

  settings {
    brotli                   = "on"
    security_level           = "high"
    opportunistic_encryption = "on"
    automatic_https_rewrites = "on"
    mirage                   = "on"
    waf                      = "on"

    minify {
      css  = "on"
      js   = "off"
      html = "off"
    }
  }
}

Note the use of "${cloudflare_zone.zones.*.zone[count.index]}" in the zone settings for the zone name. This will make sure that Terraform knows that it needs to create the Cloudflare zone before creating the zone settings override rather than not seeing a dependency between the two and trying to create them both at the same time which may potentially fail as the zone is not yet created when Terraform attempts to create the zone settings override.

Or you could move the zone configuration out to a module, allowing you to abstract things, providing a more constrained amount of control of a resource to the module caller:

modules/cloudflare-zone/main.tf

variable "zone" {}

variable "waf" {
  default = "on"
}

resource "cloudflare_zone" "zone" {
  zone = "${var.zone}"
}

resource "cloudflare_zone_settings_override" "settings" {
  name = "${cloudflare_zone.zone.zone}"

  settings {
    brotli                   = "on"
    security_level           = "high"
    opportunistic_encryption = "on"
    automatic_https_rewrites = "on"
    mirage                   = "on"
    waf                      = "${var.waf}"

    minify {
      css  = "on"
      js   = "off"
      html = "off"
    }
  }
}

This module then has a required variable of zone and an optional, defaulted variable of waf that controls whether to enable the WAF for the zone. All the other options are set for the caller so the module can simply be called multiple times like this:

module "cloudflare_zone_example1" {
  source = "path/to/module"
  zone   = "example1.com"
}

module "cloudflare_zone_example2" {
  source = "path/to/module"
  zone   = "example2.com"
  waf    = "off"
}

Upvotes: 2

Quentin Revel
Quentin Revel

Reputation: 1478

In order to avoid repetition of Terraform code, you could:

  • create a module and use it three times
  • set the count property to three and create a list of your domain names

Example for the second solution:

local {
    domain_names = [
        example1.com,
        example2.com,
        example3.com
    ]
}

resource "cloudflare_zone" "these_zones" {
    count = "${length(local.domain_names)}"
    zone = "${element(local.domain_names, count.index)}"
}

resource "cloudflare_zone_settings_override" "these_zones_settings" {
    count = "${length(local.domain_names)}"
    name = "${element(local.domain_names, count.index)}"
    settings {
        brotli = "on"
        security_level = "high"
        opportunistic_encryption = "on"
        automatic_https_rewrites = "on"
        mirage = "on"
        waf = "on"
        minify {
            css = "on"
            js = "off"
            html = "off"
        }
    }
}

PS: This code is written for terraform < 0.12

Upvotes: 0

Related Questions