跳转到内容

总体架构

本页给出 NSIO 三组件的”角色 + 互联”总体视图:每个组件在哪个平面、对外暴露什么、谁向谁发起连接、典型时序如何展开、各组件失败时影响范围。组件内部模块见对应组件目录的 architecture.md。本页描述已实现形态,规划项单独标注。

本页描述 NS 的账户模式:NSD 是唯一权威,NS 与 NSGW 消费它的签名投影。NS 的 Quick 模式(ns quick)不经过 NSD:设备之间凭一次性短码两两配对,NSGW 的 nsgw-quick-relay 提供短码会合与密文转发,见 Quick 模式。两种模式在同一台设备上互斥。

平面职责谁在这个平面是否承载业务流量
管理面管理员 / 成员编辑、IdP 对接、审计、SaaS 平台运营NSD(内嵌管理台 / Admin API / Platform API / nsdctl)否
控制面身份签发、Access Grant 编译、配置投影与签名分发NSD(唯一来源);NS / NSGW(订阅者 + 上报者)否
数据面业务流量转发与 ACL 终决NS(端点:发布端终决、访问端预检);NSGW(中继 / 终结 / 公网边缘 / Egress / Exit)是

NS 的数据面将由独立组件 nsplane提供:WireGuard 引擎、传输与路径、过滤链、netstack 与 TUN;账户模式(2026-10-03)与 Quick 模式(2026-10-04)都已只运行在 nsplane 引擎上(tag v0.14.0);自 2026-10-12 起 ns 把每个已连接的 NSD Network 与 Quick 作为同一引擎上的平等 membership 同时运行(NS)。nsplane 不参与控制面,也不依赖 NS / NSD / NSGW 的任何协议。

NSD 是唯一有状态强一致组件,但永不承载业务流量;NS 与 NSGW 都是控制面订阅者,同时是数据面参与者。同一台 NS 在一条链路上是访问端(consumer),在另一条链路上可以是发布端(provider);报文字段中的 nsc / nsn 指的就是这两端。

横向是发起方,纵向是接受方;空格表示无直接连接。

↓ 接受 \ 发起 →NSDNSGWNS浏览器 / 标准工具
NSD—发现 + 注册 + 心跳 + gateway.report / gateway.services_report / gateway.usage_report + 配置流 + realm 快照轮询发现 + 注册 + 心跳 + services.report + 配置流 + pair transport 快照 + Exit 选择管理台 HTTPS / 设备授权页
NSGW——WireGuard UDP(relay :51821 / terminate :51820)、WSS(/client、/wss-relay、/relay、/exit-wss/v1)HTTPS 443 与 NSD 分配的 L4 端口(Envoy)
NS(发布端)—WireGuard(terminate 第二段)、WSS 缝合WireGuard(direct,或经 NSGW 中继的端到端会话)本机 / LAN 内进程(通过发布的 Service / 子网映射)
NS(访问端)———本机进程:tun 路由、dns-vip 环回 VIP、proxy 本地代理

三条不变量:

  • 控制面只收不拨:NSD 不主动连接任何节点;NS 与 NSGW 都主动向 NSD 拨号(注册、心跳、配置流、上报)。NSGW 同样不主动连接节点,只等节点来接。
  • 数据面各段独立握手:direct / wg-relay 下 NS ↔ NS 端到端一段握手;terminate 下 NS ↔ NSGW 与 NSGW ↔ NS 是两段独立握手;wss-relay 下两端各自向 NSGW 出站,NSGW 只缝合密文。
  • 节点身份与 WG 私钥只留在本地:NSD 从不接收它们,WgConfig 也没有 private_key 字段。这不排除 NSD 自有的签名密钥,以及集中管理的公网边缘证书密钥。

NSIO 拓扑

  • NSD : NSGW : NS = M : N : X。M 通常很少(SaaS 云端 NSD 与客户私有 NSD 并存),N 按 PoP / region 扩展,X 由租户规模决定。
  • 单个 NSD 可以单实例或多实例部署:单实例使用 SQLite;多实例 active-active 时在负载均衡后运行多个实例,共用 PostgreSQL,并经 Redis 共享配置推送、认证 nonce、限流、防重放与二次验证状态。对 NS 与 NSGW 而言仍是同一个 HTTPS origin。
  • 一台 NS 本地可保存多个 NSD,但任一时刻只有一个 active(ns nsd list / switch / remove)。每个 NSD 拥有独立的 Device identity、Account、Space Profile、配置、数据与信任命名空间;不再有”多 NSD 并行、节点侧合并”的形态,切换 NSD 等价于切换整套运行时上下文。
  • 同一 NSD 下可有多个 Space(Network)Profile,ns space switch 提交新的 active Profile;只有 active NSD 中 manifest 指向的 active Profile 参与控制面与数据面。
  • NSGW 之间互不感知:中继配对与网关选择由 NSD 投影(relay placement),NS 侧只在投影范围内做阶梯降级与同网关恢复。
  • Quick 模式不在这张拓扑里:Quick 节点之间直接连接,只依赖独立部署的 nsgw-quick-relay(可组成最多 16 个成员的 relay 区域)做短码会合与密文转发,不连接 NSD,也不使用账户模式的 NSGW 网关。
  • 公网网关池:平台运营方用 platform enrollment token 登记 NSGW,健康(近期签名上报、非 drain、有 WG 端点与公钥)的池成员才会被投影给各 realm;一台 NSGW 可同时服务多个 realm(gateway.realm_config_snapshot)。

4. 控制面:发现 → 登记 → 认证 → 订阅 → 上报

Section titled “4. 控制面:发现 → 登记 → 认证 → 订阅 → 上报”

NSIO 启动与控制面

节点只配置一个 NSD HTTPS origin。GET /api/v1/info 经系统 WebPKI 校验后返回 control_trust.v1:控制端点顺序(SSE / Noise / QUIC)、Noise X25519 公钥、QUIC SPKI SHA-256 current/next pin、Envelope 签名键 RFC 7638 thumbprint current/next。HTTP、跨源跳转、未知版本、非法 trust 一律 fail-closed;不再有手工 pin 或 TOFU。

传输NSD 侧用途
SSE over HTTPS(默认)Caddy 终结 TLS → nsd:8080常规部署
Noise IK over TCP(:4001)nsd-noise-proxy sidecar 解帧 → 明文 HTTP无 SNI、无 TLS 指纹
QUIC over UDP(:4002)nsd-quic-proxy sidecar,自签证书按 SPKI pin 认证,禁用 0-RTTUDP 友好,HTTPS 受干扰环境

NS 默认 auto:优先 SSE,同一传输连续可重试失败后冷却并切换到下一候选;显式 sse / noise / quic 保持强制与 fail-closed。NSGW 按发现顺序逐个探测并用签名探测验证 Envelope signer。三种外壳共用同一份事件解析器。

主体首次登记运行期认证
NSns up --server <URL>:浏览器 / 设备授权流,由已登录 Account 批准(批准绑定精确设备公钥);一次性 invite 也可走同一路径。租户 auth key 已不再接受Envelope v1(Ed25519 签名 + nonce + ±60 s 时钟窗);短期机器 JWT(默认 30 min)通过 token_refresh 事件滚动,WSS 401 触发运行态重认证
NSGWplatform enrollment token(仅限首次 gateway 登记,限次、可过期、可撤销)同上;WSS 相关 leg token 由 NSD 签发、aud=nsgw-wss

机器身份是两把本地生成的密钥:Ed25519 身份键(签 Envelope)与 X25519 对等键(WireGuard)。Device 身份由身份公钥派生并记录在 Organization 范围;Node 是 Network 范围内的 (Network, Device, Account) 数据面 Profile。

订阅建立后 NSD 按订阅者种类 + 已协商能力推送事件子集;每条事件都带 Ed25519 签名。上报是策略合成的反向链路:

上报方向触发的合成
services.report(源自 services.toml)NS → NSDService 目录、路由、Short DNS、services_ack 三态回执
ns subnet add / bindNS → NSDSubnet 权威、active / standby 选择、SubnetRouteConfig
pair transport 快照(60 s 心跳携带)NS → NSDpair 级 relay transport 权威(同网关 WSS override)
Exit 选择 / 撤销NS → NSDGatewayExitCandidates、GatewayExitNftConfig、capture route
gateway.report(30 s)NSGW → NSD网关健康、端点、能力、证书状态、版本
gateway.services_report(源自 gateway_services.toml)NSGW → NSDGateway Egress / Exit 的本地 floor
gateway.usage_reportNSGW → NSD计量账本、按网关的上报新鲜度
心跳中的 gateway_rtt(声明 relay_gateway_rtt.v1)NS → NSD分档的网关 RTT,供中继放置(§4.5)
wg_relay.register_sourceNS → NSGWrelay 目标的 NAT 学习源(90 s TTL)

NSIO 配置下发

配置流的每个事件是 {"type": <tag>, ...} 形式的 JSON,type 为下表的线上标签(未带版本后缀的标签是 Rust 变体名的 snake_case)。NS 与 NSGW 各自用一份 ControlMessage 解析:NS 在 ns 仓库 crates/control,NSGW 在 ns-shared 的 control(nsgw 固定 ns-shared-rev);NSGW 把未知标签解成 Unknown 并跳过,不会因为新事件中断整条流。

线上标签NSNSGW说明
wg_config✓✓(条件)peer 表;NS 侧每个 peer 附带 wg_relay / wss_relay / wss_relay_fallback 指令。只有公网入口、Exit、Egress 网关或 realm 快照才带给 NSGW
proxy_config✓—发布端服务的本地代理规则
acl_config✓✓(条件)编译后的 ACL(bindings / groups / hosts / rules),ExplicitEmpty / FetchFailed 三态;NSGW 只在公网入口 / Exit / 快照中收到
services_ack✓—services.report 的 matched / unmatched / rejected 回执
gateway_config✓✓网关拓扑与端点;NS 侧可带中继测量名单 probe_roster
routing_config✓✓(条件)Service → 发布端 Node 地址 / 端口;NSGW 侧供 egress 查找与公网路由
dns_config✓快照管理员显式域名映射
gateway_wg_relay / gateway_wss_relay✓✓中继配对表(realm 内按 pair 投影)。NS 取其中的客户端 WG 公钥集合(client_keys,缺省时由配对行推出),对经中继到达的报文按解密 peer 公钥判定来源;NSGW 据此放行中继。gateway_wg_relay 可带测量探测集合 probe_set
peer_candidates✓—direct P2P 候选,按 epoch 合并
node_l3_config.v1✓—目标绑定的 Node L3 策略快照(node_l3_acl.v1)
subnet_route_config.v1 / subnet_l3_route_config.v1 / subnet_lan_dns_config.v1✓—子网映射、L3 所有权、LAN DNS(能力门控)
gateway_exit_candidates.v1✓—身份授权的 Exit 候选
gateway_exit_config.v1—快照Exit 的 nft 配对表
gateway_egress_wg_config.v1—快照Egress 的 WG client leg
gateway_http_config.v1 / gateway_l4_map.v1 / gateway_auth_config.v1 / gateway_certificate_bundle.v1 / gateway_client_ca_bundle.v1—✓(能力门控)公网入口:路由、L4 端口、Edge Auth、证书、客户端 CA
policy_version✓✓策略版本号,声明 policy_version.v1 才下发;心跳中回显
token_refresh✓✓滚动机器 JWT;NS 侧另带 wss_token、wss_relay_token、exit_wss_token(缺省即撤销 Exit 承载授权)
ca_bundle_update✓—realm 的 CA 信任锚,声明 ca_bundle_update.v1 才下发
gateway_drain✓—网关维护前的排空通知(gateway_id、reason、deadline_secs),只发给 NS
ping✓✓流保活
Short DNS v2 快照✓—独立 Envelope API,能力协商后才投影

“快照”表示 NSGW 以 gateway.realm_config_snapshot(每 20 s 轮询,每个 served realm 九类 body:wg_config、acl_config、routing_config、dns_config、gateway_config、gateway_egress_wg_config.v1、gateway_exit_config.v1、gateway_wg_relay、gateway_wss_relay)为准;流上收到的 gateway_wg_relay、gateway_exit_config.v1、gateway_egress_wg_config.v1 只记日志。快照超过 24 h 未刷新时标为 degraded,默认继续使用上次的有效配置。NS 还能解析 posture_config、pong,但 NSD 当前不发送。

中继网关的选择由 NSD 决定,测量数据来自节点:

  1. 名单:声明 relay_gateway_rtt.v1 的 NS 收到 gateway_config.probe_roster,最多四个可承担中继且正在接纳的网关(先是它当前的 wg-relay 载体,再按 realm 顺序补足,最后一个名额每个 UTC 日轮换)。对应网关收到 gateway_wg_relay.probe_set。
  2. 测量:NS 在每 20 s 的反射轮次中,同时用各自的 nonce 探测当前锚点与名单中的每个网关;名单回复只更新 RTT 统计,不改变反射候选。NSGW 对名单中的机器应答纯测量探测,既不绑定 pair 源也不刷新中继路由;反射请求在验签前按源 IP 限速。
  3. 上报:平滑后的 RTT 映射为 lt30 / lt100 / ge100 三档(边界有 20 % 滞回),连续三轮无回复记为 unreachable。NSD 确认 gateway_rtt.v1 后,NS 在档位变化时、且至少每 5 分钟一次,在心跳中携带完整列表。
  4. 放置:NSD 把结果写入按 realm 隔离的 machine_gateway_rtt(超过 15 分钟视为未知)。realm 打开 relay_placement_rtt 后,pair 放置按”可达优先、档位成本之和、再 HRW”排序;开关默认关闭,关闭时沿用 realm 级排序与主网关回退。
段用途分配者
100.64.0.0/11 + 100.98.0.0 – 100.126.255.255Node 地址,跨整个部署全局唯一,租约持久化NSD
100.96.0.0/15Service VIP(访问端本地铸造,NSD 从不分配)NS 访问端
100.127.0.0/16网关地址NSD
127.127.0.0/16dns-vip 模式的环回 VIPNS 访问端
fd<T><R>::/48子网映射 ULA::1::/64 为 IPv4 LAN 映射、:2::/64 为访问端回程身份由 Network token + Realm 派生

ns 分支 refactor/nsplane 自 2026-10-12 起不再消费 NSD 分配的 Node IPv4:Node 以身份键投影,本机 IPv4 只是 ns 分配的别名(账户模式 §2.3)。上表的 Node 地址段在 NSD 的 M6 配套完成前仍是 NSD 与 nsgw 的现状,见迁移计划。

NSIO 数据流

模式路径NSGW 角色NSGW 是否见明文何时使用
directNS ↔ NS(P2P,NSGW relay socket 提供 NSGWP2P1 反射探测)不在路径上—只在已有经认证的 WG 会话之后竞争,不做冷启动
wg-relayNS ↔ NSGW :51821 ↔ NS(端到端 WG)mac1 分流 + receiver-index 转发,不解密✗默认首选;NAT 阻断直连但 UDP 可达
wss-relayNS ↔ WSS ↔ NSGW ↔ WSS ↔ NS(端到端 WG 密文装在 WSS 里)两条已认证出站 leg 的不透明缝合✗UDP 被阻断,或 wg-relay pair 连续两个窗口无握手 / RX 证据时的同网关降级
terminateNS ↔ WSS /client ↔ NSGW ↔ WG / WSS ↔ NS终结访问端 leg、进程内判 ACL、重新发起发布端 leg✓节点登记时声明 --gateway-terminate 能力后由 NSD 选择
exitNS(默认路由 / CIDR 捕获)↔ WG 或 /exit-wss/v1 ↔ NSGW → 公网nft SNAT,per-pairing,fail-closed✓ns exit set 选择网关
egressNS → NSGW → 指定目标 TCP / UDPNSGW 终结 + 完整 ACL + 本地 floor✓Gateway Egress 资源
https / L4公网客户端 → Envoy :443 / L4 端口 → NSGW 内部 listener → 发布端 NSTLS 终结、Edge Auth、源 IP 准入、入口 ACL✓不依赖 NS 的公网访问

链路阶梯由 NS 在每个 pair 上执行:登记时声明 --transport auto|wg|wss(能力集);NSD 投影 pair 指令;NS 优先 wg-relay / direct,检测到真实出站需求且连续两个窗口无健康证据时先向原 relay 端点强制握手验证,再降级到同一 gateway_id 的 WSS;健康证据可取消 pending 转换;同一 pair 两端按 machine id 稳定生成互补的 client / relay leg。

NS 数据路径

  • 访问端 tun 模式:本机进程直接连 Node 地址或 Service VIP,内核路由送入 TUN;dns-vip 模式:环回 VIP listener 抓取 TCP;proxy 模式:SOCKS5 / HTTP CONNECT。
  • 访问端做 Service 预检 ACL(fail-closed,以来源 NSD 为键);发布端做 Service PEP 终决 + services.toml 兜底,以及 Node L3 ACL(同 Account 全通、跨 Account 需显式 Grant、返回流有状态)。

HTTPS 公网入口路径

Envoy 在 host network 上终结 :443(filesystem SDS 证书、可选客户端 mTLS),过滤链顺序固定:源 IP RBAC → jwt_authn → ext_authz(NSGW 内置验证器:OIDC RP / API key / 签名 URL / mTLS / Basic)→ router。NSGW 注入 x-ns-external-subject(s) / x-ns-external-idp 后,由路由所属 realm 的 ACL 桶对派生的 external: 主体终决,再经内部 listener 转发到发布端 Node。

对象归属说明
Account部署级人类身份,外部 IdP 按精确 (issuer, subject) 绑定
Organization部署级商业主体(SaaS 中一个 org 对应一个 realm)
Network(Space)Organization技术隔离空间 = realm;成员切换 Account + Organization + Network 三元组
DeviceOrganization由机器 Ed25519 公钥派生的安装身份,不带覆盖网地址
NodeNetwork(Network, Device, Account) 数据面 Profile:Node ID / Node IP / Node DNS 名
ServiceNodeservices.toml 声明并上报的稳定发布项
SubnetNetwork持久 32 位 Subnet ID,多网关 active / standby
Gateway平台 / 租户NSGW 机器;平台公网池成员或租户自有
ConsumerrealmEdge Auth 的外部调用者,external:consumer:<realm>:<ref>

NSD 把授权建模为一条逻辑 Access Grant(一个 ID、修订、审批、审计、启用态;主体集合 × 资源集合,集合内 any_of)。资源族:私有 Service、Node、Subnet、公网应用、Gateway Egress、Internet Exit(legacy:Site、NetworkSegment)。主体:user / group / machine / all,以及 Edge Auth 的 consumer / group。

  • 系统级同 Account Grant:每个 Network 内置一条关系型 Grant(source.account == target.owner_account),授权同 Account 的 Node 之间全双向 L3 与私有 Service。
  • 跨 Account 默认拒绝:只有当两端都证明已安装精确 enforced 快照后,跨 Account pair 才可用;Service Grant 只开选定 listener,Node Grant 开目标 Node 的指定流量并覆盖其 Service listener,Subnet Grant 只开被路由子网,Exit / Egress 从不授权网关主机本身。
  • 个人网络 personal_auto:已批准映射自动互联;policy_required 网络必须显式 Grant。

NSD 把身份与授权编译为自包含的 acl_config 快照(bindings 连接 → 主体、groups、hosts、rules)并随签名配置流下发;执行点本地求值,从不回调 NSD。未被任何规则引用的机器不会出现在 bindings,因此无法解析为主体,天然 fail-closed。

执行点判什么失败语义
NS 访问端Service 流预检(按来源 NSD 的 ACL 引擎)无引擎即拒;ExplicitEmpty 立即拒;FetchFailed 保留 last-known-good
NS 发布端Service PEP 终决 + services.toml floor;Node L3(node_l3_acl.v1);Subnet 策略在 IPv6→IPv4 转换前fail-closed
NSGW terminate / 公网入口 / Egress / Exit用户 / 外部主体 ACLfail-closed;ACL 抓取失败超过 600 s 转为全拒
NSGW wg-relay / wss-relay / direct不判用户 ACL,只判 pair 是否在 NSD 投影内不在配对表即丢弃
边界线内线外
节点身份 / WG 私钥NS / NSGW 本地受保护的密钥存储NSD 投影、传输载荷与日志;NSD 自有的签名密钥与公网边缘证书密钥另有存储 / 备份规则
业务明文发布端 NS;terminate / 公网入口 / Egress / Exit 下的 NSGWrelay 模式下的 NSGW;NSD
用户级 ACL 终决发布端 NS(NsnBacked 路径);NSGW(terminate 入口、公网入口、Egress、Exit)NSD(只编译不判)
能力声明NS services.toml / ns subnet;NSGW gateway_services.tomlNSD(只能裁剪,不能凭空生成)
多 realm 隔离NSGW 每个 served realm 独立配置桶,永不合并—
故障业务连接控制变更新节点接入
NSD 整体不可达既有 WG 会话继续;机器 JWT 过期后新的 WSS leg / Exit 承载无法认证不能下发新策略不能登记
多实例 NSD 中的一个实例故障不受影响其余实例继续服务;连在该实例上的订阅者重连到其他实例不受影响
某个 NSGW 不可达该网关上的 relay / terminate / Exit 会话断;NS 按投影切到其他候选,wg-relay pair 可同网关降级到 WSS不影响不影响
某台发布端 NS 不可达其 Service / 子网不可达;子网 standby 网关接管新连接不影响不影响
配置流短暂断链NS / NSGW 保留 last-known-good;显式空策略仍立即生效暂停热更新暂停
NSGW 与 NSD 断链超过 600 sNSGW ACL 门转为全拒(fail-closed)——
Quick relay 不可达已建立的直连继续;经 relay 的 Quick 对端切到 relay 区域的下一个成员或内置列表中的其他 relay,只有单个自定义 relay 时不可达—无法通过该 relay 的短码配对
  • 想看 NSIO 提供的能力与差异点 → 首页
  • 想知道某个组件具体做什么 / 不做什么 → 对应组件目录的 architecture.md
  • 想理解 WireGuard 不解密中继的协议细节 → nsgw/peer-relay-protocol.md
  • 想看正在进行的计划与延期验收项 → 各组件目录的 roadmap.md