Treating production accounts as code
Cloudflare runs its own platform as "Customer Zero," using the same security products it sells to keep internal services safe. The security division's dedicated Customer Zero team manages hundreds of production Cloudflare accounts — which makes a single bad configuration dangerous: one mistake can propagate across the edge in seconds, lock employees out of critical applications, or take down a production service.
The operational problem is scale. Manually checking security settings across hundreds of accounts through the dashboard is error-prone and tedious. Cloudflare's answer was to stop treating configurations as point-and-click tasks and manage them as code, shifting security validation to the earliest stages of the development lifecycle before failures reach production.
That shift rests on four principles:
- Consistency: Configurations must be reusable across accounts.
- Scalability: Large changes must apply rapidly to many accounts at once.
- Observability: Anyone must be able to audit current state and accuracy.
- Governance: Guardrails must block bad deployments before they happen.
The production IaC operating model
All production accounts are now managed with Infrastructure as Code (IaC). Every modification is tracked to a user, a commit, and an internal ticket. Teams still use the dashboard for analytics and insights, but critical changes flow through code review. Security policy is set centrally, while owning engineering teams implement their own configuration changes in a shared repository.
Two technologies anchor the stack:
- Terraform with the Cloudflare provider, chosen for its ecosystem and deep Policy as Code integrations.
- Atlantis integrated with GitLab, which runs roughly 30 merge requests per day across the accounts.
State files are handled by a custom Go program, tfstate-butler, which acts as a Terraform HTTP backend. Its security design ensures each state file gets a unique encryption key, limiting the blast radius if any single file is compromised. Configuration for all internal accounts lives in a centralized monorepo where individual teams are code owners of their slices.
Infrastructure as Code data flow:

Baseline security enforced by policy
The entire shift-left strategy depends on a firm security baseline applied to every internal production account. The baseline is curated by the security team as Policy as Code — required configurations covering items like session length, logging, and WAF settings.
Enforcement uses Open Policy Agent (OPA) and its policy language Rego, integrated through the Atlantis Conftest Policy Checking feature. Around 50 Rego policies currently define the baseline for Cloudflare provider resources. As an example, one policy ensures that only @cloudflare.com email addresses can be used in access policies.
# validate no use of non-cloudflare email
warn contains reason if {
r := tfplan.resource_changes[_]
r.mode == "managed"
r.type == "cloudflare_access_policy"
include := r.change.after.include[_]
email_address := include.email[_]
not endswith(email_address, "@cloudflare.com")
reason := sprintf("%-40s :: only @cloudflare.com emails are allowed", [r.address])
}
warn contains reason if {
r := tfplan.resource_changes[_]
r.mode == "managed"
r.type == "cloudflare_access_policy"
require := r.change.after.require[_]
email_address := require.email[_]
not endswith(email_address, "@cloudflare.com")
reason := sprintf("%-40s :: only @cloudflare.com emails are allowed", [r.address])
}
Policy checks run on every merge request (MR) before deployment, with output posted directly in the GitLab MR comment thread. Enforcement operates in two modes:
- Warning: comments on the MR but permits the merge.
- Deny: blocks the deployment outright.
When a proposed change deviates from the baseline, the check identifies exactly which resources are out of compliance.
WARN - cloudflare_zero_trust_access_application.app_saas_xxx :: "session_duration" must be less than or equal to 10h
WARN - cloudflare_zero_trust_access_application.app_saas_xxx_pay_per_crawl :: "session_duration" must be less than or equal to 10h
WARN - cloudflare_zero_trust_access_application.app_saas_ms :: you must have at least one require statement of auth_method = "swk"
41 tests, 38 passed, 3 warnings, 0 failures, 0 exception
Some exceptions are unavoidable, but they follow the same rigor as the policies themselves. Teams request exceptions through Jira; once approved by the Customer Zero team, the exception is merged into a central exceptions.rego repository. Exceptions can be scoped at three levels:
- Account: exclude an entire account from a policy.
- Resource category: exclude a resource type within a specific account.
- Specific resource: exclude one named resource in an account.
The following example shows a session-length exception granted for five named applications under two separate accounts:
{
"exception_type": "session_length",
"exceptions": [
{
"account_id": "1xxxx",
"tf_addresses": [
"cloudflare_access_application.app_identity_access_denied",
"cloudflare_access_application.enforcing_ext_auth_worker_bypass",
"cloudflare_access_application.enforcing_ext_auth_worker_bypass_dev",
],
},
{
"account_id": "2xxxx",
"tf_addresses": [
"cloudflare_access_application.extra_wildcard_application",
"cloudflare_access_application.wildcard",
],
},
],
}
What the rollout taught us
Migrating years of dashboard-driven "clickops" scattered over hundreds of accounts into strict IaC is an ongoing process. Importing existing chaos remains difficult, and Cloudflare hit edge cases in its own Terraform provider that only surface at extreme scale. Those frictions produced three hard lessons.
Adoption needs an easy path in
The steepest initial hurdle is onboarding resources that were previously configured by hand. Teams had two options: write Terraform resources and import blocks manually, or use the cf-terraforming command-line utility, which generates required Terraform code and import statements directly from the Cloudflare API. The latter dramatically accelerated migration. Cloudflare also formed an internal community where experienced engineers help guide teams through complex imports.
Drift is constant
Direct dashboard edits during incidents bypass IaC, leaving Terraform state out of sync with deployed reality. To catch that, Cloudflare built a custom drift detection service that repeatedly compares Terraform's defined state against actual deployed state via the Cloudflare API. When drift is found, an automated system files an internal ticket assigned to the owning team, with remediation SLAs tiered by risk.
Automated tooling closes capability gaps
Cloudflare's API grows faster than manually maintained integrations ever could. The Terraform provider lagged behind product features until the release of the v5 provider, generated automatically from the OpenAPI specification. The shift to code generation was rough at first, but it keeps API and Terraform capabilities in sync and substantially reduces drift between what the platform supports and what IaC can manage.
The takeaway: building guardrails early beats fixing them late
Centralized security baselines, mandatory peer review, and pre-deployment policy enforcement limit configuration errors, accidental deletions, and policy violations. The approach also accelerates engineering: teams ship with confidence that their changes are already compliant.
For enterprise-scale governance, the lesson is straightforward: the dashboard is fine for day-to-day operations, but consistent, auditable security across many accounts requires treating configuration as living code.



