Skip to main content

Webhook receivers

By default, Flux polls each GitRepository on its configured interval: to detect new commits. If you want changes to be applied fast - typically for an actively developed repo - you set the interval to a low value at the cost of Flux hitting your repo every minute. You can also use a push based system using Flux' webhook receiver: the Git provider POSTs to a URL on push, Flux verifies the payload, and reconciliation starts within a second or two.

The Haven+ FluxCD reference implementation provides HTTPRoutes for the webhooks as well as example Receiver objects for GitLab and GitHub.

Setting up a Receiver for a new tenant​

Copy the Receiver (GitLab or GitHub) and the token Secret from tenants/tenant-demo/ in the gitops-flux repo.

Generating the webhook token​

The token is a shared secret between the Git provider and the Flux Receiver. You can create it using:

TOKEN=$(openssl rand -hex 16)
echo "$TOKEN" # e.g. 8f3c2a1b9d4e5f6a7b8c9d0e1f2a3b4c

Keep $TOKEN around — you will paste it into the Git provider's webhook configuration (raw, unencrypted) and into the Kubernetes Secret (encrypted, see below).

Encrypting the token with Sealed Secrets​

The token Secret lives in flux-system (alongside the Receivers). It must be encrypted before it is committed to Git. The Haven+ reference implementation uses Sealed Secrets for this.

Use the $TOKEN from the previous step to create a secret.yaml:

apiVersion: v1
kind: Secret
metadata:
name: webhook-token
namespace: flux-system
type: Opaque
stringData:
token: <TOKEN>

Next, use kubeseal to generate a sealed-secret based on the secret above:

kubeseal -f secret.yaml -w flux-webhook-token.sealed.yaml --controller-namespace sealed-secrets -n flux-system

Registering the webhook with the Git provider​

After Flux has applied the Receivers, each one publishes a unique webhook path under .status.webhookPath. Combine that with the cluster's flux.<cluster-domain> hostname (configured in infrastructure/flux-webhook-receiver/overlays/<cluster>/patches/http-route.yaml) to get the full URL:

GITLAB_PATH=$(kubectl get receiver [receiver]-gitlab -n flux-system -o jsonpath='{.status.webhookPath}')
GITHUB_PATH=$(kubectl get receiver [receiver]-github -n flux-system -o jsonpath='{.status.webhookPath}')
echo "GitLab webhook URL: https://flux.<cluster-domain>${GITLAB_PATH}"
echo "GitHub webhook URL: https://flux.<cluster-domain>${GITHUB_PATH}"

Then register the webhook at the provider:

  • GitLab — Project → Settings → Webhooks. Paste the URL, set "Secret token" to the raw $TOKEN, enable Push events and Tag push events, leave SSL verification on. See the GitLab webhook documentation for the full set of options and event types.
  • GitHub — Repository → Settings → Webhooks → Add webhook. Paste the URL as Payload URL, content type application/json, set Secret to the raw $TOKEN, and at minimum enable Pushes. See the GitHub webhooks documentation for an overview and Creating webhooks for the step-by-step.

Increase reconciliation intervals​

Once the webhooks are working, polling intervals become less important and can be increased to on the following resources:

  • GitRepository — the source the Receiver reconciles. With a webhook firing on every push, the polling interval: can comfortably move from the default 1m to e.g. 1h.
  • Kustomization — when its sourceRef points at the webhook-driven GitRepository, the Kustomization re-applies as soon as the source changes, regardless of its own interval.
  • ImageUpdateAutomation — webhooks from a container registry can drive image automation the same way through a registry-specific Receiver type. With that wired up the IUA interval: becomes a fallback too. Provider support varies, though: GitHub fires a package webhook event on every push to GHCR, so image-push events are available end-to-end. GitLab does not emit project webhooks for its Container Registry — pushes to the GitLab Container Registry don't fire any event in the project webhook event list, so on GitLab-only setups the IUA must keep polling at its interval:.