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 itslicense_leasestable. - Holder: the deployment's
alphaswarm-localdaemon stores the lease at~/.alphaswarm-local/license_lease.jsonand auto-renews when < 24 h of validity remain. - Enforcement: with
license_enforcement_enabledON (wired by the BYOC terraform module), the platform gatesbyoc_deployments,kb_federation, andlive_tradingon the verified lease. - Revocation model: revocation is renewal denial — the auth service
answers 403
license_revokedat 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; sizettlandgrace_period_secondsaccordingly (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-keyserves the active key.
Issue a lease
- Admin UI → Identity Service → Licensing (
/identity/license). - Issue lease:
deployment_id(stable id of the customer install — for BYOC records useCustomerDeployment.license_deployment_id),entitlements(copy the customer's Resolved entitlements — plan ∪ contract overrides),ttl_seconds, optionalcustomer_idbacklink. - 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.
- Lease TTL must not outlive the contract: clamp
ttl_secondstoCustomerContract.ends_atwhen issuing near renewal boundaries.
Customer-side install / renewal
- Install:
alphaswarm-localwrites 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/leasealphaswarm/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:
- Issue the lease as above; fetch the active public key
(
GET /auth/license/public-key). - 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). - Force a new deployment — mandatory.
put-secret-valuedoes 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>-workerand<silo>-beat). - Verify with the environment's
secret_seed_manifestoutput +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
- Licensing page → the lease (or the deployment's active lease) →
Revoke (typed confirmation; step-up MFA; audit-first
admin.identity.license.revoke). - With
license_registry_enforcedON, the next renewal attempt gets 403 and the deployment enters grace at its natural expiry: requests pass withX-AlphaSwarm-License-Status: grace, then hard-403 (license_invalid) once grace lapses. - 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
revokedwith actor + reason. - Customer-side:
alphaswarm-local doctorreports the renewal denial; after expiry+grace, gated routes return 403license_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.