Skip to content

Kubernetes Operator

The Hookbase Kubernetes Operator lets you manage your entire webhook infrastructure as declarative YAML, right alongside your application manifests.

Overview

Instead of configuring webhook sources, destinations, routes, and tunnels through the dashboard or CLI, platform teams define them as Kubernetes custom resources. The operator watches these resources, reconciles them against the Hookbase API, and keeps the two in sync.

kubectl apply -f webhooks.yaml   →   Operator reconciles   →   Hookbase API updated

Key capabilities:

  • 10 Custom Resource Definitions covering all Hookbase resources
  • Drift detection with configurable reconciliation intervals
  • Sidecar injection for tunnel agents
  • Ingress controller mode for annotation-based setup
  • Per-namespace API key isolation
  • Prometheus metrics with ServiceMonitor support
  • Helm chart for production deployment

Installation

Prerequisites

  • Kubernetes 1.26+
  • Helm 3.x
  • A Hookbase API key with admin scopes

Install with Helm

Clone the operator repository from GitHub:

bash
git clone https://github.com/HookbaseApp/hookbase-operator.git
cd hookbase-operator

Create a bootstrap API key Secret:

bash
kubectl create namespace hookbase-system
kubectl create secret generic hookbase-bootstrap-key \
  --namespace hookbase-system \
  --from-literal=apiKey=whr_your_api_key_here

Install the operator from the local chart:

bash
helm install hookbase-operator ./chart \
  --namespace hookbase-system \
  --create-namespace \
  --set hookbase.apiKeySecretRef.name=hookbase-bootstrap-key \
  --set hookbase.apiKeySecretRef.key=apiKey

Docker Images

The operator images are published to GitHub Container Registry:

  • Operator: ghcr.io/hookbaseapp/hookbase-operator
  • Tunnel Agent: ghcr.io/hookbaseapp/hookbase-agent

Verify the operator is running:

bash
kubectl get pods -n hookbase-system

Quick Start

1. Create a Source

yaml
apiVersion: hookbase.io/v1alpha1
kind: WebhookSource
metadata:
  name: github-webhooks
spec:
  name: GitHub Webhooks
  slug: github-webhooks
  provider: github
  verifySignature: true
  signingSecretRef:
    name: github-webhook-secret
    key: secret

2. Create a Destination

yaml
apiVersion: hookbase.io/v1alpha1
kind: WebhookDestination
metadata:
  name: my-api
spec:
  name: My API
  url: "https://api.example.com/webhooks"
  method: POST
  authType: bearer
  authSecretRef:
    name: api-token
    key: token

3. Create a Route

yaml
apiVersion: hookbase.io/v1alpha1
kind: WebhookRoute
metadata:
  name: github-to-api
spec:
  name: GitHub to API
  sourceRef: github-webhooks
  destinationRef: my-api

4. Apply and Verify

bash
kubectl apply -f webhooks.yaml
kubectl get webhooksources,webhookdestinations,webhookroutes

Check the status:

bash
kubectl describe webhooksource github-webhooks
# Status:
#   Conditions:
#     Type:    Ready
#     Status:  True
#     Reason:  Synced

Cross-Resource References

CRDs reference each other by name within the same namespace:

yaml
apiVersion: hookbase.io/v1alpha1
kind: WebhookRoute
spec:
  sourceRef: github-webhooks       # References WebhookSource by metadata.name
  destinationRef: internal-api     # References WebhookDestination by metadata.name
  filterRef: production-only       # References WebhookFilter by metadata.name
  transformRef: strip-headers      # References WebhookTransform by metadata.name

The route controller resolves these names to API IDs at reconciliation time. This is GitOps-friendly -- no raw API IDs in manifests. If a referenced resource is not Ready yet, the route requeues and waits.

API Key Resolution

The operator resolves API keys using a priority chain:

  1. Explicit apiKeyRef on the CRD -- reads from a K8s Secret
  2. Default HookbaseAPIKey in the namespace (labeled hookbase.io/default=true)
  3. Bootstrap key from the Helm installation

This allows teams to start with a shared bootstrap key and progressively isolate with per-namespace scoped keys.

Per-Namespace Keys

Create a scoped API key for a team namespace:

yaml
apiVersion: hookbase.io/v1alpha1
kind: HookbaseAPIKey
metadata:
  name: team-key
  labels:
    hookbase.io/default: "true"
spec:
  name: Team API Key
  scopes:
    - sources:read
    - sources:write
    - events:read
  expiresInDays: 90
  secretRef:
    name: hookbase-team-key
    key: apiKey

After reconciliation, a Secret named hookbase-team-key appears in the same namespace. All other CRDs in that namespace automatically use it.

Tunnel Sidecar Injection

The WebhookTunnel CRD can automatically inject a lightweight Go-based tunnel agent as a sidecar container into your Deployments:

yaml
apiVersion: hookbase.io/v1alpha1
kind: WebhookTunnel
metadata:
  name: dev-tunnel
spec:
  name: Dev Tunnel
  targetPort: 8080
  targetService: my-app
  sidecarInjection:
    deploymentRef: my-app
    resources:
      requests:
        cpu: 10m
        memory: 16Mi
      limits:
        cpu: 100m
        memory: 64Mi

The operator:

  1. Creates the tunnel in the Hookbase API
  2. Stores the auth token in a K8s Secret (dev-tunnel-tunnel-auth)
  3. Patches the target Deployment to add a hookbase-agent container
  4. The agent connects via WebSocket and forwards requests to localhost:8080

On tunnel CRD deletion, the sidecar is automatically removed from the Deployment.

Ingress Controller Mode

For teams that prefer annotations over new CRDs, the operator watches Kubernetes Ingress resources with ingressClassName: hookbase:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-webhooks
  annotations:
    hookbase.io/source-provider: "stripe"
    hookbase.io/source-verify-signature: "true"
    hookbase.io/source-signing-secret-ref: "stripe-secret:whsec"
spec:
  ingressClassName: hookbase
  rules:
    - host: webhooks.example.com
      http:
        paths:
          - path: /stripe
            pathType: Prefix
            backend:
              service:
                name: payment-service
                port:
                  number: 8080

The operator automatically creates the underlying Hookbase source, tunnel, and route.

Available Annotations

AnnotationDescription
hookbase.io/source-providerWebhook provider (e.g., stripe, github)
hookbase.io/source-verify-signatureEnable signature verification (true/false)
hookbase.io/source-signing-secret-refK8s Secret reference for signing secret (name:key)
hookbase.io/route-transform-refReference to a WebhookTransform CRD
hookbase.io/api-key-refOverride API key for this ingress

Drift Detection

The operator reconciles on a configurable interval (default 5 minutes). If someone modifies a resource through the dashboard or API, the next reconciliation cycle brings it back in line with the YAML definition.

This ensures your Git repository remains the source of truth for webhook infrastructure.

Observability

Prometheus Metrics

MetricTypeDescription
hookbase_operator_reconcile_totalCounterReconciliations by resource type and outcome
hookbase_operator_reconcile_duration_secondsHistogramReconciliation latency
hookbase_operator_api_calls_totalCounterSDK API call counts
hookbase_operator_managed_resourcesGaugeNumber of managed resources
hookbase_operator_tunnel_connectedGaugeTunnel connection status (0/1)

Enable the ServiceMonitor in Helm values:

yaml
metrics:
  serviceMonitor:
    enabled: true

Status Conditions

Every CRD has standard Kubernetes conditions:

  • Ready -- overall resource health
  • Synced -- last successful sync with Hookbase API
bash
kubectl get webhooksources
# NAME              SOURCE ID   PROVIDER   READY   AGE
# github-webhooks   src_2       github     True    5m

Health Probes

The operator exposes:

  • /healthz -- liveness probe
  • /readyz -- readiness probe

Admission Webhooks

Optional validating and defaulting webhooks enforce constraints at apply time:

  • Slug immutability -- prevents changing .spec.slug after creation
  • CIDR validation -- validates IP allowlist/denylist entries
  • Mutual exclusion -- prevents setting both filterRef and filterConditions on routes
  • Defaults -- sets provider=generic, method=POST, filterLogic=AND

Enable in Helm values:

yaml
webhook:
  enabled: true
  certManager:
    enabled: true

GitOps Integration

ArgoCD

The operator works out of the box with ArgoCD. Add your webhook manifests to your application repository and ArgoCD will sync them:

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: webhook-infra
spec:
  source:
    repoURL: https://github.com/your-org/infra
    path: webhooks/production
  destination:
    server: https://kubernetes.default.svc
    namespace: webhooks

Flux

Similarly, Flux Kustomizations will deploy and reconcile webhook CRDs:

yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: webhook-infra
spec:
  sourceRef:
    kind: GitRepository
    name: infra
  path: ./webhooks/production

Resources

Next Steps

Released under the MIT License.