Best practices
Though all Terraform deployments are unique, follow these best practices to set yourself up for success.
Terraform works best when it manages all changes to and the lifecycle of a resource.
After any operation on the configuration, Terraform attempts to reconcile the differences by syncing the remote into the local state. If there are differences in the local and remote - caused by managing resources outside of Terraform - you may need to delete and recreate the resource in the state file (usually via importing) as not all resources support in-place updates.
Cloudflare recommends using a directory structure that relies on a combination of accounts, zones, and products for isolating changes. This setup lets you have fine-grained owners and scoped Terraform operations to a specific product in a zone. It also more closely aligns owners with Cloudflare’s default roles, as well as additional tools like AWS or GCP storage by permissioning separate state files.
For products that encompass many responsibilities such as Rulesets, you can extend this even further by partitioning at the phase level (WAF, redirects, origin rules).
Terraform modules are ways of encapsulating multiple resources with logic in an abstracted interface. Consider the example where a module sets up default load balancer with a pool, some DNS entries, and perhaps a page rule. The end user may use it like this:
In terms of Terraform resources, however, the above example would be translated to:
While convenient, this setup can cause unanticipated issues. If this module is shared and then changes internally, the module may have resources out of sync or recreated.
Using modules also increases the difficulty of debugging or reproducing issues as you must then factor in potential logic bugs outside of Terraform core and the Cloudflare provider.
Cloudflare recommends using cf-terraforming
to migrate existing resources into Cloudflare.
It is perfectly fine to manage some resources inside Terraform and others using a different tool, but make sure you are not doing both for the same resource.
To safely manage separate environments (staging, QA, UAT, production), use separate Cloudflare accounts with separate domains (such as example.com
and example-staging.com
).
This is because some products defined at the account level are shared (such as Load Balancer monitors and pools) and you cannot make an isolated change to them if they are in the same account. Using separate accounts is also beneficial if you intend to test things like DNSSEC, which may affect your entire domain if configured incorrectly.
To minimize drift, use Terraform and a CI/CD pipeline that runs across both domains to keep them in sync as needed.
We do not recommend storing Cloudflare credentials as plaintext.
Locally, you can use a third-party tool like cf-vault ↗ to store your Cloudflare credentials.
For CI pipelines, use an internal or secret storage tool (such as Vault ↗).