feat!: probes generate their own keys and enroll with a join token; node and peer keys are separate [CI]
ci/woodpecker/push/main-amd64-build Pipeline was successful
ci/woodpecker/push/main-amd64-build Pipeline was successful
This commit is contained in:
1 parent
1ff847e45a
commit
a9f562441f
51 files changed
+505
-749
No files matched your search
+3
-4
@@ -37,7 +37,7 @@
|
||||
├─ auth/{login|logout|me}
|
||||
├─ agents agents/{id} agents/{id}/{approve|disable|enable|takeover}
|
||||
├─ join-tokens
|
||||
├─ probes probes/{id} probes/{id}/{rotate|revoke} Probe 身份(后端生成、吊销、删除)
|
||||
├─ probes probes/{id} probes/{id}/revoke Probe(用 probe 角色的加入令牌注册、吊销、删除)
|
||||
├─ links links/{probe_id}/{agent_id} 线路开关:哪些(Probe,Agent)连成线路(自动连接 + 手动选择)
|
||||
├─ tasks tasks/{id} 线路模板、针对单个 Agent 的覆盖、目标任务
|
||||
├─ lines/{line_id}/tests 在某条线路(某个 Probe)上发起按需测试;tests/{id}/cancel
|
||||
@@ -126,11 +126,10 @@
|
||||
| PATCH | `/api/admin/agents/{id}` | `name`、`labels`、`public_host`、`public_visible` |
|
||||
| POST | `/api/admin/agents/{id}/approve` `/disable` `/enable` `/takeover` | 见 [enrollment.md](enrollment.md) |
|
||||
| DELETE | `/api/admin/agents/{id}` | 删除;历史数据按保留策略自然过期 |
|
||||
| GET/POST | `/api/admin/join-tokens` | 创建时返回令牌明文和安装命令(仅此一次) |
|
||||
| GET/POST | `/api/admin/join-tokens` | 创建时返回令牌明文和安装命令(仅此一次);`role` 是 `agent`(默认)或 `probe`,决定用它注册出来的是哪种节点 |
|
||||
| DELETE | `/api/admin/join-tokens/{id}` | 吊销 |
|
||||
| GET/POST | `/api/admin/probes` | 列出所有 Probe(含它现在连着哪些 Agent:版本、远端 IP、起始时间);创建 Probe 身份,返回 `probe.json`(含私钥,仅此一次) |
|
||||
| GET | `/api/admin/probes` | 列出所有 Probe(含它现在连着哪些 Agent:版本、远端 IP、起始时间);Probe 由 `role=probe` 的加入令牌注册,密钥由它自己生成 |
|
||||
| GET/PATCH/DELETE | `/api/admin/probes/{id}` | 详情、改名、删除(历史数据按保留策略自然过期) |
|
||||
| POST | `/api/admin/probes/{id}/rotate` | 换新密钥(id 不变):旧密钥立即失效,所有 Agent 断开它的会话;返回新的 `probe.json`(仅此一次) |
|
||||
| POST | `/api/admin/probes/{id}/revoke` | 吊销:公钥从所有 Agent 的名单里移除,Agent 立即断开它;记录和历史保留 |
|
||||
| POST | `/api/admin/agents/{id}/probes/{probe_id}/disconnect` | 让这个 Agent 断开这个 Probe 的会话(Probe 会重连,除非已吊销);没有会话时返回 409 `probe_offline` |
|
||||
| GET/POST | `/api/admin/tasks` | 列表和创建:line 模板(不带 `agent_id`)、单个 Agent 的覆盖(带 `agent_id` + `base_task_id`)、target 任务 |
|
||||
|
||||
+6
-6
@@ -102,8 +102,8 @@ Linux 上比 Windows 大,是因为 .NET 的加密、压缩、网络本机库
|
||||
# Agent(服务器):注册并启动
|
||||
./install.sh agent --server https://panel.example.com --join <加入令牌> --name hk-1
|
||||
|
||||
# Probe(家宽网络里的机器或 OpenWrt 路由器):先在面板生成身份(POST /api/admin/probes,只能下载一次)
|
||||
./install.sh probe --probe-json ./probe.json
|
||||
# Probe(家宽网络里的机器或 OpenWrt 路由器):用面板里 probe 角色的加入令牌注册,密钥由它自己生成
|
||||
./install.sh probe --server https://panel.example.com --join <加入令牌> --name home-1
|
||||
|
||||
./install.sh uninstall agent|probe [--purge] # --purge 同时删除身份(节点需要重新注册)
|
||||
```
|
||||
@@ -174,7 +174,7 @@ OpenWrt 默认不带 OpenSSL:`opkg install libopenssl3`(较新的快照和 2
|
||||
|
||||
- **Backend 通过隧道暴露**:隧道把一个公网域名转到家宽机器的 `29181`;Backend 监听 `http://0.0.0.0:29181`(只写一个监听地址,同时写 `0.0.0.0` 和 `[::]` 会报地址已被占用),家宽路由器的防火墙不放行这个端口,公网只能经隧道进来。Agent 用 `fleet-enroll --server https://<公网域名>` 注册,之后用 WSS 连回 Backend。
|
||||
- **经隧道注册之后,检查 Agent 的 `public_host`**:Backend 看到的来源地址是隧道的出口,不是 VPS 的地址,要改成 VPS 的真实地址,Probe 才连得上。
|
||||
- **Probe 直连面板**:`probe.json` 里的 `server` 就是面板地址(取自 `MoShiro__PublicUrl`,没配就用创建它时的请求地址),Probe 用它连面板,Agent 列表由面板下发;先注册还是先创建 Probe 都可以。
|
||||
- **Probe 直连面板**:`probe.json` 里的 `fleet.server` 就是面板地址,Probe 用它连面板,Agent 列表由面板下发;密钥由 Probe 注册时自己生成,身份目录(`node.json`、`node.key`、`tls.pfx`)在 `fleet.identity_dir`。
|
||||
- **小 VPS 把 `limits.max_total_mbps` 调低**(试跑时用 100);Agent 常驻约 23 MB,VPS 上原有的服务不受影响,结束后删除 `/opt/…`、停掉进程即可,没有留下任何东西。
|
||||
- 家宽的 IPv6 前缀会在路由器重新拨号(比如停电)后变化,SSH 地址要跟着换;面板走隧道的域名,不受影响。
|
||||
- 本地电脑没有直连 VPS 的路径时,用家宽机器当跳板(`SSH_ASKPASS` + `SSH_ASKPASS_REQUIRE=force`,密码放环境变量,不写进文件)。
|
||||
@@ -212,7 +212,7 @@ OpenWrt 默认不带 OpenSSL:`opkg install libopenssl3`(较新的快照和 2
|
||||
```sh
|
||||
# 首次部署(需要 root;脚本和 packaging/ 里的 systemd/、update/ 放在一起)
|
||||
sudo sh deploy-node.sh agent --image-repo registry.oeo.one/moshiro/moshiro-agent --server https://<backend> --join <token> --name <name>
|
||||
sudo sh deploy-node.sh probe --image-repo registry.oeo.one/moshiro/moshiro-probe --probe-json ./probe.json
|
||||
sudo sh deploy-node.sh probe --image-repo registry.oeo.one/moshiro/moshiro-probe --server https://<backend> --join <probe 令牌> --name <name>
|
||||
# 之后更新节点:不带参数
|
||||
sudo sh deploy-node.sh agent
|
||||
```
|
||||
@@ -230,7 +230,7 @@ JSON
|
||||
podman compose up -d
|
||||
```
|
||||
|
||||
Probe 在 `packaging/compose/probe` 下,将面板下载的身份文件通过标准输入导入 volume:`podman compose run --rm -T --entrypoint /bin/sh probe -c 'umask 077; cat > /etc/moshiro/probe.json' < probe.json`,再 `podman compose up -d`。私钥权限为 600。已有部署迁移时,应把原配置与身份原样复制进 volume,不重新注册或轮换密钥。Docker 与 Podman 各自管理 volume,切换引擎不会自动共享数据。
|
||||
Probe 在 `packaging/compose/probe` 下,和 Agent 一样先用 `fleet-enroll` 注册:`podman compose run --rm --entrypoint /usr/local/bin/fleet-enroll probe --server https://<backend> --join <probe 令牌> --name <name> --identity-dir /etc/moshiro/probe-id`,再写 `probe.json`(`{"fleet":{"server":"https://<backend>","identity_dir":"/etc/moshiro/probe-id"}}`),然后 `podman compose up -d`。已有部署迁移时,应把原配置与身份原样复制进 volume,不重新注册。要换密钥就在面板吊销再重新注册。Docker 与 Podman 各自管理 volume,切换引擎不会自动共享数据。
|
||||
|
||||
纯 Compose 使用 `compose pull && compose up -d` 更新镜像;面板自动更新使用下述 systemd 单元和更新器。Rootless Podman 使用 `moshiro-<role>-rootless.service`,安装到 `~/.config/systemd/user/`,镜像文件为 `~/.config/moshiro/<role>.image`;rootful Podman 使用 `moshiro-<role>-container.service`,Docker 使用 `moshiro-<role>-docker.service`,安装到 `/etc/systemd/system/`,镜像文件为 `/etc/moshiro-update/<role>.image`。所有单元均使用相同的配置和状态 volume 名称。自动启动分别使用 `systemctl --user enable --now <unit>` 或 `sudo systemctl enable --now <unit>`。Rootless 在退出登录后继续运行需管理员执行一次 `loginctl enable-linger <用户名>`。
|
||||
|
||||
@@ -243,7 +243,7 @@ Backend 用根目录的 `compose.yaml`(见上文「Backend 容器」),数
|
||||
Agent 和 Probe 每天固定时刻有序退出一次,由服务管理器拉起(所有 systemd 单元和 OpenWrt 的 procd 脚本都是「总是重启」,正常退出也会被拉起)。节点只是自己退出,没有任何执行命令的能力;重启期间测量会中断几十秒。
|
||||
|
||||
- **在管理端控制**:系统 → 设置 →「定时重启」,开关、时刻和时区(默认**开**,北京时间 04:30)。保存后马上通知所有在线节点,新连上的节点会补发。
|
||||
- **节点本地覆盖**:节点本地写了就以本地为准(面板的设置对它不生效)。`agent.json` 或 `probe.json` 里加 `"restart_at": "04:30+08:00"`,或者设置环境变量 `MOSHIRO_RESTART_AT`(优先)。写法 `HH:mm`(按 UTC)、`HH:mmZ` 或 `HH:mm±hh:mm`;写错了启动时就会报错。从面板重新下载 `probe.json` 会丢掉手写的 `restart_at`,所以 Probe 的容器推荐用环境变量。
|
||||
- **节点本地覆盖**:节点本地写了就以本地为准(面板的设置对它不生效)。`agent.json` 或 `probe.json` 里加 `"restart_at": "04:30+08:00"`,或者设置环境变量 `MOSHIRO_RESTART_AT`(优先)。写法 `HH:mm`(按 UTC)、`HH:mmZ` 或 `HH:mm±hh:mm`;写错了启动时就会报错。Probe 的容器同样可以用环境变量。
|
||||
- 启动后不满 10 分钟不会触发,所以重启之后不会立刻又重启一次。日志里有 `restart scheduled at=… source=panel|local` 和 `stopping result=scheduled_restart`。
|
||||
- Windows 上没有自带的服务单元,需要服务管理器配置为退出后重启。
|
||||
|
||||
|
||||
+9
-7
@@ -7,7 +7,7 @@
|
||||
| 主体 | 凭据 | 生成方 | Backend 保存 |
|
||||
| --- | --- | --- | --- |
|
||||
| Agent | Fleet 节点身份(ECDSA P-256)+ 面向 Probe 的 TLS 证书 | `fleet-enroll` | 公钥、SPKI 指纹 |
|
||||
| Probe | Fleet 节点身份(同时用于连面板和连 Agent) | 面板生成 `probe.json`(可以有多个 Probe,每个独立吊销) | 公钥 |
|
||||
| Probe | Fleet 节点身份(连面板)+ 另一把独立的密钥(连 Agent,放在 `tls.pfx`) | `fleet-enroll`,和 Agent 一样用加入令牌(`role=probe`);可以有多个 Probe,每个独立吊销 | 两把公钥 |
|
||||
| 面板用户 | 账号 + 密码(PBKDF2-SHA256) | 面板 | 密码哈希 |
|
||||
| API 令牌 | 随机高熵令牌,作用域为 `read` 或 `admin` | 面板 | SHA-256 |
|
||||
| 发布签名 | ECDSA P-256 发布密钥 | CI(Woodpecker 密钥 `release_signing_key`)或离线环境 | 只在节点宿主机的更新器里配置公钥(容器节点是 `moshiro-update`,见 [deployment.md](deployment.md);纯二进制节点的更新是待办),**面板不保存私钥,也不验签** |
|
||||
@@ -41,10 +41,12 @@ install.sh(只做安装,不包含任何远程控制功能;容器节点的
|
||||
Probe 直接连面板(Fleet 长连接,身份是下面生成的密钥),Agent 列表由面板作为期望状态下发;测量数据仍然只走 Probe → Agent。
|
||||
|
||||
```text
|
||||
面板:POST /api/admin/probes {name}
|
||||
└─ 生成 Fleet 节点身份,返回 probe.json(只能下载一次;轮换密钥 /rotate 会使旧密钥失效,吊销 /revoke 会让面板和所有 Agent 断开它)
|
||||
{ probe_id, private_key, server: "https://panel...",
|
||||
limits: { max_test_mbps, max_total_pps } } ← 本地硬上限,面板无法修改;在路由器上建议调低
|
||||
面板: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 带上系统、架构和构建信息
|
||||
@@ -87,8 +89,8 @@ Probe 启动
|
||||
| GET | `/api/agent/v1/rpc` | 由 `MapFleetLink` 提供(升级为 WebSocket) |
|
||||
| GET/POST/DELETE | `/api/admin/join-tokens` | 管理加入令牌 |
|
||||
| POST | `/api/admin/agents/{id}/approve`、`/disable`、`/enable`、`/takeover` | 审批与启停 |
|
||||
| GET/POST/PATCH/DELETE | `/api/admin/probes`、`/probes/{id}` | Probe 身份的创建、列表、改名、删除 |
|
||||
| POST | `/api/admin/probes/{id}/rotate`、`/revoke` | 轮换密钥、吊销 |
|
||||
| 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.sh`、`/install.ps1` | 安装脚本 |
|
||||
|
||||
|
||||
+1
-1
@@ -263,7 +263,7 @@ Agent 和 Probe 的核心永远是纯采集器。**所有敏感能力**(exec
|
||||
|
||||
```text
|
||||
零 协议方向声明表 + 收发校验 + 对账测试 G7,第 8 节;同时把 NodeConnection 按职责拆开(第 13.2 节) 已完成,不破坏
|
||||
一 Probe 自己生成密钥 + 加入令牌注册 + 密钥按用途拆开 G2、G11 破坏性:旧 probe.json 失效
|
||||
一 Probe 自己生成密钥 + 加入令牌注册 + 密钥按用途拆开 G2、G11 已完成,破坏性:旧 probe.json 失效
|
||||
二 预握手敲门(等级一) G4;先基于现有的对端公钥列表,名册出来后换成名册 破坏性:旧 Probe 被拒绝
|
||||
三 操作员凭证 + 名册 + 节点验签与持久化 G1 的大部分、G3、G6;webauthn 和 ecdsa 先做,oidc 随后 破坏性:节点要固定操作员公钥并重新注册
|
||||
四 测量数据的可信 + 入库配额和输入校验 + CSP G5、G8、G9、G10、T5(第 9.1、9.2 节) 破坏性:块格式加签名
|
||||
|
||||
Reference in new issue
Block a user