将 cloudflare_zone_settings_override 应用于多个区域

Apply cloudflare_zone_settings_override to multiple zones

我刚刚接触 Terraform,但我没有看到一个明显的方法来防止我重复自己。

我在 Cloudlfare 中有很多区域需要管理。这些区域都有非常相似的设置,我希望我的 .tf 文件既简短又可读。

假设我有 example1.com example2.com example3.com...我用以下代码添加它们:

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

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

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

到目前为止一切顺利。

现在我想使用 cloudflare_zone_settings_override 提供商将一些相同的设置应用到我的所有区域。

查看文档,这对于一个区域来说是直截了当的。但我宁愿不必为每个区域都这样做:

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"
        }
    }
}

将这些应用到 Cloudflare 中所有(或部分)区域的最佳方法是什么?

谢谢

为了避免重复 Terraform 代码,您可以:

  • 创建一个module并使用它三次
  • count 属性 设置为三个并创建一个域名列表

第二种解决方案的示例:

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:此代码是为 terraform < 0.12

编写的

Terraform 有几种方法可以最大限度地减少重复自己。

您可以循环遍历列表,使用 count meta-parameter 根据需要创建资源:

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"
    }
  }
}

请注意在区域名称的区域设置中使用 "${cloudflare_zone.zones.*.zone[count.index]}"。这将确保 Terraform 知道它需要在创建区域设置覆盖之前创建 Cloudflare 区域,而不是看不到两者之间的依赖关系并尝试同时创建它们,这可能会失败,因为区域还没有在 Terraform 尝试创建区域设置覆盖时创建。

或者您可以将区域配置移出 module,允许您抽象事物,为模块调用者提供更多受限的资源控制量:

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"
    }
  }
}

此模块然后有一个必需的变量 zone 和一个可选的默认变量 waf 来控制是否为该区域启用 WAF。所有其他选项都是为调用者设置的,因此可以像这样简单地多次调用该模块:

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

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

使用此 module 的替代解决方案。这是一个 ready-to-use 示例:

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"
  }
}