Skip to content

v0.2.0

Choose a tag to compare

@JonathanGraniero JonathanGraniero released this 26 Oct 02:01
· 58 commits to main since this release
17312e6

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.yaml

The 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 the kflare-metrics-reader ClusterRole (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 from metrics.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 for get on /metrics, which the new
    kflare-metrics-reader ClusterRole grants. The controller's ClusterRole may create TokenReviews and
    SubjectAccessReviews to check them. metrics.certSecret serves 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: 1 when replicaCount is 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-secure also 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-path serves the metrics certificate and key from a directory (tls.crt, tls.key), reloaded
    when they change
  • --default-deletion-policy, the chart's defaultDeletionPolicy: retain keeps the Cloudflare objects of deleted
    resources, unless a resource says kflare.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, Normal when
    it turns True and Warning when it turns False, so kubectl describe shows the resource's history. The
    controller's ClusterRole may create and patch events.k8s.io Events
    (#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's reconcileTimeout (5 minutes by default): a reconcile that runs longer ends with
    reason APIError and is retried with back-off, and its controller goes on to the next resource
  • --drift-check-interval, the chart's driftCheckInterval, 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 kflare category, so kubectl get kflare lists 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 as AlreadyExists until 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, originRequest timeouts are not exposed, and R2 buckets live in the default
    jurisdiction only