Skip to content

fleet 供给收权:节点密钥与端口的单一口径

节点 WireGuard 密钥与 WireGuard 端口段位都是 control-server 的一等数据,所有写入渠道走同一个服务。本文说明这两条单一口径的形状、对等命名规范,以及存量收编用的运维端点。


节点密钥

单一事实源是 node_wireguard_keysnode_id → 私钥加派生公钥),由 control-server 保管。

  • 节点无钥时收养既有接口在用的字面钥,全新节点才生成一对。绝不凭空生成一把顶替正在跑的身份——那正是密钥分叉的形状。
  • 不用任何引用魔法。 node://secret:// 之类的 URI 形态一律废弃,管理面校验直接 422。spec 与 DesiredState 里存的都是密钥字面串
  • 单源纪律由 materializer 对每个 WG 接口无条件注入节点密钥实现——这与 link-local 注入同构,都是「把副本变派生」。spec 里存什么都会被节点密钥覆盖,agent 侧协议零改动。
  • Node.wireguard_public_key 是本表公钥的只读投影,写路径只有 services/node_keys。托管上报的一致性闸对照的就是这个投影:公钥不符即 409 并回滚事务。

轮换set_node_key 加全接口重物化。内部对端的公钥由 materializer 现取现填、自动跟随;外部对端需要人工通知。

agent 侧只做一致性上报,不生成也不保管密钥:从 DesiredState 取密钥、推导公钥上报,控制面比对不符即 409 并中止该轮 reconcile。状态目录下已无密钥文件。

⚠️ 私钥以 base64 明文列存在 node_wireguard_keys 里。 控制面数据库泄露等于全 fleet 隧道密钥泄露——这是密钥收权换来的代价,库备份、公网发布的 PostgreSQL 端口与读权限凭据都要按此定级。

可选的离线托管([server] recovery_public_key)在此之上再存一份加密副本,生产当前未配置。见 密钥托管与恢复


端口

段位入库 port_pools

scope段位用途
external51800–51830对外对等,含自动对等
internal52800–52820节点间内部隧道

表空时自播种,保证任何建库路径都能落到定案值。

统一分配 services/port_allocator:全部渠道——自动对等落成、管理面手工、迁移工具——共用同一套 allocatevalidate_port

占用集是节点的全部 WG 接口,含禁用的。禁用是暂停不是释放:一条禁用会话的端口若被重新分配出去,恢复它就会撞端口。调用方持 Node 行锁,与 materialize 串行化。

发布段派生:节点 runtime 的 wireguard_port_range(external)与 wireguard_internal_port_range(internal)由 materializer 从 port_pools 注入。schema 的 normalize 钩子对两段做并集校验,并各注入一条 UDP 发布。

base_template 里的显式段位是过渡门控——存量端口迁完前优先生效;迁移清除后端口池成为唯一口径。

端口段位收窄有一个直接的运维收益:docker-proxy 为每个发布端口起一个进程,段位从上百个收到几十个之后,这些进程的常驻内存随之显著下降。


对等命名规范

单一事实源是 services/peer_naming

资源规则
Peering<slug>_<asn>_<node>exploro_4242421771_hkg1
WG 接口as<asn>(≤15 字符)as4242421771
BGP 会话<slug>_<asn>_<node>_<af>afv6_v4(MP-BGP)/ v4 / v6exploro_4242421771_hkg1_v6_v4

slug 是对端短名,取值按优先级:

  1. 既有 BGP 会话名的首段——保留运维与对端沟通时惯用的名字,规范化不改口;
  2. 既有 Peering 名;
  3. registry as-name 归一(NEXUS-ASnexus);
  4. 兜底 as<asn>

全程只用 [a-z0-9_],对 BIRD 标识符与 Linux 接口名都安全。

观测侧不按名字反推。 live、metrics、routes 一律经 peering_id 关联查该对等的实际会话名——名字里含 slug 与节点,无法从 ASN 猜出来。


可用连接数与开关

  • 节点可用连接数等于外部端口池剩余量——端口才是真资源。autopeering_node_policies.max_sessions可选的额外上限,NULL 表示只受端口池约束。用户面同时给出 free_ports 与取二者较小值的 remaining
  • 是否接受自动对等是节点级、存库的开关autopeering_node_policies.enabled)。前端用 PATCH /admin/autopeering/nodes/{node_id}{"enabled": false} 即可切换——部分更新,不必回填 endpoint_host 与展示元数据;PUT 仍是全量替换语义。

关闭后该节点从用户面清单消失、新提交 404已落成的对等不受影响——停的是「接纳新对等」。拆除既有对等走标准 Peering 管理 API。

运维视角见 自动对等运维


存量收编端点

三个管理面端点,幂等、支持 dry_run。它们是为把历史形态收编到上述口径而存在的,在已收编的 fleet 上跑是 no-op,也可用于核对当前状态。

执行顺序

  1. POST /admin/nodes/{id}/peerings/backfill——先修 orphan 关联。孤儿接口与会话没有 Peering 行,后续两步按聚合根遍历就会漏掉它们。

  2. POST /admin/fleet/migrate-keys——每节点取一把典范钥(外部对等在用的那把,统一到它意味着外部对端零配合)入库;全部接口 spec 归一为该字面串,历史写入的引用形态也在此归一。

    per-link 分叉的接口(早期「每条链路独立 keypair」的产物)随之换成节点密钥,其对端的 peer 公钥同事务跟随改写。内部链路两端都受管,换钥只有一次重握手的瞬断。

  3. POST /admin/fleet/normalize-peer-names——存量对等命名规范化,顺带清理空壳 Peering。改名会重建对应的 BIRD protocol 与 WG 接口,一次瞬断。route collector 的喂送会话跳过。

  4. POST /admin/fleet/migrate-internal-ports——内部链路的 listen_port 迁入 internal 池,引用旧端口的对端 endpoint 同事务改写。节点全部端口都能被池解释之后,清除 base_template 里的过渡段位。每条链路的两端在同一事务与同一广播轮内保持一致。

先跑 dry_run 审阅 details,再实跑。


部署顺序(硬约束)

  1. agent 先行——必须是认识 wireguard_internal_port_range 的版本。旧 agent 的 StrictModel 会拒收携带新 runtime 字段的 DesiredState。

    控制面代码本身可以先上:新字段的注入被 base_template 的过渡段位门控,迁移前不会产出。

  2. 控制面部署——新表由迁移链建出。

  3. 依序跑收编端点——迁移会触发全 fleet 容器重建(发布段变化进 config_hash),内部 mesh 有一次滚动重握手,收敛与自愈回路兜底。

顺序的普遍规则见 锁步契约