Files
pangolin/infra/cloud-init/node.yaml.tmpl
T
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

46 lines
2.2 KiB
Cheetah
Raw 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.
#cloud-config
# Pangolin 加速节点一段式安装模板(与 #14 弹性开机共用)。
#
# 渲染:控制面 provisioner 用 sed 替换所有 __PLACEHOLDER__(沿用 deploy/ 约定)。
# __CONTROL_PLANE__ 控制面 gRPC 地址 host:port
# __SERVER_NAME__ 校验控制面证书的 TLS SNI(留空则取 host 部分)
# __BOOTSTRAP_TOKEN__ 一次性引导 token(由 mtls.BootstrapTokenManager.IssueToken 预签发,15min TTL
# __DERIVE_KEY__ Hy2 口令派生密钥(与控制面同源,见 agentd.DeriveHy2Password
# __AGENT_VERSION__ pangolin-agent 版本(与产物命名/SHA 锁定一致)
# __ARTIFACT_BASE__ 二进制与安装脚本下载根 URL
# __INSTALL_SHA256__ install-node.sh 的 SHA-256(整链可复现校验)
#
# 安全:agent.env 内含 bootstrap token,权限 0600token 一次性消费后即失效。
# 节点无状态:除 /etc/pangolin-agent/{node.key,node.crt,ca.crt,state.json} 与
# /etc/sing-box 外不落任何持久数据,且 state.json 仅含 dp_uuid + expires_at。
write_files:
- path: /etc/pangolin-agent/agent.env
permissions: '0600'
owner: root:root
content: |
PANGOLIN_AGENT_CONTROL_PLANE=__CONTROL_PLANE__
PANGOLIN_AGENT_SERVER_NAME=__SERVER_NAME__
PANGOLIN_AGENT_BOOTSTRAP_TOKEN=__BOOTSTRAP_TOKEN__
PANGOLIN_AGENT_DERIVE_KEY=__DERIVE_KEY__
PANGOLIN_AGENT_STATE_DIR=/etc/pangolin-agent
PANGOLIN_AGENT_SINGBOX_CONFIG=/etc/sing-box/config.json
PANGOLIN_AGENT_SINGBOX_UNIT=sing-box
PANGOLIN_AGENT_VERSION=__AGENT_VERSION__
runcmd:
- |
set -euo pipefail
mkdir -p /opt/pangolin
tmp="$(mktemp)"
# 下载安装脚本并按锁定 SHA-256 校验后再执行(拒绝被篡改的脚本)。
curl -fsSL --retry 3 "__ARTIFACT_BASE__/install-node.sh" -o "$tmp"
echo "__INSTALL_SHA256__ $tmp" | sha256sum -c -
install -m 0755 "$tmp" /opt/pangolin/install-node.sh
rm -f "$tmp"
ARTIFACT_BASE="__ARTIFACT_BASE__" AGENT_VERSION="__AGENT_VERSION__" \
bash /opt/pangolin/install-node.sh
# 整机 35 分钟内可服务:cloud-init 完成 → agent 首启 Enroll → Register 取全量配置 →
# 渲染 sing-box config 并 restart sing-box → REALITY/Hy2 入站上线。