Cloudflare, managed from Kubernetes
kflare is an open-source operator that manages Cloudflare through custom resources: zones, DNS records, tunnels, Workers and their storage, WAF rules and the Rules products.
Keep Cloudflare's configuration in git next to the workloads it serves, apply it with Helm, Argo CD or Flux like everything else, and kflare keeps Cloudflare matching it.
- Kubernetes
- 1.34 or newer
- Helm
- 3.8 or newer
- Images
- amd64, arm64
- License
- MIT
apiVersion: kflare.dev/v1alpha1
kind: Tunnel
metadata:
name: hello-tunnel
spec:
name: hello
accountRef:
name: my-account
credentialsSecretRef:
name: hello-tunnel-token
---
apiVersion: kflare.dev/v1alpha1
kind: DNSRecord
metadata:
name: hello
spec:
zoneRef:
name: my-zone
name: hello.example.com
type: CNAME
tunnelRef:
name: hello-tunnel$ kubectl apply -f hello.yaml
tunnel.kflare.dev/hello-tunnel created
dnsrecord.kflare.dev/hello created
$ kubectl wait --for=condition=Ready dnsrecord/hello
dnsrecord.kflare.dev/hello condition met20 resource kinds
DNS, tunnels, Workers, storage, the WAF and Rules
Tested live
Every kind, against a real Cloudflare account
Signed releases
cosign signatures, SBOMs and provenance
GitOps-ready
Installs with Helm, Argo CD or Flux
What it manages
One operator for the Cloudflare you already use
20 kinds in kflare.dev/v1alpha1, across DNS, tunnels, Workers and their storage, security and the Rules products. Grant a token only the permissions of the kinds you use.
Accounts
CloudflareAccountThe credentials every other resource uses, cluster-scoped
DNS
ZoneA zone, created or adopted, with its name servers and status
DNSRecordA DNS record, or a hostname pointed at a Tunnel
Tunnels
TunnelA Cloudflare Tunnel, its token written to a Secret for
cloudflaredTunnelConfigurationA tunnel's routes, from hostname to Service
Workers and storage
WorkerScriptA Worker, from inline code or a ConfigMap, with its bindings
WorkerRouteA route from a URL pattern to a Worker
KVNamespaceA Workers KV namespace
R2BucketAn R2 bucket; kflare never deletes its objects
D1DatabaseA D1 database
Security
WAFCustomRuleOne WAF custom rule in a zone
RateLimitRuleOne rate limiting rule in a zone
ManagedRulesetA managed ruleset deployed to a zone, with overrides
IPListAn IP list that rule expressions use as
$name
Rules
TransformRuleOne URL rewrite or header transform rule
RedirectRuleOne single redirect
CacheRuleOne cache rule
ConfigurationRuleOne configuration rule: SSL mode, security level and more
OriginRuleOne origin rule: the origin's destination port
Zone settings
ManagedTransformA zone's managed transforms, the headers Cloudflare adds or removes
How it behaves
Built for platform teams
kflare shares the Cloudflare account with the people and tools already using it, and runs like the rest of your cluster.
Never takes over what it didn't create
Nobody starts with an empty Cloudflare account. An existing object is used only when its resource asks, with the kflare.dev/adoption-policy annotation. Otherwise the resource reports AlreadyExists and changes nothing.
Deletion is deliberate
Deleting a resource deletes what kflare created and keeps what it adopted. kflare.dev/deletion-policy keeps any object, for zones and storage that must outlive a manifest.
References, not copied IDs
Resources point at each other by name. A DNS record follows its tunnel when the tunnel is recreated with a new ID, and resources can be deleted in any order: parents wait for the ones that need them.
One Ready condition says why
Every resource reports a single Ready condition with a reason, and records each change as a Kubernetes Event. kubectl describe names the missing Secret or the permission Cloudflare refused.
A platform component like any other
Install it with Helm, Argo CD or Flux. The chart manages the CRDs and runs under the restricted Pod Security Standard, with leader election, standby replicas, a PodDisruptionBudget and metrics over HTTPS.
Teams manage their own
API tokens stay in Secrets, so External Secrets Operator and Sealed Secrets work, and a rotated token is picked up straight away. Only cluster admins create accounts; the namespaced kinds join the built-in edit and admin roles.
Pause for an incident
Annotate a resource with kflare.dev/paused: "true" and kflare leaves its Cloudflare object alone, for an incident or a migration done by hand, until the annotation is removed.
Drift put back
A change made in the Cloudflare dashboard is put back on the next reconcile. By default that can be hours away; the chart's driftCheckInterval checks every resource on a schedule.
Signed releases
The image and the Helm chart are signed with cosign, keyless, and the image ships with SBOMs and provenance, so an admission policy or Flux can verify them before they run.
Get started
A Service on the internet in four steps
The quickstart puts a demo Service on hello.your-domain.com through a Cloudflare Tunnel, with no public IP, load balancer or open inbound port. You need a domain on your Cloudflare account.
Create an API token
In the Cloudflare dashboard, create a token with these permissions, the zone ones limited to your domain:
- Account · Account Settings · Read
- Account · Cloudflare Tunnel · Edit
- Zone · Zone · Read
- Zone · DNS · Edit
Note your account ID, shown on the account's overview page.
Install kflare
The Helm chart installs the CRDs and the controller, which runs under the restricted Pod Security Standard.
Install the chart helm install kflare oci://ghcr.io/jonathangraniero/charts/kflare \ --version 0.4.1 --namespace kflare-system --create-namespace kubectl -n kflare-system rollout status deployment/kflareConnect your account
The token goes in a Secret, and a cluster-scoped
CloudflareAccountpoints at it. Every other resource refers to the account by name.Point kflare at the token kubectl -n kflare-system create secret generic cloudflare-token \ --from-literal=CF_API_TOKEN=<your API token> kubectl apply -f - <<'EOF' apiVersion: kflare.dev/v1alpha1 kind: CloudflareAccount metadata: name: my-account spec: accountID: <your account ID> tokenSecretRef: name: cloudflare-token namespace: kflare-system EOFExpose a Service
The example holds a demo app, a
Zonethat adopts your domain, aTunnel, itsTunnelConfiguration, aDNSRecordpointinghelloat the tunnel, and thecloudflaredDeployment that connects it.Deleting the namespace deletes the record and the tunnel, and keeps your zone, because kflare adopted it rather than creating it.
Apply the example curl -sSL https://raw.githubusercontent.com/JonathanGraniero/kflare/v0.4.1/examples/expose-a-service/expose-a-service.yaml \ | sed 's/example\.com/your-domain.com/g' | kubectl apply -f - kubectl -n kflare-example wait --for=condition=Ready dnsrecords.kflare.dev/hello --timeout=5m curl https://hello.your-domain.com
How it's built
Tested against the real Cloudflare API
kflare is developed with AI assistance (Claude Code). This is what keeps it honest.
Live end-to-end tests
A suite in GitHub Actions runs every resource kind against a real Cloudflare account on the Free plan, and checks Cloudflare's copy after each step. Its token holds only the permissions the deploy guide lists.
Mutation testing
Deliberate bugs are injected into the controllers, and the tests have to catch every one.
Fuzz tests
On the code that reads input kflare doesn't control: the metrics endpoint's authentication and the reading of Cloudflare's errors.
Cloudflare checked first
What the API accepts, refuses and stores is probed live before code relies on it, and recorded in ARCHITECTURE.md.
Known vulnerabilities checked
The code and the image are scanned on every pull request, and the latest release's image every week.
OpenSSF Scorecard
The repository's security practices are scored by the Open Source Security Foundation's Scorecard.
What was verified, and known limitationsOpenSSF ScorecardSecurity policy
Roadmap
Where it's going
kflare is in alpha: its API is v1alpha1, and fields can still change between releases. What people ask for decides the order of what comes next.
In the next release
Merged since v0.4.1
- Each API token kept within Cloudflare's rate limit, so an account past its limit holds up no other
- Accounts that limit which namespaces may use them
- Health checks for Argo CD and Flux, so an application turns Degraded when Cloudflare refuses a resource
- kflare's own metrics: calls to Cloudflare, readiness and drift, with the cf-ray ID of each failure
Next
More of Cloudflare that a Free account can use and test
- Zone settings: SSL mode, Always Use HTTPS, minimum TLS version and HSTS
- Queues and Vectorize indexes for Workers
- Turnstile widgets, with the widget's secret written to a Secret
- Workers custom domains, next to
WorkerRoute - Hyperdrive connections, with the database password read from a Secret
- Bulk redirects
- Managed ruleset exceptions