本文定义 NSD、ns、NSGW 和 Client 共同实现的首版运行控制协议。字段名是实现基线;具体编码首选 canonical JSON/CBOR 中可稳定签名的一种,由 ns-shared-next 固定。所有示例省略共享事件信封中的签名和时间字段。Peer、Relay、ServiceFlow、RouteFlow 和 Gateway 的建流/传输以 Data Plane Protocol v1 为权威。
一个 Profile 绑定一个 NSD deployment、账号会话和本地 Organization Device
identity。profile_id 只是 Client 本地配置 ID,不发送给 NSD,也不进入签名
artifact。/control 使用四个 production SignedArtifact 完成认证,不能压缩成只校验
Device ID 的一次请求/响应:
ControlHello 至少包含:
protocol_version=1、expected_deployment_id、device_id、device_key_id;client_nonce;ns 的完整 CapabilityManifest,而不是未认证的 capability header;(target_membership_id, stream) 严格排序的 projection watermarks。NSD 可以先解码 device_id 定位注册记录,但在注册 Device Key 验证原始完整
artifact前,任何 Hello 字段都不是权威。Device 已禁用/撤销、Deployment 不同、Key
ID 不同、签名错误分别拒绝;不能通过未知字段或 capability 降级进入旧认证路径。
NSD 验证 Hello 后计算两个已签名 manifest 的确定性交集,并要求结果仍包含
control@1.0。Challenge 由 NSD Authority 签名,绑定:
challenge_id、服务端 nonce、Deployment、Organization、Device 和 Device Key;Challenge 最长 60 秒。NSD 还要在服务端保存 Device authority generation、预期 session
generation、Hello/Challenge 原始字节及一个非 wire 字段
transport_binding。该 binding 必须来自已认证信道 exporter 或等价的连接唯一值,不能
使用客户端自报连接 ID。
ns 先验证 NSD Challenge 签名、Deployment 和 Hello 绑定,再对
digest(exact signed Hello, exact signed Challenge) 签名。NSD 收到 Authenticate 后重新
读取当前 Device 权威,验证完整 transcript,并在一个原子提交里:
ControlSessionCredential bytes。同一认证 transport 上对同一个 Authenticate 的精确重传返回原来那份已签名 credential; 不同 transport、不同 proof、过期 Challenge、已被后续 session 取代的旧重传都拒绝。并发 提交不能签发两个新 generation。
Credential 最长 15 分钟,scope 在 v1 只能是 runtime_projection_read,并精确绑定
Deployment、Organization、Device、Device Key、当前有权读取的排序 Membership 集、三个
capability digest、transcript digest、Authenticate artifact digest、session generation、
revoke key 和有效期。它只允许读取发给这些 Membership 的 runtime 投影,不能调用租户
管理 API,也不能因为 Device 后续加入了 Network 就自动扩大旧 credential。
过期前续期必须重新执行握手。Device authority、Membership 或 Device Key 发生变化时, 待提交 Challenge 失效;已发 credential 的在线撤销和短 TTL 共同满足撤销 SLA。
NSD 必须把当前 Credential 的 ID、session ID、generation、revoke_key、固定有效期和
撤销 disposition 与 Device session authority 原子持久化。按 revoke_key 撤销只命中这
一份当前 Credential,不改变 Device/Membership authority,也不增加 session generation;
重复撤销幂等,错误或已被替换的 key 返回 superseded,不能影响新会话。投影发送前、空闲
唤醒后和 ACK 持久化前都重新检查该 disposition。撤销后旧流不能再收事件或提交 ACK,
同一 active Device 可重新认证为新 generation,并从未清除的 outbox 继续收敛。
Shared 定义 canonical CBOR、domain-separated digest、签名与四消息验证;NSD 定义原子 Challenge/session authority;HTTP/QUIC framing 只负责有界传输和生成可信 transport binding。传输层不得重新解释身份、capability 或 Membership scope。持久化、多实例 claim、 故障转移和网络 ACK 是独立实现项,不能从单进程握手测试推断已经完成。
事件的 event_type 与 schema_version 分开:
| Stream | Snapshot | Delta/Status | Target |
|---|---|---|---|
| netmap | netmap.snapshot | netmap.delta | Membership |
| grants | grants.snapshot | grants.delta | Membership / Gateway |
| services | services.snapshot | services.delta | Membership |
| dns | dns.snapshot | dns.delta | Membership |
| routes | routes.snapshot | routes.delta | Client/Connector Membership |
| gateways | gateways.snapshot | gateways.delta | Membership / Gateway |
| publication | publication.request | publication.status | Device / Membership |
| capability activation | capability_activation.snapshot | capability_activation.revoke | Membership / Gateway |
| edge ingress | edge_ingress.snapshot | edge_ingress.revoke | Gateway |
| operation | operation.status | - | Client Session |
首版 schema_version=1。新增可选字段保持 1;改变必需语义才产生该 event type 的新 major,不联动其他 stream。
所有事件信封使用:
type 枚举为 device、membership、gateway、client_session。事件必须恰好有一个 target;消费者拒绝目标类型不适用、ID 不属于当前认证身份或 target 与 payload scope 不一致的事件。
Peer 出现在 netmap 只表示有建立加密路径的必要,不等于允许所有流量。peer_path_lease 的完整 claims、路径用途与 Node L3 反欺骗规则见 Data Plane Protocol §4.3;它只授权到指定 key epoch 的加密 carrier,不授权任意 Node packet。runtime_transport 使用 Data Plane Protocol §3.1 的 userspace demux 或 exclusive-listener profile,只承载 ServiceFlow/代理型 RouteFlow,不产生 Node L3 权限;隔离验证失败整轴为 not_ready。Peer 删除或 lease 到期后停止新会话并按 drain policy 清理路径。
NSD 把创作层 selectors 规范化成目标节点可直接执行的规则:
Resource kind 包括 node、service、route、exit、ingress-admin、publication。数据面 projection 只含执行所需 ID,不下发用户邮箱、Group 完整成员或 authoring selector。规则为空表示明确无授权;读取/编译失败不会产生这份空 snapshot。
Node 流量同时通过源端 egress projection 和目标端 ingress projection。Service 在 consumer 与 publisher/NSGW 两端执行同一 service_id 的动作约束。
backend_kind 为 node 或 gateway_egress。Gateway Exit 不是 Service,不得出现在 Service 列表。消费者不接收 backend origin;publisher/NSGW 在自己的目标配置中接收后端。
发给发布 Membership 的同一 stream 使用 role=publisher,每项至少包含 service_id、endpoint_id、publisher audience、local manifest ID/revision/digest、允许的 credential issuer/audience、protocol/port/L7 enforcement、generation、service_projection_digest、input revision、完整 provenance 和有效期。Publisher 不接收 User/Group 目录;收到 role 不匹配的 payload 必须拒绝。
ServiceFlowCredential 不是不透明占位符。其完整 claims、本地验签、建流握手、半关闭、UDP timeout、换代和撤销见 Data Plane Protocol §6。消费者与 publisher 必须绑定同一 generation/digest,且不得 union 两代允许集合。
Endpoint health 枚举 ready、degraded、offline、disabled。Service 没有健康 endpoint 时仍可保留目录项并显示 unavailable;服务读取失败是 projection 级 error,不等于 services=[]。
DNS 和对应 Service/Route snapshot 使用同一 config_revision_group,runtime 只在依赖全部可应用后切换。Custom domain 只发给有权访问 Service 的目标。
发给客户端 Membership 的 payload:
发给 Connector Membership 的 payload 使用同一 stream,但 role=connector,每代至少包含 route_id、generation、digest、input revision、精确 prefixes/domain resolution、protocols/ports、NAT mode、allowed source credential issuers/audiences、not_before/not_after 和完整 provenance。消费者必须拒绝与自身角色不匹配的 payload。
RouteAccessCredential 的签名 claims 至少包括 issuer、organization/network、source membership、route ID、connector audience、generation、route projection digest、grant rule、input revision、kernel version、issued/expires 和 credential ID。Connector 本地验签并同时校验实际目的地;建流不能回查 NSD。
kind 为 subnet、application、exit_cidr。Default Exit 放在 Gateway projection,避免普通 Route 与用户 selection 混淆。runtime 对现有 OS route 做精确 owner 检查;projection 不能要求强制覆盖外部对象。
Connector 可同时保存 current、next 和可选 previous generation,但每代目的地集合独立。security_first 以 activation epoch 切换且到点立即拒绝旧代;bounded_drain 的 previous 不超过 credential TTL。消费者绝不能 union 两代目的地。
发给 Membership 的交互和执行投影:
候选集合错误使用事件/查询 error envelope,不伪装成空 items。no_authorized_candidates 与 temporarily_unavailable 是已读通后的集合状态。
发给 Gateway 的配置按 capability 分开,包含 tenant scope、listener/tunnel/backend、允许 source/resource、limits、secret reference 和 Capability Lease;不包含完整候选或用户目录。
Gateway-target payload 必须带 role=relay|egress|exit|ingress。Relay 使用轮换 opaque session/route ID,不下发稳定 Membership/WG 标识;Egress 复用 Service publisher projection并携带本地 EgressOriginLease;Exit 带 scope digest、tunnel generation 和 ExitTunnelLease;Ingress 带 PublicApplication/Binding revision 和 backend Service credential。各角色收到不适用字段或 capability 时拒绝整份候选配置,不从其它 role 猜默认值。
上行命令共享 idempotency/revision 信封:
| Command | Producer | 关键 payload |
|---|---|---|
node.endpoint.report | ns | membership、endpoint、network type、TTL |
node.posture.report | ns/MDM | signed claims、observed time |
service.declare | ns | local manifest revision、protocol、backend metadata、health |
service.endpoint.health | ns/NSGW | endpoint、state、reason、TTL |
route.advertise | ns | CIDR/domain、kind、local authorization |
gateway.capabilities.report | NSGW | capability/profile、region、capacity、health |
gateway.exit.selection | ns | gateway ID、scope、expected config revision |
projection.ack | ns/NSGW | stream、epoch/revision、applied/rejected |
node.key.prepare | ns | membership、current/next key epoch、公钥、proof |
node.key.activate.ack | ns | membership、key epoch、prepared/activated/rejected |
声明只报告本机事实,不自授予可见性。Posture claim 有来源与过期;NSD 不信任普通节点自报“managed”。
Endpoint candidate、authenticated discovery probe、漫游和 Node/WG key epoch 状态机见 Data Plane Protocol §4。上报 endpoint 或 next key 只创建候选事实,不授权 peer,也不要求目标端接受。
本地 API 向 Client 返回:
字段允许新增可选轴。未知 enum/major 必须产生 incompatible,而不是回落到 ready/disabled。
长操作返回 operation_id,Client 订阅:
phase 是可枚举真实阶段,不能由计时器伪造百分比。终态 succeeded/failed/canceled 持久化有限时间,重复查询返回同一结果。
Delta 使用 typed operations:upsert/delete + object ID + object revision。数组整体顺序不是语义;消费者按 ID 构建候选集合,完成全量引用校验后原子替换。Delete 不允许删除本 stream 不拥有的对象。
对规则、DNS/Route 协调组和 Gateway safety config,服务端可直接发送 snapshot,避免复杂 delta 产生半状态。首版优先正确快照,达到实测规模瓶颈后再为具体 stream 引入 delta。
ns-shared-next 建 ID、envelope、target、error 和 canonical fixtures;