状态
Accepted(Revised,2026-07-25)。
背景
私有 NuGet Feed 只能限制未来下载;它无法召回已缓存包。客户在离线、本地、容器与 Kubernetes 中运行,因此商业运行时授权需要一个独立于包下载权利与租户 Feature 授权的信任模型。
决策
十三条决策定义该信任模型:
- ES256 签名的不可变 License Envelope——厂商私钥签名;客户 Runtime 公钥验证;私钥仅存在于 KMS/HSM 或受控签发系统。
- License 约束 Customer、Product、Edition、Feature、Version Range、Environment、Deployment Limit、有效期、离线租约、grace 期、KeyId 与协议版本。
- 请求路径不远程调用 License 服务——在线激活签发短期租约;Runtime 在本地验证签名 + 状态;后台服务安全刷新。
- 失败关闭状态——从未激活、伪造签名、被撤销或过度授权均失败关闭。一个已激活实例在短暂网络故障下可进入有限的
Grace,但必须告警并暴露就绪状态。 - 统一状态:
Valid / Grace / Expired / Revoked / Invalid / Unavailable。 - 许可强制执行不仅在 UI/Host 中间件——一个商业模块执行入口通过生成的 descriptor 或统一 Mediator 管线消费许可决策;缺失的 Licensing 适配器默认拒绝。
- DeploymentId 是持久的 Site/Deployment 身份——不是 PodId/ContainerId/MAC/CPU——跨多实例共享,使扩缩容不重新消费授权。
- 离线租约——离线部署使用限时签名 License 文件;即时撤销不可能,因此撤销列表与续期通过受控离线流程到达。
- 许可到期不得破坏客户备份/导出/迁移;写入限制与数据可移植性遵循商业合同。
- Strong Name/混淆/完整性/Native AOT 仅提高攻击成本——它们不是信任根。
- 密钥轮换与到期协议可移植性——共享免费策略不能成为未签名绕过。协议 v2 在签名 payload 中加入
policyId/profile/静态composition;协议 v1 的规范签名字节保持不变。共享 DeploymentId 仅允许由 ADR 0504 激活的精确组合。 - 基础控制面不依赖客户商业许可——最低身份会话、强制改密、密码恢复、权限过滤导航及受权 LicenseManagement 操作使用编译期精确消息清单跳过商业 gate;认证、授权、校验、事务和审计照常执行,邀请、注册、用户管理与业务功能不在清单中。
- 基础就绪与商业就绪分离——
/health/ready决定实例能否承接基础流量,/health/license独立报告商业许可状态,/health保留聚合诊断。License 不可用不会把控制面从负载均衡摘除,普通业务仍失败关闭。
后果
License 模块是一个深层模块,把签名、可信时间、缓存、在线/离线租约、密钥轮换与状态机隐藏在稳定接口之后。当客户完全控制私有 Host 时,绝对防补丁是不可能的——真正不可泄露的能力保留在厂商控制的远程服务中。PlatformBilling 可在客户系统内提供租户套餐,但不能签发或决策厂商 Runtime License。