Files
pangolin/infra/cloud-init/README.md
wangjia f03d2dc8a6 feat(agent): node agent — enroll/mTLS, heartbeat, command stream, sing-box 用户表 (tsk__R8M4jEw43JR)
与控制面同仓同 go.mod,新增节点 agent 实现:

- proto/agent/v1/agent.proto + internal/pb/agentv1:冻结的控制面↔agent gRPC 契约
  (Enroll/Register/Heartbeat/Subscribe/Ack/ReportUsage)。仓库尚无 protoc 流水线,
  暂以手写 Go 类型 + JSON gRPC codec 实现,与 proto 1:1 对应,待 protoc 接入即可替换。
- internal/agentd:
  - enroll.go:首启生成 EC 密钥+CSR,持 bootstrap token 调 Enroll 换 90d 节点证书
    (CN=node_uuid),落 /etc/pangolin-agent/,此后 mTLS。
  - conn.go(agent.go)+creds.go:mTLS 主动拨号 + 指数退避重连;重连携带 last_command_id;
    Register 取 ConfigSnapshot 全量配置覆盖本地。
  - heartbeat.go:30s 上报 peer/带宽/CPU + config_version;need_full_resync→全量同步。
  - command.go:消费 Subscribe,Upsert/Revoke/Rotate/ApplyConfig/Lifecycle 幂等处理后
    Ack(at-least-once,按 command_id 去重)。
  - singbox.go+render.go:内存用户表 + 落盘 state.json(仅 dp_uuid+expires_at);任何变更
    渲染完整 sing-box 配置(REALITY users[uuid,flow] + Hy2 users[派生口令])→ 500ms 去抖
    合并 → systemd 重启。
  - ttl.go:凭证 TTL 定时移除并上报。
  - usage.go:按 dp_uuid 聚合上报,绝无 user_id/email/目的地址。
  - derive.go:Hy2 口令 = HMAC-SHA256(key, dp_uuid),与控制面同源派生。
- cmd/agent:入口(flag/env 配置)。
- infra/cloud-init/{node.yaml.tmpl,install-node.sh,README.md}:一段式安装,下载锁定版本
  二进制并校验 SHA-256,systemd 拉管,首启即 Enroll/Register。shellcheck -S warning 通过。

测试(bufconn mock 控制面,无需 docker):Enroll→Register→Heartbeat 全流转;Upsert/Revoke
渲染正确;Rotate 宽限期新旧并存到点移除;TTL 自动移除并上报;断流重连 last_command_id
续发不丢不重;need_full_resync 触发重注册;state.json 恢复;去抖合并;扫描确认无身份字段。
go test -race ./internal/agentd/... ./internal/pb/... 通过;go vet ./... 通过。

落实 doc/04 §2 节点无状态化与 doc/06 §3 数据面红线(节点仅见 dp_uuid)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 12:26:58 +08:00

40 lines
2.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# infra/cloud-init —— 节点一段式安装
加速节点开机即用所需的全部物料。控制面(或 #14 弹性开机)在创建节点前,用 `sed`
把模板里的 `__PLACEHOLDER__` 替换成真实值(沿用 `deploy/` 渲染约定),再作为
user-data 注入。
## 文件
- `node.yaml.tmpl` —— cloud-config 模板。写入 `/etc/pangolin-agent/agent.env`
(含一次性 bootstrap token0600),下载并按 SHA-256 校验 `install-node.sh` 后执行。
- `install-node.sh` —— 幂等安装脚本:下载锁定版本的 `sing-box` + `pangolin-agent`
二进制并校验 SHA-256,装 systemd 单元(agent 拉管 sing-box),生成 Hy2 自签证书,
启动 agent(首启即 Enroll/Register)。`shellcheck -S warning` 通过。
## 占位符
| 占位符 | 含义 |
| --- | --- |
| `__CONTROL_PLANE__` | 控制面 gRPC 地址 `host:port` |
| `__SERVER_NAME__` | 校验控制面证书的 TLS SNI(留空取 host |
| `__BOOTSTRAP_TOKEN__` | 一次性引导 token`mtls.BootstrapTokenManager`15min TTL |
| `__DERIVE_KEY__` | Hy2 口令派生密钥(与控制面同源,见 `agentd.DeriveHy2Password` |
| `__AGENT_VERSION__` | agent 版本(与产物命名 + SHA 一致) |
| `__SINGBOX_VERSION__` / `__SINGBOX_SHA256__` | sing-box 版本与校验和 |
| `__AGENT_SHA256__` | agent 二进制校验和 |
| `__ARTIFACT_BASE__` | 二进制 + 安装脚本下载根 URL |
| `__INSTALL_SHA256__` | `install-node.sh` 自身的 SHA-256(防篡改) |
## 可复现性
版本与 SHA-256 全部锁定:`install-node.sh` 顶部的版本/校验和占位符由发布流水线渲染
为固定值并随产物一起发布;cloud-init 下载脚本后先校验脚本 SHA-256 再执行,脚本再逐个
校验二进制 SHA-256。任何一环不匹配即 `set -e` 中止,保证整链可复现、不可被中间人替换。
## 无状态红线
节点除 `/etc/pangolin-agent/{node.key,node.crt,ca.crt,state.json}``/etc/sing-box`
外不落任何持久数据;`state.json` 仅含 `dp_uuid + expires_at`,无任何账号/设备/目的地址/
DNS 信息,亦无访问日志(见 `doc/04 §2``doc/06 §3`)。