# license manage service **Repository Path**: onpromise/lms ## Basic Information - **Project Name**: license manage service - **Description**: 在做安全网元集中管控平台的过程中,本地的授权服务器(LMS)如同噩梦一般一直追随,带来了很多的困扰, 产品上易用性不好,运维中故障百出,苦其久已,其根本原因就是无法打消各厂商的信任顾虑,思来想去也只有开源是一个可行的尝试, 即使未必能成功. - **Primary Language**: Go - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2022-06-11 - **Last Updated**: 2022-10-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # lms ## 介绍 在做安全网元集中管控平台的过程中,本地的授权服务器(LMS)如同噩梦一般一直追随,带来了很多的困扰, 产品上易用性不好,运维中故障百出,苦其久已,其根本原因就是无法打消各厂商的信任顾虑,思来想去也只有开源是一个可行的尝试, 即使未必能成功. 我们将打造一个开源的本地授权服务器,会借鉴区块链、数字签名、程序加壳等技术, 作为构建信任的技术基础, 在信任的基础上构建一个标准的本地授权服务器,它的样子和各家的授权服务器其实也都类似的。之后我们还会持续的扩展其能力,例如在后付费模式上进行探索, 基于后付费模式,就可以基本做到“安全点"的任意互换。 ## 软件架构 ### 架构图 ![架构图](docs/images/lms.drawio.png) ### 功能介绍 #### 设备 设备为被授权的基本单位, 它要主动发起到LMS的心跳连接, 心跳信息中至少要包含其对应的签名服务的ID #### LMS LMS是本地授权管理的核心, 它是唯一对外可见的授权管理服务, 是导入授权的入口, 授权申请,授权状态查询等接口的提供者, 连接设备和签名服务的中介 #### 签名服务 设备是由不同的厂商提供的, 为了保障不同厂商的权益, 和设备进行信息沟通的心跳信息需要进行数字签名, 关键的授权信息需要加密, 这些都是签名服务提供的功能. 签名服务的框架是基本确定的,不同的厂商可以定制签名或签名算法,内置不同的私钥. 按道理内置私钥是不安全的,可能会造成厂商权益的破坏, 但是实际上很多设备都相对专业,厂商提供的服务(不限于前期协助沟通,后期技术支持)才是最重要的 ### 流程介绍 ```mermaid sequenceDiagram LMS-)LMS: 新设备上线 LMS-)设备: 查询设备类型 设备-)LMS: 返回设备类型,厂商信息,序列号信息,信息带有厂商的签名 LMS-)签名服务: LMS根据厂商信息定位到签名服务,确认设备是该厂商的 签名服务-)LMS: 设备是或不是该厂商的设备,如果是,LMS继续下面的流程 LMS->签名服务: 申请授权 签名服务-)签名服务: 链式记录授权信息,每个新加入的信息都要签名 签名服务-)LMS: 获取LMS的签名 LMS-)设备: 告知LMS地址,心跳频率等信息,授权信息 设备-)LMS: 周期心跳同步,同步授权状态 LMS->签名服务: 将心跳信息转发给签名服务, 确认授权合法 签名服务-)LMS: 心跳验证返回 LMS-)设备: 心跳验证返回 ``` ## 模块设计 ### 序列号 #### 数据结构 ```mermaid classDiagram class Hardware { + HostInfo() String + ProductInfo() String + BoardInfo() String + BiosInfo() String + CpuInfo() String + MemInfo() String + NetworksInfo() String + SerialNum() String } class Node { + String Address + GetSerial() + PeerNodes() } ``` 最终要基于SerialNum产生序列号, 初步的规划是基于内容序列化后, 对序列化的内容进行sha256计算, hash值为序列化号 #### 处理流程 ```mermaid flowchart TD Start((开始)) SerialIntf[序列号接口] Hardware[硬件信息查询] CreateSerial[创建序列号] HasPeerNodes{有其它节点吗?} GetPeerSerial[获取其它节点的序列号] End[结束] Start --> SerialIntf SerialIntf --> Hardware Hardware --> CreateSerial CreateSerial --> HasPeerNodes HasPeerNodes --> |Yes| GetPeerSerial HasPeerNodes --> |No| End GetPeerSerial --> End ``` ### LMS #### 数据结构 ```mermaid classDiagram %% 接口,对外提供Restful接口 class Restful { + QueryLicenseSummary() + QueryLicensesByType() + QueryLicenseByComponent() + AssignLicenseByComponent() + RevertLicenseByComponent() + ExportLicenseChain() + DeviceHeartbeat() } %% 和签名服务的交互,几乎LMS所有的接口请求都会转发给签名服务 class SignService { + SetLMSInfo() + QueryLicensesByType() + QueryLicenseByComponent() + AssignLicenseByComponent() + RevertLicenseByComponent() + DeviceHeartbeat() } %% 和设备交互的模块 %% SetLMSInfo中,也会把签名服务的SN告知设备 class Device { + QueryDeviceSN() + QueryLicenseStatus() + SetLMSInfo() + GetLMSInfo() } %% 主要用来存储LMS签名的授权 class SignStore { + StoreSignedLicense() + QuerySignedLicenses() + QuerySignedLicensesByComponent() } ``` #### 处理流程 ##### QueryLicenseSummary ```mermaid flowchart TD Start(请求开始) AuthCheck{授权和鉴权} QuerySignService[向所有授权服务发起请求] SumQueryResult[汇总授权服务的返回结果] Error[设置错误信息] End[结束] Start --> AuthCheck AuthCheck --> |成功| QuerySignService AuthCheck --> |失败| Error QuerySignService --> SumQueryResult SumQueryResult --> End Error --> End ``` ##### QueryLicensesByType ```mermaid flowchart TD Start(请求开始) AuthCheck{授权和鉴权} QuerySignService[向特定授权服务发起请求] Error[设置错误信息] End[结束] Start --> AuthCheck AuthCheck --> |成功| QuerySignService AuthCheck --> |失败| Error QuerySignService --> End Error --> End ``` ##### QueryLicenseByComponent ```mermaid flowchart TD Start(请求开始) AuthCheck{授权和鉴权} QuerySignService[向特定授权服务发起针对特定组件的查询请求] Error[设置错误信息] End[结束] Start --> AuthCheck AuthCheck --> |成功| QuerySignService AuthCheck --> |失败| Error QuerySignService --> End Error --> End ``` ##### AssignLicenseByComponent ```mermaid flowchart TD Start(请求开始) AuthCheck{授权和鉴权} CheckLicenseReq{LMS检查授权申请是否有效} SignServiceCheck{授权服务检查授权申请是否有效} LMSSignLicense[LMS先对授权进行签名] SignServiceSignLicense[请求授权服务对授权进行签名] Error[设置错误信息] End[结束] Start --> AuthCheck AuthCheck --> |成功| CheckLicenseReq AuthCheck --> |失败| Error CheckLicenseReq --> |OK| SignServiceCheck CheckLicenseReq --> |Fail| Error SignServiceCheck --> |OK| LMSSignLicense SignServiceCheck --> |Fail| Error LMSSignLicense --> SignServiceSignLicense SignServiceSignLicense --> End Error --> End ``` ##### RevertLicenseByComponent ```mermaid flowchart TD Start(请求开始) AuthCheck{授权和鉴权} CheckRevertReq{LMS检查撤销申请是否有效} SignServiceCheck{授权服务检查撤销申请是否有效} LMSSignRevert[LMS先对撤销进行签名] SignServiceSignRevert[请求授权服务对撤销进行签名] Error[设置错误信息] End[结束] Start --> AuthCheck AuthCheck --> |成功| CheckRevertReq AuthCheck --> |失败| Error CheckRevertReq --> |OK| SignServiceCheck CheckRevertReq --> |Fail| Error SignServiceCheck --> |OK| LMSSignRevert SignServiceCheck --> |Fail| Error LMSSignRevert --> SignServiceSignRevert SignServiceSignRevert --> End Error --> End ``` ##### DeviceHeartbeat ```mermaid flowchart TD Start(请求开始) LMSSignCheck{LMS检测设备的签名是否合法} LogHeartbeatReq[记录心跳请求信息] RelayToSignService[将心跳消息转发给授权服务器] LogHeartbeatResp[记录心跳响应信息] RelayRespToDevice[将授权服务的响应转发给设备] Error[错误] End[结束] Start --> LMSSignCheck LMSSignCheck --> |OK| LogHeartbeatReq LMSSignCheck --> |Fail| Error LogHeartbeatReq --> RelayToSignService RelayToSignService --> RelayRespToDevice RelayRespToDevice --> LogHeartbeatResp LogHeartbeatResp --> End Error --> End ``` ### 签名服务 #### 数据结构 ```mermaid classDiagram %% 接口,对外提供Restful接口 class RpcRestful { + QueryLicensesByType() + QueryLicenseByComponent() + AssignLicenseByComponent() + RevertLicenseByComponent() + DeviceHeartbeat() + ExportLicenseChain() } %% 授权信息记录 class LicenseStore { + QueryLicenseChain() + AppendLicenseChain() + ExportLicenseChain() } %% 签名管理 class SignMgr { + String LMSPubKey + String SignPrivKey } ``` 每一个签名信息中都会记录当前已经签发的授权的总数, 操作完成后的数量, 如果是新增授权,就+1, 如果撤销授权, 就-1 #### 处理流程 ##### QueryLicensesByType ```mermaid flowchart TD Start(RPC开始) AuthCheck[鉴权] QueryLicenses[查询所有的授权的当前状态,包括总数等信息] Error[设置错误信息] End[查询结束] Start --> AuthCheck AuthCheck --> |OK| QueryLicenses AuthCheck --> |Fail| Error QueryLicenses --> End Error --> End ``` ##### QueryLicenseByComponent ```mermaid flowchart TD Start(RPC开始) AuthCheck[鉴权] QueryLicenses[查询组件授权的当前状态,包括签名链等信息] Error[设置错误信息] End[查询结束] Start --> AuthCheck AuthCheck --> |OK| QueryLicense AuthCheck --> |Fail| Error QueryLicense --> End Error --> End ``` ##### AssignLicenseByComponent ```mermaid flowchart TD Start(RPC开始) AuthCheck[鉴权] LicenseCheck{检查是否有授权可用} AssignLicense[签发授权,保存授权] Error[设置错误信息] End[分配授权结束] Start --> AuthCheck AuthCheck --> |OK| LicenseCheck AuthCheck --> |Fail| Error LicenseCheck --> |OK| AssignLicense LicenseCheck --> |Fail| Error AssignLicense --> End Error --> End ``` ##### RevertLicenseByComponent ```mermaid flowchart TD Start(RPC开始) AuthCheck[鉴权] LicenseCheck{检查是否有授权可撤销} RevertLicense[撤销授权,保存结果] Error[设置错误信息] End[分配授权结束] Start --> AuthCheck AuthCheck --> |OK| LicenseCheck AuthCheck --> |Fail| Error LicenseCheck --> |OK| RevertLicense LicenseCheck --> |Fail| Error RevertLicense --> End Error --> End ``` ##### DeviceHeartbeat ```mermaid flowchart TD Start(请求开始) AuthCheck[鉴权] SignCheck{检测设备的签名是否合法} MakeResp[组装心跳同步结果] Error[记录错误,达到上限后可以暂停该设备授权] End[结束] Start --> AuthCheck AuthCheck --> |OK| SignCheck AuthCheck --> |Fail| Error SignCheck --> |OK| MakeResp SignCheck --> |Fail| Error Error --> MakeResp MakeResp --> End ``` ##### ExportLicenseChain 导出目前为止的签发链, 帮助厂商离线确认目前的授权数量 ```mermaid flowchart TD Start(请求开始) AuthCheck[鉴权] ExportChain[导出链] Error[导出错误] End Start --> AuthCheck AuthCheck --> |OK| ExportChain AuthCheck --> |Fail| Error Error --> End ExportChain --> End ``` ### 设备 #### 数据结构 ```mermaid classDiagram %% Heartbeat中就可以包括授权的分配和撤销 class LicenseMgr{ + QueryLicense() + AssignLicense() + Heartbeat() } ``` #### 处理流程 ##### QueryLicense ```mermaid flowchart TD Start(开始) AuthCheck[鉴权] Query[查询] Error[错误] End[结束] Start --> AuthCheck AuthCheck --> |OK| Query AuthCheck --> |Fail| Error Query --> End Error --> End ``` ##### AssignLicense 正常情况下建议通过heartbeat来获取授权 ```mermaid flowchart TD Start(开始) AuthCheck[鉴权] IsOffical{正式授权吗} AssignLicense[分配正式授权] AssignTmpLicense[分配临时授权] Error[错误] End[结束] Start --> AuthCheck AuthCheck --> |OK| IsOffical AuthCheck --> |Fail| Error IsOffical --> |Yes| AssignLicense IsOffical --> |No| AssignTmpLicense Error --> End AssignLicense --> End AssignTmpLicense --> End ``` ##### Heartbeat ```mermaid flowchart TD Start(开始) SyncLicenseStatus[同步授权状态] IsLicensed{已经授权?} AssignOrRevert{分配或撤销授权} AssignLicense[获取到分配的授权] RevertLicense[撤销原来的授权] IsLicenseValid[授权是否还有效] Working[正常工作] ReportInValid[报告授权失效] Unworking[停止工作] End[结束] Start --> SyncLicenseStatus SyncLicenseStatus --> IsLicensed IsLicensed --> |Yes| AssignOrRevert IsLicensed --> |No| IsLicenseValid AssignOrRevert --> |Assign| AssignLicense AssignOrRevert --> |Revert| RevertLicense IsLicenseValid --> |Yes| Working IsLicenseValid --> |No| ReportInValid ReportInValid --> Unworking AssignLicense --> End RevertLicense --> End Working --> End Unworking --> End ``` # UPX加壳 基于UPX对二进制程序进行加壳,进一步增强防护 # 异常处理 ## LMS或签名服务不可用 1. 服务却是挂掉 2. 服务状态异常,不能即使修复 能不能导出当前的授权信息, 让厂商在家里签发一个特殊授权, 通过预留的驱动导入设备, 临时延长设备的服务时间,避免设备不可用 # 后付费授权模式 ## 何为后付费 主要是在不知道客户具体使用设备数量的前提下不能完成确定性的签约, 类似只能支付定金,因此只能在一定时间段后才能确定最终的付费 ## 优势 如果可以采用后付费的模式, 集成者就可以实现类似通用授权的功能, 一个授权可以申请任何一个设备,例如 1. 集成商发了100个授权, 5个不同厂商的设备(A,B,C,D,E), 5个厂商设备都有100个虚拟授权可供使用 2. 可以开通100个A设备,其他设备都不开 3. 时候同步设备使用情况, 发现只需要和A进行再结算 ## 劣势 1. 技术相对复杂 2. 运维相对复杂, 对于不能在线同步的情况下,需要有离线同步的工作量 ## 保障 签名服务应该每隔一段时间(7天或一个月)就统计当前授权状态,并签发确认,追加到确认链中 如果3个月后进行同步, 要能拿到到目前为止的链上所有节点的信息,而不仅仅是当前的状态, 防止造假 # 其他规划 # 胡言乱语,一家之言 ## wangyuchang ### 开放与零信任 开放是零信任的基础, 就像加密算法的开放一样,过于封闭的技术体系一定是零信任的阻碍,因为技术不透明,存在风险, 同时因为不开放,也导致掌握相关技术的人的数量有限,甚至在理解上造成偏差,从而影响协同.