Files
MoShiro/docs/security/enrollment.md
T
justme a9bf849697
ci/woodpecker/push/web-build Pipeline was successful
ci/woodpecker/push/verify Pipeline was successful
ci/woodpecker/push/e2e Pipeline was successful
docs: rewrite README and AGENTS.md etc..
2026-10-21 06:28:19 +08:00

8.4 KiB
Raw Blame History

MoShiro 的注册与身份

通用的注册、身份、认证机制由 Fleet 提供,见 Fleet 文档 的「身份」「注册」两节。本文只描述 MoShiro 在 Fleet 之上的约定:Agent 注册后如何自动接入测量、Probe 的身份以及 Agent 列表同步,以及节点本地的硬上限。

1. 身份一览

主体 凭据 生成方 Backend 保存
Agent Fleet 节点身份(ECDSA P-256)+ 面向 Probe 的 TLS 证书 fleet-enroll 公钥、SPKI 指纹
Probe Fleet 节点身份(连面板)+ 另一把独立的密钥(连 Agent,放在 tls.pfx) fleet-enroll,和 Agent 一样用加入令牌(role=probe);可以有多个 Probe,每个独立吊销 两把公钥
面板用户 账号 + 密码(PBKDF2-SHA256) 面板 密码哈希
API 令牌 随机高熵令牌,带一组能力(见 access.md) 面板 SHA-256
发布签名 ECDSA P-256 发布密钥 CI(Woodpecker 密钥 release_signing_key)或离线环境 只在宿主机的更新器里配置公钥(Backend 和脚本装的节点用 moshiro-update,见 deployment.md;Quadlet 节点不验证清单,只是退出后重新拉镜像;纯二进制节点的更新见路线图),面板不保存私钥;登记清单时面板用公钥验签,宿主机的更新器之后再验一次

2. Agent 接入流程

管理员 ── 创建加入令牌 {标签, max_uses, 过期时间, auto_approve, controllers} ──> 面板(Fleet.Server.Enrollment)
       <── 一段 Quadlet 安装命令(默认,Podman 系;Docker 另有 compose 命令):把面板地址、一次性码、创世指纹和属主写进本地 env,下载面板提供的静态
           Quadlet 单元并核对 SHA-256,再启动用户服务;命令里只有公开的值(见 access.md 第 10 节)。
           备用:一行安装脚本(先核对脚本哈希再执行),参数走环境变量

两条路径做的事一样:容器的入口脚本,或 install.sh / install.ps1(packaging/install/,嵌入 Backend,静态文件,不替换任何值):
  ├─ 向面板取 CI 签名的发布清单,用脚本里内置的发布公钥验签,按清单里的 digest 拉镜像
  ├─ 用 Docker 或 Podman 起容器,身份和配置存在命名卷里;节点名字默认取主机名
  └─ 容器入口用代码注册:fleet-enroll --server … --join jt_… --genesis … --controllers …
        ├─ 先验操作员集合链(创世指纹、属主在集合里),验不过就不交出密钥
        ├─ 注册元数据(MoShiro 定义):{ probe_tcp_port, probe_quic_ports, public_host?, kinds[] }
        └─ 写 trust.json(创世指纹、链、属主)和 agent.json(本地硬上限)
下载压缩包的二进制安装(packaging/install.sh)做同样的注册,另外创建系统用户 moshiro、启用 moshiro-agent.service,见 deployment.md。

面板收到 OnEnrolled(MoShiro 挂钩)
  ├─ public_host 未提供时,来源 IP 是公网地址才用;之后 hello 里 Agent 上报本机公网地址(`addresses`),面板自动填 public_host 和 ipv6_host,手填的优先
  ├─ 按“线路任务模板”为该 Agent 计算有效任务集(TaskSet)
  └─ 面板把新的 Agent 列表作为期望状态推给所有 Probe → Probe 自动连接新 Agent
     从安装到开始出数据,全程不需要手工配置

名称冲突、审批、接管、禁用等行为都采用 Fleet 的默认规则。

3. Probe 身份与 Agent 列表同步

Probe 直接连面板(Fleet 长连接,身份是下面生成的密钥),Agent 列表由面板作为期望状态下发;测量数据仍然只走 Probe → Agent。

面板:POST /api/admin/join-tokens {role: "probe"}  → 一次性加入令牌 jt_…
Probe 机器:fleet-enroll --server … --join jt_… --name home --identity-dir …
  ├─ 本地生成两把密钥:node.key(连面板认证)和 tls.pfx 里的密钥(连 Agent 对端认证);面板从不接触私钥
  ├─ 注册请求带两把公钥(pubkey、tls_pubkey)和持有证明;面板据此写 probes 记录,ID 前缀 prb_
  └─ 吊销 /revoke 会让面板和所有 Agent 断开它;换密钥 = 吊销后重新注册(没有 rotate)
probe.json:{ fleet: { server, identity_dir }, restart_at?, limits? }   ← limits 是本地硬上限,面板无法修改;在路由器上建议调低

Probe 启动
  ├─ 连接 server:Fleet 长连接(用 probe_id 和私钥认证),fleet.hello 带上系统、架构和构建信息
  ├─ 面板推送期望状态 probe_agents:{ version, agents: [ {agent_id, host, tcp_port, quic_ports, public_key}... ] }
  ├─ 调和:新增的 Agent → 建立点对点会话(peer 用途签名);被移除或禁用的 → 断开
  └─ 之后列表的任何变化(Agent 注册、禁用、地址或证书变化),面板都重新推送同一种期望状态;
     Probe 用 Fleet.Hosting.ConfigStore 把最新列表写回 agents.json(这是配置,不是测量数据;面板暂时连不上时,Probe 靠它继续测量)
  • 每个 Agent 通过自己的期望状态(TaskSet.peers)获得 Probe 的公钥,用来验证点对点会话的签名。
  • 哪些 Probe 连哪些 Agent 由面板决定,始终是 Probe 主动拨出:设置 fleet.auto_link(默认开)打开时,所有未吊销的 Probe 和所有 Agent 两两连;关闭时只连手动选中的。每一对还可以在管理端 Probe 页的「线路」矩阵里手动强制开或关(PUT /api/admin/links/{probe_id}/{agent_id}),手动设置优先于自动连接。结果同时用在 Probe 的 Agent 列表、Agent 的 peers 和线路目录(关掉的线路从总览里消失,历史数据还在)。
  • 吊销 Probe:POST /api/admin/probes/{id}/revoke,旧公钥立即从所有 Agent 的期望状态中移除,旧会话随之断开;要继续用就重新注册。

4. Agent 本地配置(/etc/moshiro/agent.json,面板无法修改)

{
  "fleet": { "server": "https://panel.example.com", "identity_dir": "/etc/moshiro" },
  "listen": { "control_port": 7443, "quic_ports": [7443], "tcp_ports": [7444] },
  "limits": {
    "max_total_mbps": 200,
    "max_total_pps": 20000,
    "allowed_target_cidrs": [],
    "max_concurrent_tests": 1
  },
  "fleet_policy": { "allow_methods": ["moshiro.test.run", "moshiro.test.cancel"] }
}
  • limits 是本地硬上限:期望任务集超出这些范围时,调和器拒绝执行,并在 rejected[] 中给出原因。
  • allowed_target_cidrs 默认为空,即不允许执行任何目标任务;需要时由节点所有者在本机显式开启。
  • listen 默认不包含 443。要用 443 测量,需要在本机把它加入 quic_ports 或 tcp_ports(端口不能被真实服务占用),见 measurement.md 第 8 节。
  • fleet_policy.allow_methods 在 Fleet 默认值的基础上进一步收窄。

5. 相关 API

方法 路径 说明
POST /api/agent/v1/enroll 由 MapFleetEnrollment 提供
GET /api/agent/v1/rpc 由 MapFleetLink 提供(升级为 WebSocket)
GET/POST/DELETE /api/admin/join-tokens 管理加入令牌
POST /api/admin/agents/{id}/approve、/disable、/enable、/takeover 审批与启停
GET/PATCH/DELETE /api/admin/probes、/probes/{id} Probe 的列表、改名、删除
POST /api/admin/probes/{id}/revoke 吊销(换密钥就是吊销之后重新注册,没有轮换)
POST /api/admin/agents/{id}/probes/{probe_id}/disconnect 让 Agent 断开某个 Probe
GET /install、/install.ps1 静态安装脚本(Agent 和 Probe 共用,不带参数,哈希在一个版本内固定)
GET /install/manifest?code=…、/install/manifest.sig?code=… 凭一次性代码取该角色已签名的发布清单(原样,一个字节也不改)

Agent 的本地配置:主机状态上报

agent.json 和 probe.json 的 reporting 段(面板无法修改):

{ "reporting": { "host_stats": true, "host_interval_s": 2 } }

host_stats 为 true(默认)时,Agent 和 Probe 每隔 host_interval_s 秒用 moshiro.host 上报一份主机资源占用的汇总数字(CPU、内存、根分区、网卡累计流量与网速、运行时长;没有型号、主机名、IP);设为 false 就一个字也不上报。