Repository navigation
Releases: JonathanGraniero/kflare
Release list
kflare v0.4.1
The sixth alpha release of kflare: the API is still v1alpha1, and it needs Kubernetes 1.34 or newer. It fixes a race
in the shared CRUD reconciler that v0.4.0 shipped with, which could upload a Worker twice, or mark an object kflare
created as adopted.
helm upgrade kflare oci://ghcr.io/jonathangraniero/charts/kflare --version 0.4.1 -n kflare-system \
--values kflare-values.yamlThe image is ghcr.io/jonathangraniero/kflare:0.4.1, for linux/amd64 and linux/arm64. The deploy guide's
Verifying a release checks both signatures before you install. To install kflare
for the first time, follow the README's quickstart.
Upgrading from v0.4.0
The CRDs, the controller's permissions and the chart's defaults are v0.4.0's, so the upgrade itself needs nothing.
A resource with adopt-or-create that v0.4.0 marked kflare.dev/adopted for an object it created stays marked, and
deleting it keeps the object, as for any adopted object. To have such an object deleted with its resource, set
kflare.dev/deletion-policy: delete on the resource first.
The controller
- A resource no longer acts on a stale read of itself. The manager's cache can lag behind the status a reconcile
wrote last, while that reconcile's own writes queue the next one. Reading no ID, the next reconcile found the object
it had just created and wrote it again, or, withadopt-or-create, marked it adopted, so that deleting the resource
would have kept it; reading a WorkerScript's previous hash, it uploaded the Worker a second time. The kinds of the
shared CRUD reconciler now read the resource from the API server before they find, adopt, create or update an
object, and wait for the cache when it is behind (#131)
Known limitations
v0.4.0's, unchanged: ARCHITECTURE.md explains each.
kflare v0.4.0
Known issue, fixed in v0.4.1. A reconcile can act on a copy of its resource from before the status the previous reconcile wrote. A
WorkerScriptcan then upload its Worker a second time, and withadopt-or-createa resource can mark an object it created as adopted, so that deleting the resource keeps the object. The fix is #131, onmain.
The fifth alpha release of kflare: the API is still v1alpha1, and it needs Kubernetes 1.34 or newer. Every kind but
CloudflareAccount now runs on a shared reconciler. IPList, Tunnel and DNSRecord are generated by kflare's code
generator, on Cloudflare's generated Go SDK; Zone, TunnelConfiguration and WorkerScript get their types and
wiring from it, while their fields and calls stay hand-written on cloudflare-go v0.119. Manifests written for v0.3
apply unchanged, but these kinds behave as the generated kinds do, and the chart now creates a
HorizontalPodAutoscaler, on by default: read Upgrading from v0.3.0 before upgrading. It is a
minor release because of those changes.
helm upgrade kflare oci://ghcr.io/jonathangraniero/charts/kflare --version 0.4.0 -n kflare-system \
--values kflare-values.yamlThe image is ghcr.io/jonathangraniero/kflare:0.4.0, for linux/amd64 and linux/arm64. The deploy guide's
Verifying a release checks both signatures before you install. To install kflare
for the first time, follow the README's quickstart.
Upgrading from v0.3.0
No manifest changes, and the controller's permissions are v0.3.0's. Of the CRDs, only Tunnel's and WorkerScript's
change, as Every kind on a shared reconciler says. If you manage the CRDs yourself
(crds.enabled=false), apply config/crd/bases from v0.4.0 first. Each existing resource keeps its Cloudflare object:
it records its claim at its first reconcile, without being marked adopted, and no Worker is uploaded again.
The chart creates a HorizontalPodAutoscaler, on by default, which then owns the Deployment's replica count:
replicaCountis ignored whileautoscaling.enabledistrue. If you setreplicaCount: 2to keep a standby,
setautoscaling.minReplicas: 2instead, orautoscaling.enabled: falseto go on usingreplicaCount- The autoscaler needs the metrics API, which metrics-server provides. Without it, the Deployment keeps
autoscaling.minReplicasreplicas, one by default - The controller's resources change: its CPU request from 10m to 100m, which the autoscaler's target is a share
of, a CPU limit of 1, and its memory limit from 256Mi to 512Mi. Values that setresourcesreplace only the keys
they set
Every kind on a shared reconciler
IPList, Tunnel, DNSRecord, Zone, TunnelConfiguration and WorkerScript move onto the shared CRUD reconciler.
They keep their spec fields, and now behave as the generated kinds do:
- A Tunnel's
spec.namecan change. It renames the tunnel in place, which cloudflare-go v0.119 could not do - Status gains
status.cloudflareMetadata.scriptNameon a WorkerScript, set by its next upload - Tunnel, TunnelConfiguration and WorkerScript claim their objects, in the labels
kflare.dev/tunnel-id,
kflare.dev/tunnel-configuration-idandkflare.dev/worker-name. A resource that would take over an object another
one claims reportsNameConflict, orTunnelAlreadyConfigured, rather than sharing it. A Zone records its zone in
kflare.dev/zone-id, but two Zones may still name one Cloudflare zone, as they could before - A DNSRecord reports
NameConflictfor an identical record another DNSRecord manages, where it used to try a
create that Cloudflare refuses - A new Tunnel sends no
tunnel_secret. It is the password of a locally-managed tunnel;cloudflaredruns a
remotely-managed one with the token, which Cloudflare issues all the same (checked 2026-10-30) - A resource whose status was never written still deletes its object, through its claim, as only IPList did
ListInUse's message is the shared one: the list, what to do and how to keep it. Its reason does not change
The Helm chart
- A HorizontalPodAutoscaler (
autoscaling), on by default: from 1 to 10 replicas, adding them once the pods'
average CPU use has been above 80% of their request for 2 minutes. Only the leader reconciles, so the replicas it
adds are standbys, which take over sooner if the leader goes; they add no reconcile capacity. Memory is left out
by default, since the leader caches every Secret and the standbys nothing. The deploy guide's
Scaling and resources says how it behaves and how to tune it - Resources from measurements: requests of 100m CPU and 64Mi memory, limits of 1 CPU and 512Mi memory. The
deploy guide lists what the controller uses idle, with 1,000 and 5,000 resources, while taking over from a leader
and with many Secrets, and how to size its memory for a cluster's Secrets
(#70, its sizing part) - The PodDisruptionBudget is created whenever the Deployment can run more than one replica: with autoscaling on,
whenautoscaling.maxReplicasis above 1, so a default install gets one. WithmaxUnavailable: 1it never blocks
a drain of a single replica - The chart refuses autoscaling with
maxReplicasabove 1 andleaderElection: false, since every replica would
then reconcile, and a CPU or memory target without the matching request
Development
hack/sizingmeasures the controller's CPU and memory: it runs the image in Docker against an envtest API server,
as a leader and a standby, while it adds Secrets and kflare resources and stops the leader- Go code that builds these kinds' specs changes: their fields moved into inline structs, such as
DNSRecordSpecExtras, so a composite literal names them. Readingspec.tunnelReffrom Go does not change - The samples of IPList, Tunnel and DNSRecord are generated now, so
config/samplesnames other objects
Known limitations
v0.2.0's, but for Tunnel renames, which now work: ARCHITECTURE.md explains each.
The limits of cloudflare-go v0.119 now apply only to Zone, TunnelConfiguration and WorkerScript.
kflare v0.3.0
The fourth alpha release of kflare: the API is still v1alpha1, and it needs Kubernetes 1.34 or newer. Five more kinds
are now generated by kflare's code generator, on Cloudflare's generated Go SDK, as the Rules products' kinds already
were: the three security rule kinds, WAFCustomRule, RateLimitRule and ManagedRuleset, so that every rule kind is
generated, and R2Bucket and WorkerRoute, the first of the kinds written before the generator to move onto it.
The rule kinds' fields take the names of Cloudflare's API, so manifests written for v0.2 change: read
Upgrading from v0.2.1 before upgrading. It is a minor release because of that change.
R2Bucket and WorkerRoute apply manifests unchanged, but behave differently in the ways their sections list. The
other kinds written before the generator (Zone, DNSRecord, Tunnel, TunnelConfiguration, WorkerScript and
IPList) are unchanged: they move onto it in later releases, whose notes list their changes the same way. The chart
also gains an Artifact Hub page with its license, CRDs and security report.
helm upgrade kflare oci://ghcr.io/jonathangraniero/charts/kflare --version 0.3.0 -n kflare-system \
--values kflare-values.yamlThe image is ghcr.io/jonathangraniero/kflare:0.3.0, for linux/amd64 and linux/arm64. The deploy guide's
Verifying a release checks both signatures before you install. To install kflare
for the first time, follow the README's quickstart.
Upgrading from v0.2.1
The chart's values and the controller's permissions are v0.2.1's, and so are the other CRDs but R2Bucket's and
WorkerRoute's, whose manifests need no change. Only the WAFCustomRule, RateLimitRule and ManagedRuleset
resources do; if this lists none, they need nothing:
kubectl get wafcustomrules,ratelimitrules,managedrulesets -ACheck your R2Buckets before upgrading as well. spec.storageClass defaults to Standard, and kflare now sets a
bucket's storage class: a bucket whose class was set to InfrequentAccess outside kflare goes back to Standard
unless its R2Bucket says InfrequentAccess. Pause such an R2Bucket before upgrading
(kubectl annotate r2bucket <name> kflare.dev/paused=true), apply its manifest with storageClass: InfrequentAccess
after the chart, then remove the annotation (kubectl annotate r2bucket <name> kflare.dev/paused-). An alert on a
WorkerRoute's PatternOutsideZone reason needs changing too (WorkerRoute).
For the three rule kinds:
- Rewrite their manifests in the new shape, from the sections below, each with a manifest before and after. Keep
them back for now: the v0.2.1 CRDs refuse the new fields (unknown field "spec.ratelimit") - Pause each
WAFCustomRulewith ablockResponse, withkubectl annotate wafcustomrule <name> kflare.dev/paused=true. Upgraded, such a rule loses its response, and kflare would write it again without one - Upgrade the chart, which upgrades the CRDs. If you manage the CRDs yourself (
crds.enabled=false), apply
config/crd/basesfrom v0.3.0 first - Apply the rewritten manifests right away, then remove the annotations from step 2, with
kubectl annotate wafcustomrule <name> kflare.dev/paused-. With Argo CD or Flux, sync them after the chart
Between steps 3 and 4, a stored resource has lost its old fields: the API server drops the fields the new CRD does not
know when it reads the resource. The RateLimitRule and WAFCustomRule sections below say what kflare does with
their Cloudflare rules until you apply the new shape. Until then a change to the resource's spec is refused
(spec.id: Required value), but one to its metadata or status is not, so it can still be paused, report its status
and be deleted.
ManagedRuleset
rulesetIDis nowid, the API's name for the ruleset an execute rule runs. A ManagedRuleset stored with
rulesetIDhas noidafter the upgrade, and cannot be updated until it gets one: apply your ManagedRuleset
manifests withidright after upgradingidcan change in place, which updates the deployment's rule to run the other ruleset; it was immutable- The category and rule overrides are sent in the spec's order rather than sorted. Cloudflare keeps that order, so
reordering them in the spec writes the rule again - An empty
overrides.categoriesoroverrides.rulesis refused: leave it out - For Go clients:
ManagedRulesetCategoryOverrideandManagedRulesetRuleOverrideare now
ManagedRulesetOverridesCategoryandManagedRulesetOverridesRule, and an override'sactionis astring
Before:
spec:
zoneRef:
name: example-zone
rulesetID: 77454fe2d30c4220b5701f6fdfb893ba
expression: "true"
overrides:
categories:
- category: wordpress
action: logAfter:
spec:
zoneRef:
name: example-zone
id: 77454fe2d30c4220b5701f6fdfb893ba
expression: "true"
overrides:
categories:
- category: wordpress
action: logRateLimitRule
- The rate limit moves under
ratelimit, the API's name for it:characteristics,period,requestsPerPeriod,
mitigationTimeout,countingExpressionandrequestsToOrigin.blockResponseis nowresponse. A
RateLimitRule stored with the old fields has no rate limit after the upgrade, and cannot be updated until it gets
one: apply your RateLimitRule manifests in the new shape right after upgrading. Until then its Cloudflare rule is
left as it was - Nothing defaults any more: set
action(wasblock),ratelimit.characteristics(was[ip.src]),
ratelimit.period(was 10),ratelimit.mitigationTimeout(was the period; 0 throttles, on Enterprise plans) and
response.statusCode(was 429) ratelimit.characteristicsmust listcf.colo.id, which kflare no longer adds for you, and at least one other
field. They are sent sorted- For Go clients:
RateLimitRuleBlockResponseis nowRateLimitRuleResponse, the rate limit is a
RateLimitRuleRatelimit, its characteristics are[]string, and its integers areint64, the optional ones
pointers
Before:
spec:
zoneRef:
name: example-zone
expression: 'starts_with(http.request.uri.path, "/api/")'
requestsPerPeriod: 100
blockResponse:
contentType: application/json
content: '{"error":"rate limited"}'After:
spec:
zoneRef:
name: example-zone
expression: 'starts_with(http.request.uri.path, "/api/")'
action: block
ratelimit:
characteristics: [cf.colo.id, ip.src]
period: 10
requestsPerPeriod: 100
mitigationTimeout: 10
response:
statusCode: 429
contentType: application/json
content: '{"error":"rate limited"}'WAFCustomRule
- A skip rule's parameters move to the spec's root, as the API names them:
skip.remainingRules: trueis now
ruleset: current, andskip.phasesandskip.productsarephasesandproducts.skip.logis now
logging.enabled, andblockResponseis nowresponse - A WAFCustomRule stored with the old fields loses them after the upgrade:
- A skip rule then has no parameters, which Cloudflare refuses (20115): kflare reports
TerminalErrorand leaves
the Cloudflare rule as it was until you apply the manifest in the new shape - A block rule with a
blockResponsebecomes a plain block rule, and kflare writes its Cloudflare rule again
without the response. Pause such rules (kflare.dev/paused: "true") before upgrading, apply them in the new
shape, then remove the annotation
- A skip rule then has no parameters, which Cloudflare refuses (20115): kflare reports
- Nothing defaults any more: set
response.statusCode(was 403). A skip rule withoutloggingstill logs its
matches, Cloudflare's default, which kflare no longer sends itself - New:
phase: currentskips the rest of the phase, the custom rulesets that run later in it included. It combines
withproducts, but not withphasesorruleset - For Go clients:
WAFCustomRuleSkip,WAFCustomRuleSkipPhase,WAFCustomRuleSkipProductand
WAFCustomRuleBlockResponseare gone. The phases and products are[]string, the response is a
WAFCustomRuleResponsewhosestatusCodeis anint64, and logging is aWAFCustomRuleLogging
Before:
spec:
zoneRef:
name: example-zone
expression: 'http.request.uri.path eq "/healthz"'
action: skip
skip:
remainingRules: true
phases: [http_ratelimit]
log: false
---
spec:
zoneRef:
name: example-zone
expression: 'http.request.uri.path wildcard "/admin*"'
action: block
blockResponse:
contentType: text/plain
content: BlockedAfter:
spec:
zoneRef:
name: example-zone
expression: 'http.request.uri.path eq "/healthz"'
action: skip
ruleset: current
phases: [http_ratelimit]
logging:
enabled: false
---
spec:
zoneRef:
name: example-zone
expression: 'http.request.uri.path wildcard "/admin*"'
action: block
response:
statusCode: 403
contentType: text/plain
content: BlockedR2Bucket
jurisdiction:default,euoruskeep the bucket's objects in that jurisdiction (fedrampand
fedramp-highneed a FedRAMP account). Each jurisdiction has buckets of its own, so two R2Buckets can name buckets
of the same name in different jurisdictions. It defaults todefault, the only jurisdiction kflare reached before,
and cannot changestorageClass:StandardorInfrequentAccess, the class of objects uploaded to the bucket without one of
their own, changed in place. It defaults toStandard, so a bucket whose class was set toInfrequentAccess
outside kflare is set back toStandardunless its R2Bucket saysInfrequentAccess- A WorkerScript d...
v0.2.1
The third alpha release of kflare: the API is still v1alpha1, and it needs Kubernetes 1.34 or newer. It is the first
signed release, with SBOMs and provenance for the image, and any resource can now be paused with an annotation.
helm upgrade kflare oci://ghcr.io/jonathangraniero/charts/kflare --version 0.2.1 -n kflare-system \
--values kflare-values.yamlThe image is ghcr.io/jonathangraniero/kflare:0.2.1, for linux/amd64 and linux/arm64. The deploy guide's
Verifying a release checks both signatures before you install. To install kflare
for the first time, follow the README's quickstart.
Upgrading from v0.2.0
Nothing to change: the CRDs, the controller's permissions and the chart's defaults are v0.2.0's.
Releases
- The controller image and the chart are signed with cosign, keyless: Sigstore issues the signing certificate to
kflare's release workflow, for the release's tag, and records the signature in its public transparency log. Each
platform's image comes with an SPDX SBOM and SLSA provenance, stored in the signed image index, and the GitHub
release has the SBOMs as files, each with a Sigstore bundle. The deploy guide's
Verifying a release has the commands, and a Kyverno policy that admits only
signed kflare images (#84)
The Helm chart
image.digestruns the controller image by digest instead of by tag: set it to the digest whose signature you
verified
The controller
- Pausing a resource: with the annotation
kflare.dev/paused: "true", kflare leaves the resource and its Cloudflare
object alone, neither reverting changes made in Cloudflare nor applying changes to the spec, until the annotation is
removed. A paused resource being deleted keeps its finalizer until then.Readykeeps its status and takes the
reasonPaused(#81)
Known limitations
v0.2.0's, unchanged: ARCHITECTURE.md explains each.
v0.2.0
The second alpha release of kflare: the API is still v1alpha1, and it needs Kubernetes 1.34 or newer. It hardens
the Helm chart for production (#67), bounds every call to
Cloudflare with timeouts, can check every resource for drift on a schedule, records Kubernetes Events, and adds a
new kind, ManagedTransform. v0.1.0's notes announced the chart hardening as v0.1.1; it ships as a minor release
instead, because upgrading changes how Prometheus scrapes kflare (see below).
helm upgrade kflare oci://ghcr.io/jonathangraniero/charts/kflare --version 0.2.0 -n kflare-system \
--values kflare-values.yamlThe image is ghcr.io/jonathangraniero/kflare:0.2.0, for linux/amd64 and linux/arm64. To install kflare for
the first time, follow the README's quickstart.
Upgrading from v0.1.0
Metrics are served over HTTPS, and only to callers allowed to read them. A scrape set up for v0.1.0 fails with
401 or 403 until it changes, on the same port (8080):
- With the chart's ServiceMonitor, nothing changes in your values: it scrapes over HTTPS with Prometheus' own
ServiceAccount token. kube-prometheus-stack's Prometheus is already allowed; any other needs its ServiceAccount
bound to thekflare-metrics-readerClusterRole (the deploy guide's
Monitoring has the binding) - Any other scraper must use HTTPS, send a bearer token whose user is bound to
kflare-metrics-reader, and either
skip verifying the self-signed certificate or trust one frommetrics.certSecret - To keep v0.1.0's plain HTTP, set
metrics.secure: false
If you manage the CRDs yourself (crds.enabled=false), apply config/crd/bases from v0.2.0 before upgrading
the chart: it adds the ManagedTransform CRD, which the controller watches, and puts every CRD in the kflare
category.
The Helm chart
- Metrics over HTTPS with authentication and authorization, on by default (
metrics.secure). A request needs a
bearer token that the API server authenticates and authorizes forgeton/metrics, which the new
kflare-metrics-readerClusterRole grants. The controller's ClusterRole may create TokenReviews and
SubjectAccessReviews to check them.metrics.certSecretserves a certificate from a Secret, such as one
cert-manager issues, instead of a self-signed one, and the ServiceMonitor then verifies it - A PodDisruptionBudget with
maxUnavailable: 1whenreplicaCountis above 1, so that a node drain evicts one
controller pod at a time (podDisruptionBudget). A single replica gets none, so it never blocks a drain - An opt-in NetworkPolicy (
networkPolicy): scrapes of the metrics port in, from the sources you select; DNS, the
Kubernetes API server and port 443 (Cloudflare) out
The controller
--metrics-securealso authenticates and authorizes each request now, with a TokenReview and a SubjectAccessReview;
an allowed token is trusted for a minute. Before, it only turned on TLS--metrics-cert-pathserves the metrics certificate and key from a directory (tls.crt,tls.key), reloaded
when they change--default-deletion-policy, the chart'sdefaultDeletionPolicy:retainkeeps the Cloudflare objects of deleted
resources, unless a resource sayskflare.dev/deletion-policy: delete. The default,delete, keeps v0.1.0's
behavior (#80)- Every change of a resource's Ready condition to another status or reason is recorded as an Event,
Normalwhen
it turns True andWarningwhen it turns False, sokubectl describeshows the resource's history. The
controller's ClusterRole may create and patchevents.k8s.ioEvents
(#56) - Timeouts on every call to Cloudflare, so that one that gets no answer cannot stall a controller: 10 seconds for
a TLS handshake, a minute for a response to start, two for a whole request, and an HTTP/2 connection that goes 30
seconds without a word is pinged and closed if the ping gets no answer. Before, a call could wait forever
(#72) --reconcile-timeout, the chart'sreconcileTimeout(5 minutes by default): a reconcile that runs longer ends with
reasonAPIErrorand is retried with back-off, and its controller goes on to the next resource--drift-check-interval, the chart'sdriftCheckInterval, off by default: every resource is checked against
Cloudflare that long after each successful reconcile, give or take a tenth, so that a change made outside kflare is
corrected within about the interval instead of at the 10-hour resync. The deploy guide says how to pick one for the
number of resources (#55)
Resource kinds
ManagedTransform: a zone's managed transforms, the request and response headers Cloudflare adds or removes,
turned on and off by ID. One ManagedTransform configures a zone, and deleting it turns them all off unless it
adopted them. It needs Zone · Managed Headers · Edit- Every kind is in the
kflarecategory, sokubectl get kflarelists the resources of all of them, in one
namespace (-n) or in all (-A) (#54)
Known limitations
Those of v0.1.0, except the two this release fixes (no Kubernetes Events, and metrics over plain HTTP).
ARCHITECTURE.md explains each:
- Drift is corrected promptly only with a drift check interval (
driftCheckInterval). Without one, the default,
a change made outside kflare waits for the next reconcile, at worst the 10-hour resync - Adoption goes by key (a name, a title, a pattern), never by ID. Tunnel names are not unique: a Tunnel adopts the
first one listed with its name - Ownership is recorded in the cluster, except for rules, which carry a ref in Cloudflare. A cluster rebuilt from
git sees its existing objects asAlreadyExistsuntil they are adopted; the deploy guide's
Moving to a new cluster describes how - Rule order covers kflare's rules only. Rules created outside kflare keep their place
- Some limits of cloudflare-go v0.119, which most controllers still use (the generated kinds and the rule kinds
use v7): Tunnels cannot be renamed,originRequesttimeouts are not exposed, and R2 buckets live in the default
jurisdiction only
v0.1.0
The first release of kflare, a Kubernetes operator that manages Cloudflare through custom resources. It is an alpha:
the API is v1alpha1, and fields can still change between releases. It needs Kubernetes 1.34 or newer.
helm install kflare oci://ghcr.io/jonathangraniero/charts/kflare \
--version 0.1.0 --namespace kflare-system --create-namespaceThe image is ghcr.io/jonathangraniero/kflare:0.1.0, for linux/amd64 and linux/arm64. Start with the
README's quickstart, and the
deploy guide for installing with Argo CD or Flux and running kflare in production.
Resource kinds
| Area | Kinds |
|---|---|
| Accounts | CloudflareAccount (cluster-scoped; a token Secret per account) |
| DNS | Zone, DNSRecord (tunnelRef points a hostname at a Tunnel) |
| Tunnels | Tunnel (its token written to a Secret for cloudflared), TunnelConfiguration |
| Workers and storage | WorkerScript, WorkerRoute, KVNamespace, R2Bucket, D1Database |
| Security | WAFCustomRule, RateLimitRule, ManagedRuleset, IPList |
| Rules | TransformRule, RedirectRule, CacheRule, ConfigurationRule, OriginRule |
Every kind is tested live against a real Cloudflare account on the Free plan, with a token holding only the
permissions the deploy guide lists.
Adoption and deletion
- kflare creates the Cloudflare objects its resources describe, and never takes over an existing object unless the
resource is annotatedkflare.dev/adoption-policy: adopt(adopt it, never create one) oradopt-or-create.
Otherwise the resource reportsAlreadyExistsand changes nothing. - Deleting a resource deletes the object kflare created, and keeps an object it adopted.
kflare.dev/deletion-policy: retainkeeps any object, anddeletedeletes even an adopted one. - Deleting a
KVNamespaceorD1Databasedeletes its data. kflare never deletes objects in an R2 bucket. - Resources can be deleted in any order, a whole namespace included: parents wait for the resources that need them.
See Adoption and ownership and Deletion.
The Helm chart
- Installs and upgrades the CRDs as templates, and keeps them on uninstall (
helm.sh/resource-policy: keep) - Runs the controller under the restricted Pod Security Standard, with leader election, so extra replicas stand by
- Adds kflare's namespaced kinds to the built-in
editandadminroles, and every kind toview;
CloudflareAccountis left to cluster administrators - Serves Prometheus metrics, with an optional ServiceMonitor;
values.schema.jsonvalidates the values
Known limitations
- Drift is not corrected promptly. A change made outside kflare is corrected on the next reconcile, which can be up
to 10 hours away. Changing the resource, even an annotation, reconciles it straight away. - Adoption goes by key (a name, a title, a pattern), never by ID. Tunnel names are not unique: a Tunnel adopts the
first one listed with its name. - Ownership is recorded in the cluster, except for rules, which carry a ref in Cloudflare. A cluster rebuilt from
git sees its existing objects asAlreadyExistsuntil they are adopted; the deploy guide's
Moving to a new cluster describes how. - Rule order covers kflare's rules only. Rules created outside kflare keep their place.
- Some limits of cloudflare-go v0.119, which most controllers still use: Tunnels cannot be renamed,
originRequest
timeouts are not exposed, and R2 buckets live in the default jurisdiction only. - No Kubernetes Events yet: the
Readycondition and the controller's log say what happened. - Metrics are served over plain HTTP without authentication, inside the cluster.
Coming in v0.1.1
The chart will serve metrics over HTTPS with authentication and authorization by default, which changes how
Prometheus scrapes kflare. It will also create a PodDisruptionBudget when replicaCount is above 1, and gain an opt-in
NetworkPolicy. The release notes will say what to change.