KubeMQ
IntegrationsKEDAHow-to guides

Secure the KubeMQ Connection with TLS and Auth

Connect the KEDA scaler to a TLS-secured, authenticated KubeMQ broker using a CA certificate and a TriggerAuthentication token.

When your KubeMQ broker requires TLS and an authentication token, the scaler must present matching credentials on the connection it opens to the broker. This guide configures the scaler-to-KubeMQ hop — the gRPC call the scaler makes to read the Waiting count via ListQueuesChannels. It does not change how the scaler's own gRPC server (the one KEDA talks to) listens; that server is plaintext by design in v1 (see the warning at the end).

The pieces involved are:

  • A CA certificate mounted into the scaler pod so it can verify the broker's TLS certificate.
  • A TriggerAuthentication that feeds the auth token into the scaler from a Kubernetes Secret, so the token never appears in the ScaledObject manifest.
  • A ScaledObject that turns on TLS, points at the mounted CA file, and references the TriggerAuthentication.

Prerequisites

  • The scaler deployed via Helm (see Getting Started).

  • A KubeMQ broker that is configured for TLS and requires an auth token. You can run one locally for testing:

    docker run -d \  --name kubemq \  -p 50000:50000 \  -p 9090:9090 \  -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \  europe-docker.pkg.dev/kubemq/images/kubemq:next

    Port 50000 is the gRPC port the scaler connects to via kubemqAddress; port 9090 is the shared HTTP port used by connector endpoints.

  • The broker's CA certificate (ca.pem) and the auth token, available to load into Kubernetes.

Step 1 — Mount the CA Certificate into the Scaler Pod

The scaler reads the CA file from a path inside its own container, so the certificate has to be mounted there first. Store it in a Kubernetes Secret and mount that Secret at /certs using the chart's extraVolumes / extraVolumeMounts values.

Create the Secret holding the CA certificate:

Create the CA Secret
kubectl create secret generic kubemq-ca-cert \
  --from-file=ca.pem=./ca.pem

Mount it into the scaler pod at /certs. The extraVolumes and extraVolumeMounts values default to empty arrays in the chart, so you supply both:

Mount the CA at /certs via Helm
helm install kubemq-keda-scaler deploy/helm/kubemq-keda-scaler/ \
  --set extraVolumes[0].name=certs \
  --set extraVolumes[0].secret.secretName=kubemq-ca-cert \
  --set extraVolumeMounts[0].name=certs \
  --set extraVolumeMounts[0].mountPath=/certs \
  --set extraVolumeMounts[0].readOnly=true

This makes the certificate available inside the pod as /certs/ca.pem, which is the path you will reference from the ScaledObject.

/certs is one of the directories the scaler accepts for certFile. See the certFile path restriction below before choosing a different mount point.

Step 2 — Create the TriggerAuthentication and Secret

Keep the auth token out of the ScaledObject by storing it in an Opaque Secret and exposing it through a KEDA TriggerAuthentication. The secretTargetRef maps the scaler's authToken parameter to a key inside the Secret.

trigger-auth.yaml
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: kubemq-trigger-auth
spec:
  secretTargetRef:
    - parameter: authToken
      name: kubemq-auth-secret
      key: token
---
apiVersion: v1
kind: Secret
metadata:
  name: kubemq-auth-secret
type: Opaque
stringData:
  token: "your-kubemq-auth-token"

Apply it before the ScaledObject:

Apply the TriggerAuthentication and Secret
kubectl apply -f trigger-auth.yaml

The parameter: authToken value is what wires the secret into the scaler — KEDA injects the Secret's token value as the authToken metadata field when it calls the scaler.

Step 3 — Create the TLS + Auth ScaledObject

The ScaledObject turns on TLS, points certFile at the mounted CA, optionally sets a TLS server-name override, and references the TriggerAuthentication so the token is supplied from the Secret rather than inline.

scaled-object-tls-auth.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: secure-queue-scaler
spec:
  scaleTargetRef:
    name: secure-consumer
  pollingInterval: 15
  cooldownPeriod: 60
  minReplicaCount: 1
  maxReplicaCount: 10
  triggers:
    - type: external
      metadata:
        scalerAddress: <SCALER_SERVICE>.<NAMESPACE>.svc.cluster.local:9090
        kubemqAddress: kubemq.default.svc.cluster.local:50000
        queueName: secure-queue
        targetWaiting: "10"
        tls: "true"
        certFile: /certs/ca.pem
        serverOverrideDomain: kubemq.local
      authenticationRef:
        name: kubemq-trigger-auth

Replace <SCALER_SERVICE> and <NAMESPACE> with your scaler Service name and namespace. serverOverrideDomain is optional — include it only when the broker's certificate Common Name / SAN differs from the address you connect to (for example, connecting via a Service DNS name while the certificate is issued for kubemq.local).

Apply it:

Apply the ScaledObject
kubectl apply -f scaled-object-tls-auth.yaml

Metadata Fields

These are the metadata fields involved in securing the broker connection. All four are optional; supply only what your broker requires.

Prop

Type

The certFile Path Restriction

The scaler validates certFile before it ever opens a connection. The cleaned path must begin with one of three allowed prefixes and must not contain ..:

scaler/config.go
var allowedCertPrefixes = []string{"/certs/", "/etc/ssl/", "/etc/pki/"}

func validateCertPath(path string) error {
	cleaned := filepath.Clean(path)
	if strings.Contains(cleaned, "..") {
		return status.Error(codes.InvalidArgument, "certFile must not contain path traversal")
	}
	for _, prefix := range allowedCertPrefixes {
		if strings.HasPrefix(cleaned, prefix) {
			return nil
		}
	}
	return status.Errorf(codes.InvalidArgument, "certFile must be under one of: %v", allowedCertPrefixes)
}

If the path falls outside those directories or contains path traversal (..), the scaler rejects the metadata with gRPC InvalidArgument and never connects. The path is also capped at 512 characters. Mounting the CA at /certs (Step 1) keeps you inside the allowed set with no extra configuration.

How the Scaler Applies These Options

When the scaler builds its KubeMQ client, it translates the metadata into kubemq-go client options. The auth token and TLS settings are only added when present, and a Ping immediately after connect makes bad credentials fail fast instead of surfacing later during a poll:

scaler/kubemq_client.go
opts := []kubemq.Option{
	kubemq.WithAddress(meta.KubeMQHost, meta.KubeMQPort),
	kubemq.WithClientId("kubemq-keda-scaler"),
	kubemq.WithCheckConnection(true),
}

if meta.AuthToken != "" {
	opts = append(opts, kubemq.WithAuthToken(meta.AuthToken))
}

if meta.TLS {
	opts = append(opts, kubemq.WithTLS(meta.CertFile))
	if meta.ServerOverrideDomain != "" {
		opts = append(opts, kubemq.WithServerNameOverride(meta.ServerOverrideDomain))
	}
}

client, err := kubemq.NewClient(ctx, opts...)
if err != nil {
	return nil, err
}

if _, err := client.Ping(ctx); err != nil {
	_ = client.Close()
	return nil, fmt.Errorf("kubemq: ping failed after connect: %w", err)
}
  • WithAuthToken attaches the token from your Secret.
  • WithTLS(certFile) enables TLS using the mounted CA certificate.
  • WithServerNameOverride applies serverOverrideDomain only when you set it.
  • The Ping after connect fails fast on bad credentials or an unreachable broker.

Apply Order

The TriggerAuthentication (and its backing Secret) must exist before the ScaledObject references it, otherwise KEDA cannot resolve authenticationRef. The example files in deploy/examples/ are meant to be applied in this order:

FileDescriptionPrerequisites
trigger-auth.yamlTriggerAuthentication with Secret referenceCreate the Secret first
scaled-object-tls-auth.yamlTLS + auth token ScaledObjecttrigger-auth.yaml applied first

In short: create the CA Secret, apply trigger-auth.yaml, then apply scaled-object-tls-auth.yaml.

TLS here secures only the scaler-to-broker hop. The scaler's own gRPC server — the one the KEDA operator calls — runs plaintext by design in v1 and is meant to be a ClusterIP Service reachable only inside the cluster. Protect that port with a NetworkPolicy restricting ingress to the KEDA operator namespace.

Error Behavior

If the broker rejects the scaler's credentials, the scaler maps the KubeMQ error to a gRPC status code so KEDA can apply its fallback strategy:

  • An authentication failure maps to gRPC Unauthenticated.
  • A permission denial maps to gRPC PermissionDenied.

Both are returned as errors (never a fake Waiting=0), so KEDA falls back to your configured fallback.replicas instead of scaling the deployment to zero on a transient credential problem.

  • ScaledObject metadata for the complete metadata table, including the tls, certFile, and authToken fields.
  • Error codes for the full KubeMQ-error-to-gRPC-status mapping.
  • Getting Started to install the scaler and create your first ScaledObject.

Was this page helpful?

On this page