Schedule icon
Commands icon
Docker icon
Script icon
If icon
SlackIncomingWebhook icon
Set icon

HelmDriftWatch - Helm release drift detector

A Kestra blueprint that diffs live Kubernetes workloads against a Helm release's desired state and alerts on Slack about out-of-band changes, without spamming.

Categories
Infrastructure

How it works

  1. collect (io.kestra.plugin.scripts.shell.Commands, dtzar/helm-kubectl image) builds a kubeconfig from the cluster secrets, then grabs three things: helm get values (the chart-side config), helm get manifest (the desired workloads), and the live Deployments/StatefulSets carrying the release's app.kubernetes.io/instance label.
  2. check_drift (io.kestra.plugin.scripts.python.Script) parses the manifest and compares each workload's replicas, container images, and env vars against the live cluster. It also snapshots the chart values. A drift signature is hashed so the same drift alerts once; a changed drift alerts again; a reconciled release goes quiet.
  3. maybe_alert (io.kestra.plugin.core.flow.If) posts the Slack alert only on new drift, naming each difference as live-vs-chart.
  4. save_state (io.kestra.plugin.core.kv.Set) writes back the values snapshot and the drift signature.

What you get

  • A thirty-minute check that answers "did someone kubectl-edit what helm deployed?"
  • Slack alerts naming the exact drift: replicas, images, or env vars, live value vs chart value.
  • No alert spam: the same drift alerts once, and reconciling the release goes quiet on its own.
  • Quiet runs when live matches the chart.

Who it's for

Anyone deploying with Helm where a well-meaning kubectl scale or kubectl set image has silently diverged from the chart. The next helm upgrade would wipe that edit without warning; this tells you before that happens.

Why orchestrate this with Kestra

Drift is a slow problem that needs a scheduled check, a memory of what was already reported, and a notification when something new appears. Kestra holds the cluster credentials as secrets, keeps every run's diff where you can audit it, and the KV-backed drift signature means the second run does not re-page you about the same edit.

Prerequisites

  • A Kubernetes cluster with a Helm release deployed.
  • A kubeconfig client certificate and key with permission to read helm release secrets and list workloads in the target namespace.
  • Kestra with the Docker task runner available (used for the helm/kubectl and Python steps).
  • A Slack Incoming Webhook URL.

Secrets

Secret What it is
CLIENT_CRT base64-encoded client certificate from your kubeconfig
CLIENT_KEY base64-encoded client key from your kubeconfig
MASTERURL base64-encoded Kubernetes API server URL, reachable from inside the Kestra container
SLACK_WEBHOOK base64-encoded Slack Incoming Webhook URL

In Kestra OSS, secrets come from environment variables prefixed with SECRET_ and must be base64-encoded. If the API URL uses 127.0.0.1 or localhost, replace it with host.docker.internal so the Kestra container can reach it.

Quick start

  1. Start Kestra with the secrets above as SECRET_ environment variables. If minikube restarted since your last run, regenerate SECRET_MASTERURL first: the API port changes on every minikube start.
  2. Install a test chart: helm repo add bitnami https://charts.bitnami.com/bitnami then helm install drift-demo bitnami/nginx --set replicaCount=1. Import this flow and run it with release_name: drift-demo: quiet, the baseline is recorded.
  3. Drift it out-of-band: kubectl set image deployment/drift-demo-nginx nginx=nginx:1.25. Run again: the Slack alert names the image drift, live vs chart.
  4. Run again: quiet, same drift already reported.
  5. Reconcile: helm upgrade drift-demo bitnami/nginx --reuse-values. Run again: quiet, live matches the chart.

How to extend

  • Cover more kinds (DaemonSets, Services) by widening the manifest parsing and the live query.
  • Auto-reconcile by adding a gated helm upgrade --reuse-values step after manual approval.
  • Track chart version drift too by snapshotting helm status revision.
  • Watch every release in a namespace by looping helm list -o json.

Inputs

Input Type Default What it does
release_name STRING (required) the helm release to watch for drift
namespace STRING default the namespace holding the release
slack_webhook STRING (required) Incoming webhook URL of the Slack channel for alerts

Links

Pitfalls

  • A helm upgrade legitimately changes the desired state. The flow re-baselines silently on the next run; it only alerts on live-vs-chart differences, never on chart-side changes alone.
  • The flow is strictly read-only. It never upgrades, rolls back, or patches anything; reconciliation is a command for you to run.
  • Helm stores releases as Secrets in the release namespace. The client certificate needs permission to read those secrets, or helm get values fails loudly.
  • Minikube's API server port changes on every minikube start. Regenerate SECRET_MASTERURL and restart the Kestra container, or the helm/kubectl step fails to connect.
See How

New to Kestra?

Use blueprints to kickstart your first workflows.