Air-Gapped Installations
License a KubeMQ server with no network access — request a signed file for your fingerprints, pass it with KUBEMQ_LICENSE_FILE or _DATA, and renew it.
An air-gapped server is licensed with a file: a token signed by KubeMQ that the server verifies locally with the public key embedded in its binary. The server never opens an outbound connection — no activation, no refresh, no usage report.
The same file is also the answer for networks that are online but cannot allow egress to the licensing endpoint (a pre-activated file — see Use a license key).
Request a file
A license file is bound to a list of installation fingerprints — the installations allowed to run it. Collect one fingerprint per installation and send them with your request.
Read each installation's fingerprint
The fingerprint is stable per installation: on Kubernetes it is the UID of the
kube-system namespace (one per cluster); elsewhere it is an id generated on first boot
and persisted at <store>/license/instance.id.
The easiest way to read it is from a running server:
curl -s http://localhost:8080/api/v1/license | jq -r '.fingerprint, .fingerprint_source'If you do not have a licensed server yet: on Kubernetes the fingerprint is simply
the cluster's kube-system namespace UID, which you can read directly —
kubectl get namespace kube-system -o jsonpath='{.metadata.uid}'— provided the server's ServiceAccount has the permission described in
Kubernetes, so that the running server
will derive the same value (fingerprint_source: "kube-system", not persisted).
Elsewhere the fingerprint is generated on the server's first boot and persisted at
<store>/license/instance.id; the reliable way to obtain it is to run the server once
with an online key (a trial key works) on the same store volume you
will keep, and read GET /api/v1/license.
Send the list to KubeMQ
Send your fingerprints, the number of installations, and the plan to your KubeMQ contact. Ask for an unbound file (empty fingerprint list) only if your installations are genuinely ephemeral; an unbound file is accepted by any installation.
Receive the armored file
You receive a text file that looks like this:
-----BEGIN KUBEMQ LICENSE-----
eyJhbGciOiJFUzI1NiIsImtpZCI6ImxpY2Vuc2Utc2lnbmluZy12MiJ9.<PAYLOAD>.<SIGNATURE>
-----END KUBEMQ LICENSE-----The body is one signed token. Its header names the signing key id (kid) — the server
binary trusts license-signing-v1 and license-signing-v2; the payload and signature
above are placeholders, not a real license.
Store it like any other secret. It carries your license id, plan, commercial expiry, installation cap and fingerprint list, all signed.
Pass the file to the server
Two variables accept a file. KUBEMQ_LICENSE_FILE takes a path; KUBEMQ_LICENSE_DATA
takes the contents (the armored text, or the bare token inside it).
Mount the file read-only and point KUBEMQ_LICENSE_FILE at it:
docker run -d \
--name kubemq \
--hostname kubemq \
-p 50000:50000 \
-p 9090:9090 \
-p 8080:8080 \
-e KUBEMQ_LICENSE_FILE=/kubemq/license/kubemq.license \
-v "$(pwd)/kubemq.license:/kubemq/license/kubemq.license:ro" \
-v "$(pwd)/kubemq-store:/kubemq/store" \
europe-docker.pkg.dev/kubemq/images/kubemq-next:latestservices:
kubemq:
image: europe-docker.pkg.dev/kubemq/images/kubemq-next:latest
container_name: kubemq
hostname: kubemq
ports:
- "50000:50000"
- "9090:9090"
- "8080:8080"
environment:
- KUBEMQ_LICENSE_FILE=/kubemq/license/kubemq.license
volumes:
- ./kubemq.license:/kubemq/license/kubemq.license:ro
- kubemq-data:/kubemq/store
restart: unless-stopped
volumes:
kubemq-data:Store the file in a Secret and reference it from the KubemqCluster; the operator
injects its contents as KUBEMQ_LICENSE_DATA:
kubectl create secret generic kubemq-license -n kubemq \
--from-file=license=./kubemq.licenseapiVersion: next.kubemq.io/v1
kind: KubemqCluster
metadata:
name: kubemq-next
namespace: kubemq
spec:
replicas: 3
licenseFileSecretRef:
name: kubemq-license
key: licenseWith Helm: --set licenseFileSecretRef.name=kubemq-license --set licenseFileSecretRef.key=license.
Inject the Secret value directly as KUBEMQ_LICENSE_DATA:
env:
- name: KUBEMQ_LICENSE_DATA
valueFrom:
secretKeyRef:
name: kubemq-license
key: licenseOr mount the Secret as a file and set KUBEMQ_LICENSE_FILE to the mount path. Either
way the pods still need the kube-system read permission described in
Kubernetes, because the fingerprint in the
file is the cluster's namespace UID.
Precedence
| Set | Result |
|---|---|
KUBEMQ_LICENSE_FILE only | The file is used |
KUBEMQ_LICENSE_DATA only | The data is used |
Both FILE and DATA | FILE wins; a warning is logged |
A file and KUBEMQ_LICENSE_KEY | The file wins; a warning is logged (#both-key-and-file). The key is ignored entirely — no activation, no refresh |
| None | The server refuses to start (#no-license-input) |
What the server does — and does not do — with a file
- Verifies locally, at boot. Signature, signing key id, expiry (with a 5-minute leeway), and that its own fingerprint is in the file's list (or the list is empty). Every minute after that it re-checks only the expiry and its own clock against the persisted high-water mark — the signature and fingerprint are not re-verified while the server runs, so a file swapped or edited on disk takes effect at the next boot.
- Makes no network calls. There is no activation, no hourly refresh and no usage
report.
GET /api/v1/licenseshowsmode: "offline",usage.enabled: false, andlast_refresh.outcome: "never". - Has no grace period. An offline file's
expis a hard date: the server refuses to start after it, and a running server drains and exits with code 3 when it passes (#offline-expired). Renew before that. - Keeps no lease cache. The file is the source of truth. The server still writes
two things under
<store>/license/: the persisted instance id used as a fingerprint outside Kubernetes, and the clock high-water mark (clock.hwm). A clock set back more than 10 minutes behind that mark is a refusal at boot and a stop on a running server (#clock-rollback) — an offline server has no service to confirm the time with.
Renewal
A file is valid for at most one year from issuance and never beyond the commercial expiry of the license. Renewal is a reissue: request a new file before the current one expires, replace it (update the Secret, or swap the mounted file) and restart the server — the file is read at boot.
Check lease_expires_at in GET /api/v1/license (or kmq license) to see the current
file's expiry, and plan the reissue ahead of it.
What revocation means for a file
A file that has been issued cannot be revoked. There is no channel through which a revocation could reach an air-gapped server, and the server does not look for one. This is a deliberate property of the design, not a gap: the file's expiry (at most one year), its fingerprint list and your contract are what bound its use.
Consequently, if a file leaks, the remedy is contractual and the exposure ends at the file's expiry. Keep files as tightly controlled as any other credential, and prefer bound files (with a fingerprint list) over unbound ones.
Was this page helpful?
Use a License Key
Pass KUBEMQ_LICENSE_KEY to Docker, Compose, Helm and manifests; activation, the lease cache and volume requirement, key regeneration, and GET /api/v1/license.
Licensing on Kubernetes
Licensing on Kubernetes — the KubemqCluster license fields, the operator's gate, clamp and lease cache Secret, and the RBAC and PVC the server needs without it.