Installing a License
Where the file goes#
The backend reads one file, at the path in ABRQ_LICENSE_FILE
(default /var/abrq-dip/license.json). Every backend process —
API, worker, and beat — needs to see the file at that path.
Release bundle (Docker Compose)#
The customer release bundle expects the license next to the compose
file, in the license/ directory:
cp /path/to/license.json ./license/license.json
docker compose up -d
The bundle's compose file bind-mounts just the license file, read-only, into the backend, worker, and beat containers:
volumes:
- ./license/license.json:/var/abrq-dip/license.json:ro
Tip. The mount is a single file on purpose — mounting the parent directory would shadow other content under
/var/abrq-dip. Keep it a file mount, and keep it read-only so a compromised container cannot alter the license.
The bundle also mounts the host's /etc/machine-id read-only, so a
hardware-bound license can be checked against the real host. It is
always mounted, even for unbound licenses, so a later renewal that adds
binding works without editing the compose file.
Kubernetes (Helm)#
The chart does not template a license volume — there is no
license.* key in values.yaml. To install a license on Kubernetes,
create a Secret holding the file and add a volume + read-only mount at
the ABRQ_LICENSE_FILE path to the api, worker, and beat Deployments
yourself (for example with a Kustomize patch or a post-render step):
kubectl -n <NAMESPACE> create secret generic abrq-dip-license \
--from-file=license.json=/path/to/license.json
Mount the Secret so license.json appears at
/var/abrq-dip/license.json in each backend pod (or set
ABRQ_LICENSE_FILE in commonEnv to wherever you mount it).
Note. Hardware-bound licenses are impractical on Kubernetes — pods move between nodes and each node has its own machine id. Use an unbound license (empty
fingerprints) for cluster deployments.
Hardware fingerprint binding#
A license may be bound to specific hosts via the payload's
fingerprints list. Each entry is the SHA-256 hash of the host's
/etc/machine-id. The rules:
- Any one match passes — a license can list several hosts.
- An empty list means unbound — the license runs anywhere.
To give Abrq the fingerprint of the host that will run the platform, run the helper shipped in the release bundle:
./host_fingerprint.sh
It prints the hash the vendor feeds into license generation. Nothing about your host is transmitted anywhere — you send the hash yourself.
What the logs say#
On a successful start you will see a structured log event:
license_verified customer=<...> license_id=<...> expires_at=<...> days_remaining=<...>
If fewer than 30 days remain, it is followed by
license_expiry_approaching with a renewal note.
The three startup failure messages#
In prod, a bad license stops startup with License check failed: …
(logged as license_check_failed). The three messages you will meet:
| Failure | Message |
|---|---|
| File missing | license file not found at <path>. Set ABRQ_LICENSE_FILE to a valid path or place the vendor-supplied license.json there. |
| Bad signature | license signature is invalid — file has been tampered with, or was signed by a key that doesn't match the embedded vendor key |
| Expired | license expired on <date> (now <date>). Contact the vendor for a renewal. |
A malformed file (invalid JSON, or not the expected
{payload: {...}, signature: '...'} envelope) also fails with a message
naming the path and the problem. A fingerprint mismatch on a bound
license fails startup the same way.
Confirming entitlements after install#
Once the backend is up, confirm what the license grants:
curl -H "Authorization: Bearer <ACCESS_TOKEN>" \
https://dip.example.com/api/v1/license
Check that status is ok, days_remaining is what you expect, and
features matches your order (an empty list means everything is
licensed — see Entitlements). The same information
appears in the UI under Settings → License & Backup.