Skip to main content

License Lifecycle

Sukko uses ECDSA P-256-signed license keys to determine which edition (Community, Pro, Enterprise) is active. License changes take effect immediately via hot-reload — no restart required for upgrades or limit changes.

How License Changes Propagate​

When a license is reloaded via POST /api/v1/license:

  1. Provisioning validates the ECDSA P-256 signature and checks replay protection (iat must be newer)
  2. New edition and limits are atomically swapped in memory
  3. All services (Core, Gateway, Push) receive the update via gRPC stream
  4. Feature gates and limits take effect immediately

No restart is needed for upgrades or downgrades. The message backend is edition-independent — Kafka runs on every edition, so an edition change never forces a backend switch.

Upgrades​

Community → Pro​

What ChangesEffect
Tenant limit3 → 50 (new tenants can be created immediately)
Connection limit500 → 10,000
Shard limit1 → 8
Feature gatesSSE, Web Push, alerting, tracing, analytics, admin UI, token revocation, webhooks, connections API — all activate immediately. (The data path — Kafka backend, message history, gap recovery, REST publish — and per-tenant channel rules are ungated, available in every edition.)

Community → Enterprise​

Same as Community → Pro, plus:

What ChangesEffect
All limitsUnlimited
Feature gatesThe audit-log query API activates immediately (mobile push, FCM/APNs, is planned)

Pro → Enterprise​

What ChangesEffect
All limitsUnlimited (was capped)
Feature gatesEnterprise-only features activate: the audit-log query API (mobile push, FCM/APNs, is planned)

All upgrades are immediate. No data migration, no restart, no downtime.

Downgrades​

Downgrades are graceful — existing resources are preserved, but new creation is blocked when limits are exceeded.

Enterprise → Pro​

ComponentBehavior
Existing tenantsPreserved. New creation blocked if count exceeds 50.
Existing connectionsMaintained. New connections rejected if over 10,000.
Mobile push (FCM/APNs, planned)New android/ios registrations return 403 EDITION_LIMIT. Web Push continues (it is Pro). Existing device registrations preserved.
Audit logsRecords keep being written. Existing logs preserved. The query endpoint returns 403 EDITION_LIMIT.
ShardsIf running >8 shards, restart required to reduce.

Enterprise → Community​

ComponentBehavior
Existing tenantsPreserved. New creation blocked if count exceeds 3.
Existing connectionsMaintained. New connections rejected if over 500.
Kafka backendUnaffected — the backend is edition-independent. Ingestion, history, and gap recovery continue. Client/REST publishes into kafka become unroutable once routing rules can no longer be managed (routing is Pro).
SSE transportNew SSE connections return 403 EDITION_LIMIT. Existing SSE connections maintained.
Per-tenant channel rulesUnaffected — channel rules are ungated (available in every edition). Existing rules keep enforcing; creation and updates remain available.
Push notificationsNew registrations return 403 EDITION_LIMIT (Web Push requires Pro; mobile requires Enterprise). Existing registrations preserved.

Pro → Community​

Same as Enterprise → Community, except mobile push and the audit-log query API were already unavailable.

License Expiry​

When a license expires, Sukko immediately degrades to Community edition. There is no grace period — at expiry time, the system behaves as if running Community.

ScenarioEffect
Pro expiresSame as Pro → Community downgrade. Existing resources preserved, new creation blocked at Community limits.
Enterprise expiresSame as Enterprise → Community downgrade. The Kafka backend keeps running — ingestion is unaffected.

Monitoring Expiry​

Sukko exposes a Prometheus metric for license expiry:

sukko_license_expiry_timestamp

Set up an alert to catch upcoming expirations:

# Alert 7 days before expiry
- alert: SukkoLicenseExpiringSoon
expr: (sukko_license_expiry_timestamp - time()) < 7 * 86400
labels:
severity: warning

Key Behaviors​

No forced disconnections — Sukko never drops existing WebSocket or SSE connections on downgrade or expiry. Connections established before the change continue until the client disconnects.

No data deletion — Tenants, channel rules, routing rules, audit logs, and push registrations are never deleted on downgrade. They remain in the database and become accessible again on upgrade.

Replay protection — License keys include an iat (issued-at) timestamp. Older keys are rejected to prevent replay attacks.

Checking Current Edition​

Every service exposes an edition endpoint:

curl http://localhost:3000/edition   # Gateway
curl http://localhost:8080/edition # Provisioning
curl http://localhost:3005/edition # Core

Or via the CLI:

sukko edition

Key rotation & versioned upgrades​

Sukko's license public key is embedded in each binary, and license validation is fully offline — there is no license server to call. Two things follow for you as an operator:

  • Pin an immutable version. Deploy a specific ghcr.io/sukko-dev/sukko-*:vX.Y.Z image tag rather than a moving tag, so you always know exactly which build you are running.
  • Upgrades never invalidate a license. Upgrading to a newer Sukko version never breaks an existing, valid license key — upgrade whenever suits you.

On the rare occasion Sukko rotates the license signing key, the new Sukko release embeds both the previous and new keys during an overlap window. So:

  • Your existing license keeps validating after you upgrade — no coordinated cutover, no downtime.
  • Once you are on the newer release, any renewed or re-issued license simply works.

The one thing to know: stay reasonably current. If you skip the overlap release entirely and then renew your license after a rotation, the renewed key may be signed by a key your older binary does not embed — upgrading to a current vX.Y.Z release resolves it.

Next Steps​