From 3324c1d687b36744a2e14a9adb0b2db8f5f3ff97 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Thu, 23 Jul 2026 02:24:51 +0800 Subject: [PATCH] =?UTF-8?q?docs(agent):=20=E7=A7=81=E6=9C=89=E7=9B=AE?= =?UTF-8?q?=E7=9A=84=E5=9C=B0=20ACL=20=E9=85=8D=E7=BD=AE=E6=A0=B7=E4=BE=8B?= =?UTF-8?q?=E4=B8=8E=E5=B8=B8=E9=A9=BB=E6=A0=A1=E9=AA=8C=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- deploy/single-node/acl.json.example | 19 +++++++++++++++++++ docs/private-dest-acl-design.html | 2 +- server/internal/agentd/acl_test.go | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 deploy/single-node/acl.json.example diff --git a/deploy/single-node/acl.json.example b/deploy/single-node/acl.json.example new file mode 100644 index 0000000..8229bae --- /dev/null +++ b/deploy/single-node/acl.json.example @@ -0,0 +1,19 @@ +{ + "_comment": "私有目的地访问控制。复制到 /etc/pangolin-agent/acl.json 并填入自己的 dp_uuid。改完执行 systemctl reload pangolin-agent(不要 restart,restart 会冷启 sing-box 踢掉全部在线用户)。", + "enabled": true, + "allow_dp_uuids": [ + "TODO-设备级-dp-uuid", + "TODO-账户级-dp-uuid-供-sub-订阅链接用" + ], + "targets": [ + { + "_comment": "与公开站共用 ali:443 的私有 vhost,只能靠 SNI 区分", + "domain": ["brain.51yanmei.com", "git.51yanmei.com"] + }, + { + "_comment": "独占端口的服务:DSM 5001 / RDP 3389 / NAS SSH 10022 / Win SSH 10023", + "ip_cidr": ["182.92.213.171/32"], + "port": [5001, 3389, 10022, 10023] + } + ] +} diff --git a/docs/private-dest-acl-design.html b/docs/private-dest-acl-design.html index 0e9e974..f5d7bc6 100644 --- a/docs/private-dest-acl-design.html +++ b/docs/private-dest-acl-design.html @@ -185,7 +185,7 @@

不动:控制面、数据库(零 migration)、proto、客户端、管理后台、CI。改动全部收敛在 internal/agentd/

8. 名单维护 Runbook

-

新增/更换设备后,重新生成白名单(UNION 那一半是账户级 dp_uuid,供 /sub 订阅链接用,别漏):

+

新增/更换设备后,重新生成白名单(UNION 那一半是账户级 dp_uuid,供 /sub 订阅链接用,别漏)。样例文件见 deploy/single-node/acl.json.example,复制到 /etc/pangolin-agent/acl.json 后按下方 SQL 填入 uuid。

sqlite3 /var/lib/pangolin/pangolin.db \
   "SELECT d.dp_uuid FROM devices d JOIN users u ON u.id = d.user_id
     WHERE u.email = '<我的邮箱>' AND d.dp_uuid IS NOT NULL
diff --git a/server/internal/agentd/acl_test.go b/server/internal/agentd/acl_test.go
index a974848..5ae4159 100644
--- a/server/internal/agentd/acl_test.go
+++ b/server/internal/agentd/acl_test.go
@@ -490,3 +490,27 @@ func TestACL_ColdStartAfterDeletedFileFallsBackToDisk(t *testing.T) {
 		t.Fatal("冷启动(acl.json 删除)未回退到磁盘 last-good,私有服务已敞开")
 	}
 }
+
+// 样例文件必须始终可被解析且产出预期规则,防止改了 ACLTarget 形状却忘了同步样例。
+func TestACLExampleFileStaysValid(t *testing.T) {
+	path := filepath.Join("..", "..", "..", "deploy", "single-node", "acl.json.example")
+	ac, err := LoadACLConfig(path)
+	if err != nil {
+		t.Fatalf("样例文件解析失败 %s: %v", path, err)
+	}
+	if ac == nil {
+		t.Fatalf("样例文件不存在: %s", path)
+	}
+	if !ac.active() {
+		t.Error("样例文件应当是一份 active 的 ACL")
+	}
+	if len(ac.Targets) != 2 {
+		t.Errorf("样例 targets = %d, want 2", len(ac.Targets))
+	}
+	// 样例里的 uuid 是占位符,不该是真实 uuid(真实 uuid 属标识信息,不入 git)
+	for _, u := range ac.AllowDpUUIDs {
+		if !strings.HasPrefix(u, "TODO-") {
+			t.Errorf("样例文件混入了非占位 uuid %q —— 真实 dp_uuid 不得入 git", u)
+		}
+	}
+}