Saltar al contenido principal

License issuance and revocation

Procedure for issuing, renewing, and revoking Ed25519-signed offline license leases for self-hosted / BYOC deployments.

How the system fits together:

  • Issuer: the identity service (alphaswarm_auth) signs leases (POST /auth/license/leases) and — since the license registry — records every issued lease in its license_leases table.
  • Holder: the deployment's alphaswarm-local daemon stores the lease at ~/.alphaswarm-local/license_lease.json and auto-renews when < 24 h of validity remain.
  • Enforcement: with license_enforcement_enabled ON (wired by the BYOC terraform module), the platform gates byoc_deployments, kb_federation, and live_trading on the verified lease.
  • Revocation model: revocation is renewal denial — the auth service answers 403 license_revoked at the next renewal, and the offline copy decays through its natural expiry → grace → expired window. There is no remote kill of an already-issued lease; size ttl and grace_period_seconds accordingly (default posture: 7-day TTL, 3-day grace).

Key custody​

  • Signing key: ALPHASWARM_AUTH_LICENSE_LEASE_PRIVATE_KEY_PEM (or ..._PATH) on the auth service — secrets platform only, never in config files.
  • Rotation: introduce the new key under a new public_key_id, keep serving the old public key until every outstanding lease under it has expired, then retire it. GET /auth/license/public-key serves the active key.

Issue a lease​

  1. Admin UI → Identity Service → Licensing (/identity/license).
  2. Issue lease: deployment_id (stable id of the customer install — for BYOC records use CustomerDeployment.license_deployment_id), entitlements (copy the customer's Resolved entitlements — plan ∪ contract overrides), ttl_seconds, optional customer_id backlink.
  3. The signed lease JSON is returned once — deliver it to the customer installer or bake it via the BYOC bootstrap. The registry row is what you audit later; the signature cannot be re-derived without re-issuing.
  4. Lease TTL must not outlive the contract: clamp ttl_seconds to CustomerContract.ends_at when issuing near renewal boundaries.

Customer-side install / renewal​

  • Install: alphaswarm-local writes the lease + public key under ~/.alphaswarm-local/.
  • Renewal is unattended (renew_license_lease): device credential → POST /auth/license/leases → verify → atomic rewrite. The platform's mtime-cached verifier picks the new lease up without restart.

BYOC ECS delivery (Secrets Manager seed + forced redeployment)​

For BYOC workload-plane deployments (ADR 031; customer_account_aws with enable_workload_plane = true) there is no alphaswarm-local daemon and no auto-renewal. The lease travels via two Secrets Manager containers in the CUSTOMER account (placeholder + ignore_changes; Terraform owns the container, never the value):

  • alphaswarm/customer/<slug>/<env>/license/lease
  • alphaswarm/customer/<slug>/<env>/license/public_key

ECS injects both as env at task start and the container preamble writes them to the ALPHASWARM_LICENSE_*_PATH files.

Seed / rotate:

  1. Issue the lease as above; fetch the active public key (GET /auth/license/public-key).
  2. Seed both values (this is the ONLY place the lease JSON is handled; never commit it): aws secretsmanager put-secret-value --secret-id alphaswarm/customer/<slug>/<env>/license/lease --secret-string file://lease.json (same for .../license/public_key).
  3. Force a new deployment — mandatory. put-secret-value does NOT restart anything; ECS resolves secrets only at task start, so running tasks keep the OLD lease until replaced: aws ecs update-service --cluster <silo>-ecs --service <silo>-api --force-new-deployment (repeat for <silo>-worker and <silo>-beat).
  4. Verify with the environment's secret_seed_manifest output + scripts/preflight_secrets_seeded.py (value-free: names/status only).

Renewal is the same seed + forced-redeploy loop, operator-run, BEFORE expiry+grace lapses — an expired lease 403s the gated surfaces (byoc_deployments, kb_federation, live_trading) until re-seeded and redeployed. Scope honesty: a delivered lease means "lease present, API-side gates active" — workers enforce nothing per-task.

Revoke​

  1. Licensing page → the lease (or the deployment's active lease) → Revoke (typed confirmation; step-up MFA; audit-first admin.identity.license.revoke).
  2. With license_registry_enforced ON, the next renewal attempt gets 403 and the deployment enters grace at its natural expiry: requests pass with X-AlphaSwarm-License-Status: grace, then hard-403 (license_invalid) once grace lapses.
  3. For contract termination, revoke all active leases for the deployment (the deployment-scoped revoke does this in one call).

Post-action verification​

  • Registry list shows the lease revoked with actor + reason.
  • Customer-side: alphaswarm-local doctor reports the renewal denial; after expiry+grace, gated routes return 403 license_invalid.

Escalation​

  • Issuance 503 license_lease_unavailable → signing key missing/unreadable on the auth service.
  • Legitimate customer hard-locked (e.g. clock skew) → issue a fresh short-TTL lease rather than disabling enforcement.