如何用Terraform生成Cloudflare client certificate并上传AWS ACM
Terraform 实现Cloudflare客户端证书生成+上传AWS ACM方案
Cloudflare官方Terraform provider直到4.16.0版本才支持客户端证书相关资源,你之前搜所有带"cert"字样的资源找不到是正常的——这类资源归在Zero Trust/Access分类下,资源名不带通用的cert前缀,很容易漏。如果是老版WAF下的客户端证书功能,目前还没有原生资源覆盖,可以用CLI调用的方式实现全自动化。
前置依赖配置
首先锁定provider版本,避免版本不兼容导致资源不存在:
terraform { required_providers { cloudflare = { source = "cloudflare/cloudflare" version = ">= 4.16.0" } aws = { source = "hashicorp/aws" version = ">= 5.0" } tls = { source = "hashicorp/tls" version = ">= 4.0" } null = { source = "hashicorp/null" version = ">= 3.0" } } } provider "cloudflare" { api_token = var.cloudflare_api_token } provider "aws" { region = var.aws_region }
- Cloudflare API Token需要根据你选的方案开对应权限:Zero Trust场景开Access服务编辑权限,传统WAF场景开SSL与证书编辑权限
- 私钥全程在本地生成,不会上传到Cloudflare,务必严格管控Terraform状态文件的访问权限
方案1:原生资源实现(适配Zero Trust Access mTLS场景)
这是官方原生支持的实现方式,不需要依赖外部CLI,证书生命周期完全由Terraform托管:
# 本地生成证书私钥和CSR resource "tls_private_key" "client_cert" { algorithm = "RSA" rsa_bits = 2048 } resource "tls_cert_request" "client_cert" { key_algorithm = tls_private_key.client_cert.algorithm private_key_pem = tls_private_key.client_cert.private_key_pem subject { common_name = "automated-service-client" } } # 生成Cloudflare客户端证书 resource "cloudflare_zero_trust_access_mtls_certificate" "client_cert" { account_id = var.cloudflare_account_id name = "service-cert-${formatdate("YYYYMMDD-hhmm", timestamp())}" validity_days = 365 csr = tls_cert_request.client_cert.csr_pem } # 开启对应域名的客户端证书转发(可选,按需配置) resource "cloudflare_zero_trust_access_mtls_hostname_settings" "mtls_conf" { account_id = var.cloudflare_account_id hostname = var.service_domain client_certificate_forwarding = true }
方案2:CLI调用实现(适配传统WAF mTLS场景)
如果用的是SSL/TLS菜单下的传统客户端证书功能,目前没有对应原生资源,可以通过local-exec调Cloudflare官方API生成,完全纳入Terraform生命周期管理:
resource "tls_private_key" "client_cert" { algorithm = "RSA" rsa_bits = 2048 } resource "tls_cert_request" "client_cert" { key_algorithm = tls_private_key.client_cert.algorithm private_key_pem = tls_private_key.client_cert.private_key_pem subject { common_name = "automated-service-client" } } resource "null_resource" "gen_client_cert" { triggers = { cert_id = timestamp() } provisioner "local-exec" { command = <<EOT curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${var.cloudflare_zone_id}/client_certificates" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{"validity_days":365,"csr":"${tls_cert_request.client_cert.csr_pem}"}' > cert_resp.json jq -r '.result.certificate' cert_resp.json > client_cert.pem jq -r '.result.certificate_authority.certificate' cert_resp.json > ca_chain.pem EOT environment = { CF_API_TOKEN = var.cloudflare_api_token } } } data "local_file" "client_cert_pem" { filename = "${path.module}/client_cert.pem" depends_on = [null_resource.gen_client_cert] } data "local_file" "ca_chain_pem" { filename = "${path.module}/ca_chain.pem" depends_on = [null_resource.gen_client_cert] }
证书上传至AWS ACM
两种方案生成的证书都可以用下面的配置自动上传到ACM,注意方案1如果需要CA链,可以从Cloudflare控制台对应CA详情里复制后配置变量传入:
resource "aws_acm_certificate" "cf_client_cert" { private_key = tls_private_key.client_cert.private_key_pem certificate_body = try(cloudflare_zero_trust_access_mtls_certificate.client_cert.certificate, data.local_file.client_cert_pem.content) certificate_chain = try(var.cloudflare_ca_chain, data.local_file.ca_chain_pem.content, null) lifecycle { create_before_destroy = true } tags = { AutoManaged = "Terraform" Purpose = "Cloudflare-mTLS" } }
配置提示:可以给证书资源加
replace_triggered_by配置,绑定时间触发条件实现证书到期自动轮换,不需要人工干预。
内容的提问来源于stack exchange,提问作者Tomas Griušys
相关产品推荐
相关产品推荐

