4.5 KiB
Executable File
title, description, nav
title | description | nav | ||
---|---|---|---|---|
Offline JWT licence & daily‑run quota | How Stella‑Ops enforces a **runs‑per‑day** limit in fully air‑gapped deployments. |
|
JWT‑based daily‑run licence (offline‑capable)
When Stella‑Ops scanners operate entirely offline, they cannot phone home
for metering.
Instead, the backend accepts a signed JSON Web Token (JWT) that states the
maximum number of scans per UTC day.
If no token is supplied, a grace quota of 33 runs/24 h applies.
1 Token contents
Claim | Purpose | Example |
---|---|---|
sub |
Customer / licensee identifier | "f47ac10b…" |
iat |
Issued‑at timestamp | 1722566400 |
exp |
Absolute licence expiry | 2025‑12‑31T23:59:59Z |
tier |
Max scans per UTC day | {{ quota_token }} |
tid |
Token identifier (32‑byte) | "7d2285..." |
pkg |
Product SKU / edition | "stella‑core" |
Tokens are signed with RS256 and verified locally using the bundled public key. Only the public key ships inside the container; the private key never leaves the build pipeline.
2 Obtaining a token
- Request →
POST /register { email:"alice@example.org" }
- Service hashes the e‑mail (SHA‑256), stores it, and issues a JWT (60 days by default).
- Token is e‑mailed to you.
A new request for the same e‑mail returns the same token until it nears expiry, avoiding quota “top‑ups” by re‑registration.
3 Supplying the token to an air‑gapped stack
# recommended
docker run \
-v /opt/stella/license/alice.jwt:/run/secrets/stella_license.jwt:ro \
stella‑ops
Other supported paths:
Method | Mount point | Hot‑reload |
---|---|---|
Docker secret | /run/secrets/… |
✓ (inotify) |
Bind‑mounted | user‑chosen path (above) | ✓ |
Env variable | STELLA_LICENSE_JWT |
✗ restart |
4 Quota‑enforcement algorithm
flowchart TD
Start --> Verify[Verify JWT signature]
Verify -->|Invalid| Deny1[Run in non licensed mode]
Verify --> Load[load today's counter UTC]
Load -->|SUM of last 24h scans < daily_quota| Permit[allow scan, add scan]
Permit --> End
Load -->|SUM of last 24h scans ≥ daily_quota| Deny1
5 Renewal procedure
Scenario | Action |
---|---|
More capacity | Request new token with higher daily_quota ; replace file – no restart needed |
Licence expiry | Same as above; new exp date |
Key rotation | Container image ships new public key(s); older tokens still verify |
6 Fallback limits
Situation | Daily quota |
---|---|
Valid JWT present | value of daily_quota claim ({{ quota_token }}) |
No JWT | 33 |
JWT expired (if used) | treated as anonymous unless policy enforces hard‑fail |
Token signature invalid | 0 (reject) |
7 Threat‑model highlights (future work / optional hardening)
Threat | Mitigation |
---|---|
Copy token & DB to 2nd node | Bind sub /tid to host fingerprint (TPM EK) – optional enterprise control |
Counter DB rollback | Hash‑chain + monotonic clock – optional enterprise control |
Flooding single node | Redis‑backed cluster rate‑limit (30 hits / 60 s) + edge Nginx (20 r/s) |
Key compromise | Rotate RS256 key‑pair, ship new pubkey, re‑sign tokens |
8 Anonymous (33 runs) mode
Offline PoCs without registration still work:
docker compose exec stella-ops stella-jwt reload # reloads, discovers no token
…but production deployments must register to unlock real‑world quotas and receive security advisories via e‑mail.
Last updated: 2025‑08‑02