Cloudflare Terraform Provider 资源配置完全指南:Zone、Workers、存储、Rulesets 与 Zero Trust 的 HCL 实战
【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills
本指南基于 Skills 仓库 cloudflare-deploy 技能包中的 Terraform 配置参考文档,系统讲解使用官方cloudflare/cloudflareTerraform Provider 对 Cloudflare 全栈基础设施进行声明式管理的方法。你将掌握 Zone 与 DNS、Workers(含渐进式发布与各类 Binding)、KV/R2/D1/Queue 存储、Pages、Rulesets(WAF/重定向/缓存)、负载均衡与 Zero Trust Access 的完整 HCL 写法,并了解 v5 版本的关键变化与避坑要点,可直接用于生产环境的 IaC 落地。
阅读前准备:Provider 版本与认证
在动手写资源之前,先确认你使用的 Provider 版本。Cloudflare 官方 Terraform Provider 目前分两代:
| 版本 | 状态 | 说明 |
|---|---|---|
| 5.x | 当前版本 | 基于 OpenAPI 自动生成,与 v4 相比存在破坏性变更 |
| 4.x | 旧版 | 手动维护,已弃用 |
关键提醒:v5 对大量资源做了重命名,例如cloudflare_record→cloudflare_dns_record、cloudflare_worker_*→cloudflare_workers_*(注意是复数形式)。详细迁移对照见 gotchas.md 的 v5 破坏性变更章节。
基础 Provider 配置(来自 terraform/README.md):
terraform { required_version = ">= 1.0" required_providers { cloudflare = { source = "cloudflare/cloudflare" version = "~> 5.15.0" } } } provider "cloudflare" { api_token = var.cloudflare_api_token # 或使用 CLOUDFLARE_API_TOKEN 环境变量 }认证方式按推荐优先级排列:
- API Token(推荐):
api_token或CLOUDFLARE_API_TOKEN环境变量。在 Dashboard → My Profile → API Tokens 创建,建议将权限范围限定到具体 Account/Zone 以降低泄露风险。 - Global API Key(旧版):
api_key+api_email或CLOUDFLARE_API_KEY+CLOUDFLARE_EMAIL,安全性较低,优先使用 Token。 - User Service Key:
user_service_key,用于 Origin CA 证书场景。
常用命令速查:
terraform init # 初始化 Provider terraform plan # 预览变更 terraform apply # 应用变更 terraform destroy # 销毁资源 terraform import cloudflare_zone.example <zone-id> # 导入已有资源 terraform state list # 列出状态中的资源 terraform output # 查看输出 terraform fmt -recursive # 格式化代码 terraform validate # 校验配置Zone 与 DNS 配置
Zone 是 Cloudflare 管理的域名实体,配置时通过account对象语法指定所属账号,type = "full"表示完整托管(即使用 Cloudflare 的 Name Server)。
# Zone + 站点级设置 resource "cloudflare_zone" "example" { account = { id = var.account_id } name = "example.com" type = "full" } resource "cloudflare_zone_settings_override" "example" { zone_id = cloudflare_zone.example.id settings { ssl = "strict" # 严格 SSL:要求源站具备有效证书 always_use_https = "on" # 强制 HTTPS min_tls_version = "1.2" # 最低 TLS 版本 tls_1_3 = "on" # 启用 TLS 1.3 http3 = "on" # 启用 HTTP/3 (QUIC) } }DNS 记录支持 A、CNAME、MX、TXT 等类型。proxied = true表示开启橙色云代理(流量经过 Cloudflare 边缘),false则为仅 DNS 解析:
# A 记录 resource "cloudflare_dns_record" "www" { zone_id = cloudflare_zone.example.id name = "www" content = "192.0.2.1" type = "A" proxied = true } # 使用 for_each 批量创建 MX 记录(priority 对应 each.key) resource "cloudflare_dns_record" "mx" { for_each = { "10" = "mail1.example.com", "20" = "mail2.example.com" } zone_id = cloudflare_zone.example.id name = "@" content = each.value type = "MX" priority = each.key }提示:
for_each批量创建是处理多 MX、多 TXT(如 SPF/DKIM)等重复型记录的常用手法,可大幅减少样板代码。若需查询已有 Zone 而非新建,可参考 api.md 中的cloudflare_zoneData Source 用法。
Workers:两种部署模式
简单模式(旧式,仍可用)
使用cloudflare_workers_script一次性声明脚本内容、兼容日期与全部 Binding:
resource "cloudflare_workers_script" "api" { account_id = var.account_id name = "api-worker" content = file("worker.js") module = true compatibility_date = "2025-01-01" # 各类 Binding(详见下方 v5 Binding 类型表) kv_namespace_binding { name = "KV"; namespace_id = cloudflare_workers_kv_namespace.cache.id } r2_bucket_binding { name = "BUCKET"; bucket_name = cloudflare_r2_bucket.assets.name } d1_database_binding { name = "DB"; database_id = cloudflare_d1_database.app.id } secret_text_binding { name = "SECRET"; text = var.secret } }module = true表示使用 ES Module 格式的 Worker;compatibility_date决定运行时兼容行为版本。注意secret_text_binding的text应来自变量,严禁硬编码到源码。
渐进式发布(生产环境推荐)
生产环境推荐将「脚本定义」与「版本发布」分离,通过cloudflare_worker_version指定脚本内容与 SHA256 摘要(确保内容可校验),再用cloudflare_workers_deployment控制版本流量比例:
# 定义 Worker(不含内容) resource "cloudflare_worker" "api" { account_id = var.account_id name = "api-worker" } # 定义一个不可变版本 resource "cloudflare_worker_version" "api_v1" { account_id = var.account_id worker_name = cloudflare_worker.api.name content = file("worker.js") content_sha256 = filesha256("worker.js") compatibility_date = "2025-01-01" bindings { kv_namespace { name = "KV"; namespace_id = cloudflare_workers_kv_namespace.cache.id } r2_bucket { name = "BUCKET"; bucket_name = cloudflare_r2_bucket.assets.name } } } # 将版本发布到 100% 流量 resource "cloudflare_workers_deployment" "api" { account_id = var.account_id worker_name = cloudflare_worker.api.name versions { version_id = cloudflare_worker_version.api_v1.id percentage = 100 } }这种「Worker + Version + Deployment」三段式结构支持金丝雀发布:先发布percentage = 10观察指标,再逐步提升到 100,是生产环境的推荐做法。
Worker Binding 类型一览(Provider v5)
| Binding | 属性 | 示例 |
|---|---|---|
| KV | kv_namespace_binding | { name = "KV", namespace_id = "..." } |
| R2 | r2_bucket_binding | { name = "BUCKET", bucket_name = "..." } |
| D1 | d1_database_binding | { name = "DB", database_id = "..." } |
| Service | service_binding | { name = "AUTH", service = "auth-worker" } |
| Secret | secret_text_binding | { name = "API_KEY", text = "..." } |
| Queue | queue_binding | { name = "QUEUE", queue_name = "..." } |
| Vectorize | vectorize_binding | { name = "INDEX", index_name = "..." } |
| Hyperdrive | hyperdrive_binding | { name = "DB", id = "..." } |
| AI | ai_binding | { name = "AI" } |
| Browser | browser_binding | { name = "BROWSER" } |
| Analytics | analytics_engine_binding | { name = "ANALYTICS", dataset = "..." } |
| mTLS | mtls_certificate_binding | { name = "CERT", certificate_id = "..." } |
Binding 名称即 Worker 运行时env对象中的字段名,Worker 侧的类型定义与完整示例可参见 bindings/configuration.md(其中也提到所有类型 Binding 合计上限为 64 个)。
路由与定时触发器
Worker 需要路由才能对外提供服务,也支持 Cron 定时触发:
# HTTP 路由:api.example.com 下所有路径 resource "cloudflare_worker_route" "api" { zone_id = cloudflare_zone.example.id pattern = "api.example.com/*" script_name = cloudflare_workers_script.api.name } # Cron 触发器:每 5 分钟执行一次 resource "cloudflare_worker_cron_trigger" "task" { account_id = var.account_id script_name = cloudflare_workers_script.api.name schedules = ["*/5 * * * *"] }Cron 调度表达式使用标准 Unix Cron 语法,完整能力可参考 cron-triggers。
存储资源:KV、R2、D1 与 Queue
# KV:命名空间 + 预置一个键值对(值为 JSON) resource "cloudflare_workers_kv_namespace" "cache" { account_id = var.account_id title = "cache" } resource "cloudflare_workers_kv" "config" { account_id = var.account_id namespace_id = cloudflare_workers_kv_namespace.cache.id key_name = "config" value = jsonencode({ version = "1.0" }) } # R2:对象存储桶(location 必须大写,详见下方避坑) resource "cloudflare_r2_bucket" "assets" { account_id = var.account_id name = "assets" location = "WNAM" } # D1:关系型数据库(schema 迁移需通过 wrangler 执行,见下文) resource "cloudflare_d1_database" "app" { account_id = var.account_id name = "app-db" } # Queue:消息队列 resource "cloudflare_queue" "events" { account_id = var.account_id name = "events-queue" }注意细节:
- KV 键名:v5 中属性名为
key_name(v4 为key),同时需要namespace_id关联命名空间。 - R2 location 大小写:
location必须使用大写字母,如WNAM、ENAM、WEUR、EEUR、APAC,小写会导致创建后再次 apply 失败(见 gotchas.md)。 - D1 只建库不建表:Terraform 仅创建 D1 数据库资源本身,表结构与数据迁移必须用 wrangler 完成:
wrangler d1 migrations apply <db-name>。 - 上述资源创建后即可在上文 Worker Binding 中引用(
id/name/bucket_name/database_id),形成完整的资源依赖链。
Pages 项目
Pages 适合前端静态站点与全栈应用,Terraform 中通过cloudflare_pages_project管理项目、环境变量、构建配置与 Git 源:
resource "cloudflare_pages_project" "site" { account_id = var.account_id name = "site" production_branch = "main" deployment_configs { production { compatibility_date = "2025-01-01" environment_variables = { NODE_ENV = "production" } kv_namespaces = { KV = cloudflare_workers_kv_namespace.cache.id } d1_databases = { DB = cloudflare_d1_database.app.id } } } build_config { build_command = "npm run build" destination_dir = "dist" } source { type = "github" config { owner = "org" repo_name = "site" production_branch = "main" } } } # 绑定自定义域名 resource "cloudflare_pages_domain" "custom" { account_id = var.account_id project_name = cloudflare_pages_project.site.name domain = "site.example.com" }deployment_configs.production中可按环境注入 KV/D1 Binding 与环境变量;build_config控制构建命令与产物目录;source声明 GitHub 源码仓库,实现推送即部署。
已知问题:
cloudflare_pages_project的deployment_configs.*存在状态漂移(Cloudflare API 会回填默认值),建议在lifecycle中加入ignore_changes = [deployment_configs],详见 gotchas.md 的状态漂移章节。
Rulesets:WAF、重定向与缓存规则
Ruleset 是 Cloudflare 统一的规则引擎,通过phase指定作用阶段:
# WAF 自定义规则:拦截机器人流量(但放行 Cloudflare 验证过的机器人) resource "cloudflare_ruleset" "waf" { zone_id = cloudflare_zone.example.id name = "WAF" kind = "zone" phase = "http_request_firewall_custom" rules { action = "block" enabled = true expression = "(cf.client.bot) and not (cf.verified_bot)" } } # 动态重定向:/old → https://example.com/new(301) resource "cloudflare_ruleset" "redirects" { zone_id = cloudflare_zone.example.id name = "Redirects" kind = "zone" phase = "http_request_dynamic_redirect" rules { action = "redirect" enabled = true expression = "(http.request.uri.path eq \"/old\")" action_parameters { from_value { status_code = 301 target_url { value = "https://example.com/new" } } } } } # 缓存规则:对静态资源开启边缘缓存,TTL 覆盖源站为 86400 秒 resource "cloudflare_ruleset" "cache" { zone_id = cloudflare_zone.example.id name = "Cache" kind = "zone" phase = "http_request_cache_settings" rules { action = "set_cache_settings" enabled = true expression = "(http.request.uri.path matches \"\\.(jpg|png|css|js)$\")" action_parameters { cache = true edge_ttl { mode = "override_origin" # 覆盖源站 Cache-Control default = 86400 } } } }关键点:
- phase 决定规则类型:
http_request_firewall_custom(WAF 自定义规则)、http_request_dynamic_redirect(动态重定向)、http_request_cache_settings(缓存设置)。 expression使用 Cloudflare 规则表达式语言,支持eq、matches等操作符与cf.*、http.request.*字段。- WAF 规则表达式中
cf.client.bot判断客户端是否为机器人,cf.verified_bot识别通过验证的合法爬虫,两者组合可实现精准拦截。WAF 更多玩法见 waf。
负载均衡(Load Balancers)
由「健康检查 Monitor + 源站池 Pool + 负载均衡器 LB」三层组成:
# 健康检查:每 60 秒对 /health 发起 HTTP 探测,超时 5 秒 resource "cloudflare_load_balancer_monitor" "http" { account_id = var.account_id type = "http" path = "/health" interval = 60 timeout = 5 } # 源站池:挂载 Monitor,声明多个源站 resource "cloudflare_load_balancer_pool" "api" { account_id = var.account_id name = "api-pool" monitor = cloudflare_load_balancer_monitor.http.id origins { name = "api-1" address = "192.0.2.1" } origins { name = "api-2" address = "192.0.2.2" } } # 负载均衡器:绑定默认池,启用基于地理位置的流量调度 resource "cloudflare_load_balancer" "api" { zone_id = cloudflare_zone.example.id name = "api.example.com" default_pool_ids = [cloudflare_load_balancer_pool.api.id] steering_policy = "geo" }steering_policy = "geo"表示按访问者地理位置就近分配。多区域场景(如美东/西欧双池 +region_pools)的完整写法可参考 patterns.md 的「Multi-Region Load Balancing」用例。
Access(Zero Trust)
通过 Access 为内部系统增加身份认证层:应用(Application)+ 策略(Policy)+ 身份源(Identity Provider)三者配合:
# 身份源:接入 GitHub OAuth resource "cloudflare_access_identity_provider" "github" { account_id = var.account_id name = "GitHub" type = "github" config { client_id = var.github_id client_secret = var.github_secret } } # 受保护的应用:admin.example.com(自托管) resource "cloudflare_access_application" "admin" { account_id = var.account_id name = "Admin" domain = "admin.example.com" type = "self_hosted" session_duration = "24h" allowed_idps = [cloudflare_access_identity_provider.github.id] } # 访问策略:仅允许指定邮箱登录 resource "cloudflare_access_policy" "allow" { account_id = var.account_id application_id = cloudflare_access_application.admin.id name = "Allow" decision = "allow" precedence = 1 include { email = ["admin@example.com"] } }要点说明:
allowed_idps限定该应用可用的身份源;session_duration控制会话有效期。precedence决定多条策略的匹配优先级,数值越小优先级越高。decision支持allow/deny/non_identity等,可组合出「先拒绝、后放行」的分层策略。cloudflare_access_*系列在 v5 中已更名为cloudflare_zero_trust_*,迁移时需注意。
实战避坑与最佳实践
状态漂移(State Drift)
部分资源存在已知漂移问题,可通过lifecycle.ignore_changes消除永久 diff:
| 资源 | 漂移属性 | 处理方式 |
|---|---|---|
cloudflare_pages_project | deployment_configs.* | ignore_changes = [deployment_configs] |
cloudflare_workers_script | secrets 返回为 REDACTED | ignore_changes = [secret_text_binding] |
cloudflare_load_balancer | adaptive_routing、random_steering | ignore_changes = [adaptive_routing, random_steering] |
cloudflare_workers_kv | 键含特殊字符(< 5.16.0) | 升级到 5.16.0+ |
示例:忽略 Secret 漂移
resource "cloudflare_workers_script" "api" { account_id = var.account_id name = "api-worker" content = file("worker.js") secret_text_binding { name = "API_KEY"; text = var.api_key } lifecycle { ignore_changes = [secret_text_binding] } }v5 破坏性变更速查
资源重命名:
| v4 | v5 |
|---|---|
cloudflare_record | cloudflare_dns_record |
cloudflare_worker_script | cloudflare_workers_script(注意复数) |
cloudflare_worker_* | cloudflare_workers_* |
cloudflare_access_* | cloudflare_zero_trust_* |
属性变更:
| v4 | v5 | 适用资源 |
|---|---|---|
zone | name | Zone |
account_id | account.id(对象语法) | Zone |
key | key_name | KV |
location_hint | location | R2 |
状态迁移命令:
terraform state mv cloudflare_record.example cloudflare_dns_record.example terraform state mv cloudflare_worker_script.api cloudflare_workers_script.api常见错误排查
- "Error: couldn't find resource":资源被 Terraform 之外删除。用
terraform import cloudflare_zone.example <zone-id>重新导入,或terraform state rm cloudflare_zone.example从状态移除。 - "409 Conflict on worker deployment":Terraform 与 wrangler 同时部署同一 Worker,须二选一。
- "DNS record already exists":已有记录未导入状态。在 Dashboard 找到 record ID 后用
terraform import cloudflare_dns_record.example <zone-id>/<record-id>导入。 - "Invalid provider configuration":API Token 缺失、无效或权限不足,检查
CLOUDFLARE_API_TOKEN环境变量与 Dashboard 中的 Token 权限。 - "State locking errors":并发运行或残留锁,谨慎使用
terraform force-unlock <lock-id>。 - Worker 脚本超过 10 MB:脚本与依赖总大小受限,使用代码拆分、外部依赖或压缩。
工具链协作约定
- Terraform 负责:Zone、DNS、安全规则、Access、负载均衡、Worker 部署(CI/CD)、KV/R2/D1 资源创建。
- Wrangler 负责:本地开发(
wrangler dev)、手动部署、D1 迁移、KV 批量操作、日志流(wrangler tail)。 - 核心铁律:同一资源严禁同时被 Terraform 与 wrangler 管理,否则会出现状态冲突(如 409)。
- 团队环境务必使用远程状态后端(S3、Terraform Cloud 等),R2 作为 S3 兼容后端的完整 backend 配置见 patterns.md。
更多参考
- Provider 配置与认证:Provider 版本、三种认证方式、常用命令与 cf-terraforming 导入工具
- Data Sources 参考:查询已有 Zone、Worker、KV、IP 段等资源,以及跨模块引用与 output 用法
- 架构模式与多环境:目录结构、多环境、R2 状态后端、CI/CD 集成、完整用例
- 故障排查与最佳实践:状态漂移、v5 迁移、资源专属坑点、限额明细
【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考