# License Activation for Private Deployments / 私有化 License 激活方案 Core goal: for private-deployment delivery, the License does not chase absolute anti-cracking; it makes piracy detectable, containable, and attributable. This document covers only the license activation interaction flow, not how the client consumes a license file afterwards. 核心目标:私有化交付的 License 不追求绝对防破解,而是让盗版变成高成本、可检测、可止损、可追责。本文只聚焦 license 的激活交互流程,不讨论客户端拿到 license file 之后如何消费。 ## Conclusion (current scheme) / 结论(当前方案) Scheme = activation code + static Refresh Token + in-memory random instance-id detection + short-lived signed License. - An activation_code activates once and yields a static refresh token (RT, identity only, no entitlement). - Each refresh returns a short-lived signed License File (SLF, carrying the full entitlement) and extends the RT TTL when needed; the RT is never rotated. - Copy detection: the agent generates a non-persisted random instance-id in memory at startup and sends it on every refresh; when the cloud sees one RT with multiple concurrent, persistent instance-ids it flags license reuse and runs "alert -> confirm -> revoke". 方案 = 激活码 + 静态 Refresh Token + 内存 random instance-id 检测 + 短效签名 License。activation_code 单次激活换一个静态 RT(纯身份,不含授权信息);每次刷新返回一张短效签名 License File(SLF,携带全量 entitlement),必要时顺延 RT 的 TTL,不做 RT 轮转。复制检测靠 agent 启动时在内存生成的、不落盘的 random instance-id:每次 refresh 带上,云端看到同一个 RT 出现多个并发且持续的 instance-id 即判定证书复用,走「告警 → 确认 → 吊销」。 ## Threat model (two tiers) / 威胁模型(两层) - Tier 1 (copy, unmodified): copy/clone the whole running system incl. RT (over-deployment / whole-environment cloning / extract-and-reuse RT). Detectable via concurrent in-memory instance-id detection + frequency. This is the scheme's goal. - Tier 2 (code change / forged internal trust): modify the agent/service, patch out checks, pin the instance-id, forge agent-to-business-service trust. Not defensible by software alone; relies on legal contracts. Tier 1 无修改的复制(超量自部署 / 整环境克隆 / 取出并复用 RT)可检测;Tier 2 改代码或伪造内部信任,纯软件不防,靠法务合同。 ## Design premises / 设计前提 1. The trust channel between the private verification service and the business services is not breached; the License does not leak inside the private environment. Business services only accept entitlement pushed by the local license agent and never verify a bearer license file themselves. 2. The license agent is a singleton within a cluster (HA via leader). "One cluster = one live agent = one instance-id" makes the in-memory instance-id a clean copy-detection signal. Breaks when a signed license can be reused (e.g. a business service verifies it itself); then evaluate binding the license to the cluster key (key-binding). 承重前提:验签服务与业务服务之间的信任通道不被攻破,License 不在私有化环境内泄露;license agent 集群内单例,内存 instance-id 才是干净的复制检测信号。失效条件:当签名 license 可被盗用,需评估 key-binding。 ## Evolution path (old -> new) / 方案演进路径(旧 → 新) 1. Static License File: cloud-signed static file, local public-key verify. Simplest, fully offline; but manual renewal, no online revoke. 2. Key for License File: ship a long-lived key, exchange for a license file. Convenient online renewal; but the key is a long-lived token, no revoke within validity. 3. Key for short-lived License (SLF): day-scale full-entitlement snapshot, refreshed periodically (+ triggers). Enables revoke, up/down-scope, dynamic entitlement, fail-close; but a leaked long-lived key is reusable. 4. Activation Code for Refresh Token: one-time code redeemed for an RT; RT then refreshes SLFs. Narrows out-of-cluster distribution leaks, RT minted only in-cluster; but an in-cluster RT leak/clone is hard to notice. 5. (current) Static RT + in-memory instance-id detection: closes "RT leak/clone hard to notice". In-memory instance-id catches clones, cleaner than deployment_id, simplest structure, no rotation/grace/bricking. Cost: singleton agent + restart/rolling-upgrade overlap tolerance. 从静态文件 → key 换文件 → 短效 SLF → activation code 换 RT → 静态 RT + 内存 instance-id 检测;每一步解决上一步遗留的一个问题。 ## Key insights / 关键洞察 - The in-memory instance-id is the load-bearing duplication signal; fingerprint/deployment_id is a forgeable soft signal, not load-bearing. - authN/authZ split: RT = pure identity (long-lived), SLF = full entitlement snapshot (short-lived, signed) — OAuth's refresh token + access token. - Short SLF = stateless full entitlement: each is a self-contained signed snapshot; change/revoke/downscope just issues the next number; the client is stateless about entitlement. - A static RT is revocable, so no "permanent leak": churn/expiry/confirmed theft all revoke, fail-close within one TTL. - Core invariant: one license = one RT = one live consumer. Cloning and copying the RT both create a "second consumer"; the in-memory instance-id detects it, covering anti-duplication and anti-extraction at once. - detection-first: never stop on non-detection; use an overlap window + "alert -> confirm -> revoke". It never bricks. 内存 instance-id 是承重信号;authN/authZ 拆分;短 SLF 无状态;静态 RT 可 revoke;核心不变量「一个 license = 一个 RT = 一个 live consumer」;detection-first 永不变砖。 ## Activation / recovery flow / 激活 / 恢复流程 Normal activation (first time): cloud issues an activation code (high-entropy, short-lived, bound to customer/license, revocable, non-enumerable) -> singleton/leader agent redeems -> cloud validates (single-use / not expired / not revoked) -> mint static RT + first SLF + record redeem context -> void the code -> agent stores RT in a shared Secret, generates the in-memory instance-id, starts the refresh loop. Recovery / re-activation, two modes: A recovery (RT lost; issue a new code, redeem to swap in a new cert smoothly, avoid downtime); B revocation (confirmed theft; issue a new code and immediately revoke the old RT). Both revoke the old code first and converge to one live chain. Issuing a new code is the only "rotation" entry point; no silent server-side rotation. Leak signal at activation: re-redeeming a consumed activation code returns a clear error and is recorded as a potential outside-link leak; a thief redeeming first makes the legitimate customer's activation fail, turning a silent leak into a loud, attributable conflict. 正常激活一次性引导;恢复走 re-activation(恢复 / 吊销两模式,都先 revoke 旧 code,收敛到一条 live 链)。已消费码再 redeem = 泄露信号。 ## Protocol details / 协议细节 - SLF payload signs everything: license_id / customer_id / product_id / entitlement / lease_id / sequence / issued_at / not_before / expires_at; Ed25519 recommended. - Old-license replay: SLF carries a monotonic sequence; client keeps last_accepted_sequence and rejects smaller. - Clock rollback: issued_at/expires_at use server time; every restart refreshes from server; runtime uses a monotonic clock (time.Since). - Offline license verification: license bound to the kube-system namespace UID. - DB leak: cloud stores only HMAC(server_secret, raw_rt), server_secret in KMS. - Log leak: token prefixes for redaction; logs/traces/metrics/crash dumps scrubbed; errors return only error code + request_id. The point: make piracy no longer cheap, no longer invisible, no longer hard to attribute. / 核心:让盗版不再便宜、不再隐形、不再难以追责。