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 theScaledObjectmanifest. - A
ScaledObjectthat turns on TLS, points at the mounted CA file, and references theTriggerAuthentication.
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:nextPort
50000is the gRPC port the scaler connects to viakubemqAddress; port9090is 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:
kubectl create secret generic kubemq-ca-cert \
--from-file=ca.pem=./ca.pemMount it into the scaler pod at /certs. The extraVolumes and extraVolumeMounts values default to empty arrays in the chart, so you supply both:
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=trueThis 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.
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:
kubectl apply -f trigger-auth.yamlThe 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.
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-authReplace <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:
kubectl apply -f scaled-object-tls-auth.yamlMetadata 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 ..:
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:
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)
}WithAuthTokenattaches the token from yourSecret.WithTLS(certFile)enables TLS using the mounted CA certificate.WithServerNameOverrideappliesserverOverrideDomainonly when you set it.- The
Pingafter 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:
| File | Description | Prerequisites |
|---|---|---|
trigger-auth.yaml | TriggerAuthentication with Secret reference | Create the Secret first |
scaled-object-tls-auth.yaml | TLS + auth token ScaledObject | trigger-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.
Related
- ScaledObject metadata for the complete metadata table, including the
tls,certFile, andauthTokenfields. - 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?
Scale to Zero with Push Mode
Use the external-push trigger to scale a KubeMQ queue consumer from zero replicas and back, with fast scale-from-zero detection.
Environment Variables
The two environment variables the KubeMQ KEDA scaler reads at startup, plus its installation methods and how to run a local KubeMQ broker.