Format
A self-hosted license is an Ed25519-signed JWT:- Signature scheme:
EdDSA(RFC 8037 Ed25519). - The
radar-hubbinary embeds the Skyhook-controlled public key at build time. The matching private key never leaves Skyhook’s secret store. - Verified offline at boot - no network call required for the signature check itself.
Claims
license.key. max_clusters and exp drive the in-app cluster-cap and expiry banners.
How verification works
At boot
The control plane reads the JWT from one of:RADAR_HUB_LICENSE_KEYenv var (preferred)./etc/radar-hub/licensefile (Helm Secret mount).
radar-hub: in the log line - grep for these strings):
License-set path (the most common case):
radar-hub: license verified- happy path. Same log line carries license id, org, tier, max_clusters, expiry.radar-hub: license expired (warn-only - hub keeps serving)- signature OK, pastexp. An already-bootstrapped hub keeps serving behind the banner.radar-hub: license is invalid (bad signature or claims)- signature mismatch or a missing/invalid claim. A not-yet-bootstrapped hub stays blocked at the license-required screen until a validlicense.keyis set; an already-bootstrapped hub keeps serving. Investigate immediately - this almost always means the wrong build talking to a real key, or vice versa.
radar-hub: no license configured- the JWT env/file wasn’t supplied. A not-yet-bootstrapped hub stays blocked untillicense.keyis set; an already-bootstrapped hub keeps serving. Setlicense.keyin your Helm values or mount a Secret to/etc/radar-hub/license.
ghcr.io/skyhook-dev/radar-hub images):
radar-hub: embedded license public key is the all-zero placeholder; rebuild with the real key before shipping to a customer- the build wasn’t cut against the real Skyhook public key, so license verification cannot succeed against any real customer JWT. Only happens on a locally-built image - the officialghcr.io/skyhook-dev/radar-hub:<version>images embed the production public key. If you see this in production, you’re running an unofficial build; pull the published tag instead.
Warn-only enforcement
The control plane does NOT block writes when a license that was present later expires or fails verification. Enforcement is contractual via the Subscription Agreement, not technical. The user-visible behavior is:- A persistent yellow banner in the web app when verification has failed.
- Boot log lines visible to the operator.
Rotation
Licenses are issued for a fixed term (typically 12 months) matching the contract. Renewal is always manual: your account team emails a new JWT; you update the Helm value or Secret and roll theradar-hub Deployment.
Key rotation (Skyhook-side)
The embedded public key is append-only. Skyhook will publish a new chartappVersion with both the old and new public keys when the signing key rotates; existing deployments keep working until they upgrade past the cutover release.
You don’t need to do anything for a public-key rotation - just stay on supported chart versions and run helm upgrade at your normal cadence.
What you control
- The license JWT itself (rotate by upgrading the chart with a new value).
- Cookie sealing key (
hub.cookiePassword) - independent from the license; rotating it just signs everyone out. - The break-glass admin (always available, regardless of license state).
What Skyhook controls
- The signing private key.
- The terms of the Subscription Agreement that backs warn-only enforcement.