本文是 ns、NS App、NSD、NSGW 和管理控制台并行实现时必须共同遵守的协议基线。产品含义以产品闭环为权威,身份与注册分别以身份登录和注册协议为权威;管理对象状态/API 见控制资源生命周期,建流与传输见数据面协议,逐功能完备性见功能闭环总账。本文只固定跨进程、跨仓库和跨版本的可观察契约。
| 契约 | 权威生产者 | 消费者 | 禁止事项 |
|---|---|---|---|
| Identity / Session | Identity Authority + NSD | Client、管理 API | App 保存密码或自行判断 MFA 强度 |
| Device / Enrollment | NSD | Client、ns | 仅凭显示名认领 Device |
| Network / Membership | NSD | ns、Client | 客户端自行分配 Node IP |
| Grant / Policy Projection | NSD compiler | ns、Client | Dart、CLI 或 NSGW 重写授权算法 |
| Local Service Manifest | 节点所有者或受管授权 | ns、NSD | NSD 越过节点本地上限发布后端 |
| Service Directory / DNS | NSD projection | ns、Client | 读取失败渲染为空目录 |
| Route / Exit / Gateway Lease | NSD | ns、NSGW、Client | 候选列表替代数据面的最终校验 |
| Entitlement | Entitlement issuer → NSD resolver | NSD、NSGW | 客户端自报套餐能力 |
| Runtime Status | ns runtime | Client、CLI | Client 从日志文本猜运行状态 |
| Local Runtime Ownership | ns runtime + OS peer authentication | Client、CLI、installer/helper | 非 owner 读取租户状态,或 OS 管理员凭维护权限冒充 owner |
共享类型放在 ns-shared-next。共享仓库只承载稳定 wire schema、标识符、签名与错误类型,不承载数据库 ORM、产品 UI 或平台路由实现。
所有外部对象使用不可枚举、全局唯一、类型明确的 ID。显示名可修改,绝不参与授权、幂等或引用完整性。
| 对象 | 建议字段 | 最小作用域 |
|---|---|---|
| Account | account_id | Identity Authority |
| Human/Machine Principal | principal_id | Organization |
| External Identity / Session | external_identity_id / session_id | Account + issuer |
| Organization | organization_id | Deployment |
| Network | network_id | Organization |
| Organization Membership / Group | org_membership_id / group_id | Organization |
| Admin Role Binding | role_binding_id | Organization + resource scope |
| Device | device_id | Organization;不跨组织复用 Device Key |
| Node Membership | membership_id | Network + Device |
| Service | service_id | Network |
| Endpoint | endpoint_id | Service + Membership |
| Grant Set / Rule | grant_set_id / rule_id | Network |
| Access Request / Temporary Grant | access_request_id / temporary_grant_id | Network |
| Capability Policy / Activation | capability_policy_id / activation_id | Organization/Network |
| Route | route_id | Network |
| Gateway / Profile | gateway_id / profile_ref | Organization/Network |
| Public Application / Edge Policy / Binding | application_id / edge_policy_id / binding_lease_id | Organization/Network |
| Share Offer / Binding / Federation | share_id / share_binding_id / federation_binding_id | provider/consumer Organization |
| Machine Credential | oauth_client_id / credential_id | MachinePrincipal |
| Posture Provider / Claim | posture_provider_id / posture_claim_id | Organization/Device |
| Rotation / Reservation | rotation_id / reservation_id | target object / Entitlement subject |
| Request / Operation | request_id / operation_id | Deployment |
每个 API、事件和审计记录都携带必要的 organization_id、network_id 与目标 ID。仓储层必须先按租户作用域过滤,再按对象 ID 查询;不能先查全局 ID 后在 handler 里补权限判断。
所有会改变状态的 API 使用统一命令语义:
request_id 用于端到端诊断,不作为幂等键;idempotency_key 在同一命令与租户作用域内唯一,重复请求必须返回同一业务结果;expected_revision,版本不符返回 revision_conflict 并附当前 revision;impact_digest,提交时重新计算,不一致返回 impact_changed;committed_revision 和投影跟踪 ID。命令名称进入共享 registry,首版至少覆盖:identity/session、Organization/Network/Group/Role、Enrollment/Device/Membership、AccessGrant/AccessRequest、CapabilityPolicy/Activation、Service/Publication、Route、Gateway/Selection/PublicApplication、Share/Federation、MachinePrincipal/OAuth client、Posture、Entitlement/Reservation、Audit/Export/Delete/Hold。每项 create/update/approve/suspend/revoke/rotate/delete 使用独立 action;完整状态和 API 以控制资源生命周期及专项文档为准。
每种事件独立版本,不存在一个可以推断全部能力的“产品版本”。
事件目标使用 device、membership、gateway 或 client_session 类型化引用,必须与认证身份和 payload 作用域一致。客户端处理顺序固定为:验证版本可理解 → 验签 → 校验目标与作用域 → 校验 epoch/revision/有效期 → 解析 payload → 构建候选状态 → 原子替换 → 回执。任何一步失败都不能覆盖最后有效状态。具体 stream 与 payload 见Runtime Protocol v1。
每个投影流独立维护 (deployment_id, target, event_type, epoch, revision) 水位。本地 profile_id 只用于 Client 选择保存的控制端,不进入 NSD 签名事件:
base_revision 必须等于本地 revision;projection_outdated,状态为 outdated_applied;事件回执区分 received、applied、rejected。applied 必须包含实际生效 revision;rejected 包含稳定错误码和可重试性,但不得回传私钥或完整敏感 payload。
跨层功能状态不得压成布尔值。所有功能至少分成四个正交轴:
| 轴 | 回答的问题 | 示例 |
|---|---|---|
| intent | 用户/管理员想要什么 | enabled / disabled / required |
| authority | 权威是否允许 | authorized / denied / unknown |
| projection | 控制面是否给出可执行配置 | waiting / matched / mismatch / expired |
| runtime | 本机或网关是否实际生效 | starting / ready / degraded / blocked / failed |
Client 展示由这些结构化轴推导,不得用“连接成功”覆盖部分失败,也不得用“无资源”覆盖读取故障。
错误码按原因而不是页面命名。固定分类如下:
| 类别 | 示例 | 默认动作 |
|---|---|---|
| authentication | session_expired | 重新登录,不撤 Membership |
| authorization | not_authorized | 不重试,联系管理员或修改 Grant |
| admission | quota_limit_reached | 显示真实资源与限制 |
| conflict | revision_conflict, route_conflict | 刷新权威状态并让用户决定 |
| unavailable | candidates_not_ready | 保持意图,等待或重试 |
| read_failure | projection_read_failed | 保留缓存,显示故障 |
| incompatible | schema_version_unsupported | 更新对应组件 |
| local_policy | local_manifest_denied | 在节点本地处理 |
| safety | capture_blocked, signature_invalid | 保持 fail-closed,禁止自动降级 |
| local_ownership | runtime_owned_by_another_local_user, runtime_owner_inactive | 不泄露 owner/tenant;等待、释放或明确 reset |
错误结构允许新增可选 details,但不能改变既有 code 的含义。用户文案由 Client 本地化,服务端 message 仅用于诊断。
能力发现分两层:
/.well-known/nsio-capabilities 用于匿名预检,短缓存、带 ETag,不作为安全权威;Manifest 只能关闭双方不共同支持的可选功能,不能降低签名、Device Key 绑定、确认页防钓鱼、租户隔离、授权或 fail-closed 基线。客户端自报“不支持安全能力”时,服务端拒绝对应流程,不切到更宽松路径。
首版共享 credential registry 至少包含:EnrollmentGrant、control credential、PeerPathLease、RelayRouteLease、ServiceFlowCredential、RouteAccessCredential、Capability Lease、EgressOriginLease、ExitTunnelLease、IngressBackendCredential、FederatedAccessLease、OAuth Access Token、EdgeSessionCredential 和 signed EdgeIdentityContext。每类 credential 有独立 audience/claims/schema/TTL/revoke key,不能用一个通用 bearer token 跨数据面。
服务端时间是 Grant、Lease、Session 与事件有效期的权威。客户端时钟只用于提示,并保留有限偏差窗口。所有短期授权包含 not_before、expires_at 和签发 revision;续租失败时保持最后有效状态直到过期,过期后执行对应资源的 fail-closed 行为。
撤销不依赖“立即收到一条删除事件”这一单点。Peer、Route、Gateway 和跨组织分享都使用短租约,使丢失撤销事件时也能在 SLA 内自然失效。
所有跨组件操作共享 request_id,关键状态变化另有稳定 operation_id。日志字段至少包含 component、deployment、organization、network、resource、revision、result 和 error code。指标只记录必要元数据,不记录业务内容。
必须可回答:
每个共享 schema 都必须具备:
共享契约未通过这些门,任何组件都不能宣布对应功能完成。