Kubernetes operator · Argo CD · Flux · Tekton

Instant GitOps syncs without exposing your cluster

GitHub, GitLab or Bitbucket post every push to one public Webhook Relay URL. The Kubernetes operator inside your cluster connects out and delivers it to Argo CD, Flux or a Tekton EventListener, so syncs start in seconds instead of waiting for the next poll. No ingress, no load balancer, no public IP.

Free plan · No credit card · SOC 2 Type II · Self-hosted option

Buying for a company? Talk to sales

One public URL in. One outbound connection out. Nothing else exposed.

Safe on company infrastructure

  • Outbound only

    The agent or operator connects out over TLS. No inbound port, no public IP.

  • Encrypted and scoped

    AES-256 at rest. Ephemeral buckets store no bodies or headers at all.

    Data handling →

  • Verified before forwarding

    Signatures checked and source IPs allowlisted on the input, so forged requests never reach you.

    Signatures →IP allowlist →

  • SOC 2 Type II

    Independently audited controls, SSO and audit logs.

    Security review kit →

Your deploy controller has the keys to production

Argo CD and Flux can change everything in the cluster. Their API shouldn't be on the internet just to hear about a push.

Exposing the cluster to your Git host

  • Publish argocd-server or the Flux receiver through an ingress
  • Keep a load balancer and TLS certificate for one endpoint
  • Allow-list the Git host's webhook source addresses
  • Or poll every few minutes and wait for changes

With Webhook Relay

  • The operator makes one outbound connection
  • No ingress, load balancer or public IP
  • Syncs start on push, not on the next poll
  • Deliveries logged and retried for up to 30 days

Nothing published

The operator connects out from inside the cluster. Only webhook deliveries arrive, to the one in-cluster service you name.

Seconds, not poll intervals

Without webhooks, a private cluster polls the repository every few minutes. With them, a merge starts the sync immediately.

Your secrets still apply

Headers reach the controller unchanged, so Argo CD's webhook secret and Flux's receiver token keep working. Add a function to check signatures even earlier.

From the Git host you use

Repository or organization webhooks, with their usual secrets.

  • GitHub and GitHub Enterprise

    Push and pull request events, signed with X-Hub-Signature-256.

  • GitLab and GitLab self-managed

    Push and merge request events, with the X-Gitlab-Token secret.

  • Bitbucket Cloud and Data Center

    Repository push events.

  • Container registries

    Image push webhooks from registries that Flux image automation can receive.

Into the controller you run

Point the operator's output at the in-cluster service.

  • Argo CD

    argocd-server's webhook endpoint, which refreshes the apps that track the pushed repository. Use https:// if the server isn't running with --insecure.

    http://argocd-server.argocd.svc.cluster.local/api/webhook
  • Flux

    A notification-controller Receiver, served by the webhook-receiver service.

    http://webhook-receiver.flux-system.svc.cluster.local/hook/<receiver-path>
  • Tekton Triggers

    An EventListener's service, which starts your PipelineRuns.

    http://el-<name>.<namespace>.svc.cluster.local:8080

Signature verification

Check signatures before the push reaches the cluster

A Webhook Relay function runs on the input, before forwarding. This one verifies GitHub's X-Hub-Signature-256. A forged push gets a 401 and never reaches the operator.

How signature verification works
function (Lua) · runs before forwarding
local crypto = require('crypto')

-- Reject anything that isn't signed with your shared secret,
-- before it is forwarded into your network.
local sig, err = crypto.hmac('sha256', r.RequestBody, cfg:GetValue("WEBHOOK_SECRET"))
if err then error(err) end

if "sha256=" .. sig ~= r.RequestHeader["X-Hub-Signature-256"] then
  r:SetResponseStatusCode(401)
  r:SetResponseBody("invalid signature")
  r:StopForwarding()
  return
end

Set up in three steps

Install the operator once. Each controller is one custom resource.

  1. 1

    Install the operator

    Add the Helm chart and give it an access token. It runs inside the cluster and opens the outbound connection.

    shell
    helm repo add webhookrelay https://charts.webhookrelay.com
    helm upgrade --install webhookrelay-operator \
      --namespace=default webhookrelay/webhookrelay-operator \
      --set credentials.key=$RELAY_KEY --set credentials.secret=$RELAY_SECRET
  2. 2

    Forward to Argo CD

    Create a WebhookRelayForward that sends the bucket's webhooks to argocd-server.

    argocd-forward.yaml
    apiVersion: forward.webhookrelay.com/v1
    kind: WebhookRelayForward
    metadata:
      name: argocd
    spec:
      buckets:
      - name: gitops
        inputs:
        - name: git-push
          description: "Paste this URL into your repository webhook"
        outputs:
        - name: argocd
          destination: http://argocd-server.argocd.svc.cluster.local/api/webhook
  3. 3

    Paste the URL into your repository

    Use the input's public URL as the webhook URL, with the same secret you set in Argo CD. The next push starts a sync, and the bucket logs show Argo CD's response.

Start free, or buy through procurement

Try it on one pipeline

Free$0
150 webhooks a month, enough for one test cluster
Business$79.99/mo
60,000 webhooks a month, long log retention, priority support

7-day money-back guarantee on paid plans.

Buying for a company?

  • Annual plans paid by invoice and purchase order
  • Help with your security review
  • Vendor onboarding paperwork

Questions

Do I need an ingress or a public load balancer for Argo CD webhooks?

No. The Webhook Relay operator runs inside the cluster and connects out to Webhook Relay. Your Git host posts to the public Webhook Relay URL, and the operator delivers each webhook to argocd-server's /api/webhook inside the cluster.

Does Argo CD's webhook secret still work?

Yes. Headers reach argocd-server unchanged, so the secret configured in argocd-secret is checked as usual. You can also verify the signature in a Webhook Relay function before the request is forwarded.

Does it work with Flux?

Yes. Point the output at the notification-controller webhook-receiver service and the path of your Receiver. Flux checks the receiver token or HMAC as usual.

What if the cluster is down when we push?

Webhook Relay stores each webhook and the Git host gets a success response. With durable delivery it is retried for up to 30 days, and any delivery can be replayed from the logs.

Can we run it on air-gapped or edge clusters?

The operator only needs outbound HTTPS to Webhook Relay. For clusters with no internet access at all, a self-hosted version of Webhook Relay is available.

More security pages: Security alerts into an on-prem SIEM · Alerts into internal runbook automation · Security review kit

Make your next merge deploy in seconds

Install the operator, apply one resource, paste one URL. The cluster stays private.

Free plan · No credit card required · 7-day money-back guarantee on paid plans