How licensing works
How licensing works
Your deployment runs under a license issued by the Solvegio Hub. The license is a signed token that lives in a Kubernetes Secret in your namespace. A small Deployment called the license agent obtains it, keeps it fresh, and writes every successor back into that Secret.
Everything below happens inside your cluster, driven by outbound HTTPS calls. Nothing is pushed to you.
You get a code
We mint a one-time activation code for your deployment. You pass it to the chart:
helm install my-mvno solvegio/platform \
--set platform.kind=mvno \
--set platform.host=platform.example.com \
--set activation.code=<code-from-the-hub-console>
activation.code is the one licensing value you set. The chart writes it into the platform Secret (<release>-platform-env) under ACTIVATION_CODE.
The code is single-use. It also carries a fingerprint of the Hub's own signing key, packed into the code string. The agent checks that fingerprint against the key set published by activation.parentUrl before it enrolls, so a code minted for you cannot be redeemed against an impostor Hub.
The agent generates a key and enrolls
The license agent (<release>-platform-license-agent) starts alongside the API. On its first pass it finds no license in the Secret, so it enrolls.
It generates a 32-byte Ed25519 seed with the cluster's own randomness, derives a keypair from it, and posts the activation code plus the public half of that key to POST /v1/deployments/activate on the Hub. The private half stays in your namespace. See Your key never leaves for what that guarantee rests on.
The Hub redeems the code and mints a license bound to the key you presented. Binding means the license carries a cnf claim holding the thumbprint of your public key. A license with a cnf is worth nothing to anyone who does not hold the matching private key, because every later call has to prove possession of it.
The agent then writes the result back into the platform Secret. Six keys, and this is the complete set the agent ever owns:
| Secret key | What it holds |
|---|---|
PARENT_LEASE_TOKEN | The license itself |
SIGNING_SEED | The seed the enrollment key was derived from |
POP_SIGNING_SEED | The seed of the key the current license is bound to |
PARENT_BASE_URL | The Hub the deployment is pinned to |
REQUIRE_PARENT_LEASE | Set to true, which is what makes the API fail closed |
ACTIVATION_CODE_CONSUMED | The code that was spent, so the same one is never replayed |
A revoked deployment carries a seventh, LEASE_STATUS, which the agent sets and then clears again on recovery. See Revoke and recover. Every other key in that Secret comes from the chart or from you.
The API Deployment has been sitting behind a wait-for-lease initContainer this whole time. PARENT_LEASE_TOKEN landing in the Secret is what releases it. An unlicensed deployment never serves a request.
From then on, it renews
The license has a finite term. The Hub sets it (two weeks, by default) and stamps it into the token's exp claim, so you can always read your own expiry out of the token you hold.
The agent renews well before that. It calls POST /v1/licenses/{jti}/renew, signing the request with the key the current license is bound to. That signature is the proof of possession: only the holder of the private key can produce it.
Every renewal also rotates the key. Before it calls, the agent generates a new keypair and puts that new key's thumbprint in the request body. The Hub verifies the proof made with the old key, mints a successor license bound to the new one, and returns it. So each renewal is two things at once: an extension of the term, and a handover to a key that has never been used before.
The agent then persists both halves of the result, the successor license and the seed of the key it is bound to, in a single patch to the Secret.
Why the write-back is the whole point
This is the part that matters operationally.
The lease in your Secret is always the most recent one the agent obtained, not the one you installed with. A pod that restarts eight months after install reads whatever the agent last wrote. It finds a current license, bound to a current key, and it boots and serves.
The API does not even need the restart. It mounts PARENT_LEASE_TOKEN and POP_SIGNING_SEED from the Secret at /etc/platform/lease and /etc/platform/pop_seed and watches those files, so a rotation the agent performs at 3am is picked up in place, with no rollout and no dropped requests.
Grace, and what happens when the Hub is unreachable
Renewal fires early in the license term, leaving most of the term unused. That gap is deliberate: it is the grace window.
If the Hub is briefly unreachable, the renew attempt fails, the agent retries with exponential backoff, and your deployment keeps serving the whole time on the license it already holds. The failure is not a licensing event, it is a network event, and it costs you nothing until the license you hold actually expires. The window is wide enough to absorb an outage on either side without an operator noticing.
The agent publishes license_expiry_seconds on its metrics port, which is the number to alert on if you want warning. See Observability.
Fail closed
If there is no valid license, the deployment does not serve business traffic.
- No license in the Secret at boot: the
wait-for-leaseinitContainer never completes, and the API pod never starts. - License present but expired, or cleared because the Hub revoked it: every gated business route answers
424 Failed Dependency. The body saysparent lease not loadedorparent lease revokeddepending on which it is. /healthkeeps answering, in every one of those states. The process does not crash and Kubernetes does not restart-loop it. A deployment without a license is quiet, not broken, and your data is untouched.
Requests that fail authentication still get their usual 401 first. The license gate sits behind auth, not in front of it.
Where to go next
- Your key never leaves: the trust guarantees and the agent's exact Kubernetes permissions.
- What phones home: the exact fields that leave your cluster.
- Revoke and recover: what a revocation does, and the one command that undoes it.
- Licensing failures: when the agent will not enroll.