wimotek-edge-agent 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +207 -161
- package/bin/cli.js +9 -4
- package/package.json +13 -7
- package/pyproject.toml +33 -2
- package/wimotek_edge_agent/__init__.py +23 -0
- package/wimotek_edge_agent/__main__.py +5 -0
- package/wimotek_edge_agent/agent.py +633 -0
- package/wimotek_edge_agent/audit.py +29 -0
- package/wimotek_edge_agent/config.py +118 -0
- package/wimotek_edge_agent/local_bypass.py +44 -0
- package/wimotek_edge_agent/models.py +55 -0
- package/wimotek_edge_agent/nat.py +28 -0
- package/wimotek_edge_agent/policy.py +160 -0
- package/wimotek_edge_agent/tokens.py +203 -0
- package/wimotek_edge_agent/transport.py +111 -0
- package/wimotek_edge_agent/trust_store.py +254 -0
- package/agent.py +0 -330
- package/dist/wimotek_edge_agent-1.0.4-py3-none-any.whl +0 -0
- package/dist/wimotek_edge_agent-1.0.4.tar.gz +0 -0
- package/wimotek_edge_agent.egg-info/PKG-INFO +0 -228
- package/wimotek_edge_agent.egg-info/SOURCES.txt +0 -9
- package/wimotek_edge_agent.egg-info/dependency_links.txt +0 -1
- package/wimotek_edge_agent.egg-info/entry_points.txt +0 -3
- package/wimotek_edge_agent.egg-info/requires.txt +0 -2
- package/wimotek_edge_agent.egg-info/top_level.txt +0 -1
package/README.md
CHANGED
|
@@ -1,219 +1,265 @@
|
|
|
1
|
-
# Wimotek Edge Agent
|
|
1
|
+
# Wimotek Edge Agent
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://www.npmjs.com/package/wimotek-edge-agent)
|
|
5
|
-
[](https://pypi.org/project/wimotek-edge-agent/)
|
|
6
|
-
[](https://opensource.org/licenses/MIT)
|
|
3
|
+
Commercial-grade edge access control, service bridge, and tunnel agent featuring a 3-layer decision policy engine, TOFU quarantine, single-use HMAC token verification, session fast re-auth, and NAT4 reverse tunneling.
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
## Table of contents
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
- [Design goals](#design-goals)
|
|
8
|
+
- [Architecture](#architecture)
|
|
9
|
+
- [Decision matrix](#decision-matrix)
|
|
10
|
+
- [Installation & Quickstart](#installation--quickstart)
|
|
11
|
+
- [Environment variables](#environment-variables)
|
|
12
|
+
- [CLI usage](#cli-usage)
|
|
13
|
+
- [Programmatic usage](#programmatic-usage)
|
|
14
|
+
- [Reverse tunnel / NAT4](#reverse-tunnel--nat4)
|
|
15
|
+
- [Audit log](#audit-log)
|
|
16
|
+
- [Security model](#security-model)
|
|
17
|
+
- [Commercial deployment checklist](#commercial-deployment-checklist)
|
|
18
|
+
- [License](#license)
|
|
11
19
|
|
|
12
|
-
|
|
20
|
+
## Design goals
|
|
13
21
|
|
|
14
|
-
|
|
22
|
+
1. **Local connections default allow**, gated by `local_bypass_token` (mode `0600`), preventing unauthorized local processes from abusing `127.0.0.1`.
|
|
23
|
+
2. **External connections default TOFU**. Unauthenticated nodes are quarantined to heartbeats only. No business data is relayed until approved by an administrator.
|
|
24
|
+
3. **External connections with token use Edge Agent mode**. Single-use HMAC-SHA256 tokens verify signature, TTL, audience, issuer, optional node UUID, IP CIDR binding, and replay prevention.
|
|
25
|
+
4. **NAT4 / no public IP uses reverse tunnel**. Authentication strength remains identical under `nat4_reverse` network profiles.
|
|
26
|
+
5. **Trusted nodes re-auth with short-lived session tickets**. Trusted nodes without token or session are denied, strictly preventing downgrade attacks to TOFU.
|
|
15
27
|
|
|
16
|
-
|
|
17
|
-
- **🛡️ 生产级双模身份认证与防伪造(TOFU + Edge Agent)**:
|
|
18
|
-
- **默认 TOFU 模式(Trust On First Use)**:零配置启动,节点自动生成硬件指纹 UUID,管理端后台实时弹出审核认领,管理员「一键信任锁定」后完成公钥防篡改绑定。
|
|
19
|
-
- **Edge Agent 模式**:批量注入 `JOIN_TOKEN`,节点开机秒级自验证入网,支持 CI/CD 与大规模集群全自动挂靠。
|
|
20
|
-
- **🤖 智能命名与设备自协商**:自动探测出口公网 IP 或物理网卡 IP 智能拼接命名(如 `Node-123.45.67.89`),嗅探失败平滑降级为容器主机名。
|
|
21
|
-
- **🔌 通用本地服务透明桥接(Decoupled & Multi-Service)**:业务完全解耦,不仅支持 Chromium CDP(9222),亦可同时中继 VNC 桌面(6080)、Web 业务 API(8080)等任意本地端口。
|
|
22
|
-
- **🌐 跨语言分发与 CLI 驱动**:同时发布至 PyPI 与 npm,支持系统级全局命令 `edge-agent` 与 `npx wimotek-edge-agent`。
|
|
28
|
+
## Architecture
|
|
23
29
|
|
|
24
|
-
|
|
30
|
+
```text
|
|
31
|
+
+---------------------------+
|
|
32
|
+
loopback ---> | AccessPolicyEngine | ---> ALLOW_LOCAL
|
|
33
|
+
| (Single Decision Point) |
|
|
34
|
+
external ---> | | ---> ALLOW_TOKEN
|
|
35
|
+
+ token | 1. Local bypass token |
|
|
36
|
+
| 2. Join token verify | ---> ALLOW_SESSION
|
|
37
|
+
external ---> | 3. Session ticket |
|
|
38
|
+
no token | 4. TOFU quarantine | ---> PENDING_TOFU
|
|
39
|
+
| 5. Revoked / mismatch |
|
|
40
|
+
nat4_rev ---> | | ---> DENY
|
|
41
|
+
+---------------------------+
|
|
42
|
+
|
|
|
43
|
+
v
|
|
44
|
+
+-------------------+
|
|
45
|
+
| TrustStore |
|
|
46
|
+
| SQLite WAL |
|
|
47
|
+
| pending/trusted/ |
|
|
48
|
+
| revoked + jti |
|
|
49
|
+
+-------------------+
|
|
50
|
+
|
|
|
51
|
+
v
|
|
52
|
+
+-------------------+
|
|
53
|
+
| AuditLogger |
|
|
54
|
+
| JSON Lines |
|
|
55
|
+
+-------------------+
|
|
56
|
+
```
|
|
25
57
|
|
|
26
|
-
##
|
|
58
|
+
## Decision matrix
|
|
59
|
+
|
|
60
|
+
| Source | Loopback | Join token | Session ticket | Existing trust | Decision |
|
|
61
|
+
|--------|----------|------------|----------------|----------------|----------|
|
|
62
|
+
| direct | yes | - | - | any | `ALLOW_LOCAL` if bypass token ok, else `DENY` |
|
|
63
|
+
| direct | no | valid | - | any | `ALLOW_TOKEN`, bind trust |
|
|
64
|
+
| direct | no | invalid/replay | - | any | `DENY` |
|
|
65
|
+
| direct | no | - | valid | trusted | `ALLOW_SESSION` |
|
|
66
|
+
| direct | no | - | - | trusted | `DENY` (no downgrade to TOFU) |
|
|
67
|
+
| direct | no | - | - | pending, same fp | `PENDING_TOFU` (heartbeat only) |
|
|
68
|
+
| direct | no | - | - | pending, diff fp | `DENY` (fingerprint tamper prevention) |
|
|
69
|
+
| direct | no | - | - | none | `PENDING_TOFU` (quarantine) |
|
|
70
|
+
| direct | no | - | - | revoked | `DENY` |
|
|
71
|
+
| nat4_reverse | no | valid | - | any | `ALLOW_TOKEN` |
|
|
72
|
+
| nat4_reverse | no | - | - | none | `PENDING_TOFU` |
|
|
73
|
+
|
|
74
|
+
## Installation & Quickstart
|
|
75
|
+
|
|
76
|
+
### Python Package
|
|
27
77
|
|
|
28
|
-
```text
|
|
29
|
-
┌────────────────────────────────────────────────────────┐
|
|
30
|
-
│ 边缘内网节点 (家用宽带 / NAT4 / 容器无公网IP) │
|
|
31
|
-
│ │
|
|
32
|
-
│ - Chromium CDP (:9222) │
|
|
33
|
-
│ - noVNC 桌面 (:6080) │
|
|
34
|
-
│ - 自定义业务服务 (:8080) │
|
|
35
|
-
└──────────────────────────┬─────────────────────────────┘
|
|
36
|
-
▲ 本地 127.0.0.1 访问
|
|
37
|
-
▼
|
|
38
|
-
┌────────────────────────────────────────────────────────┐
|
|
39
|
-
│ wimotek-edge-agent 客户端 │
|
|
40
|
-
│ │
|
|
41
|
-
│ 职责: 硬件指纹生成 + TOFU/Token协商 + 本地服务透明中继 │
|
|
42
|
-
└──────────────────────────┬─────────────────────────────┘
|
|
43
|
-
│
|
|
44
|
-
│ 主动发起出站反向长连接 (Outbound TLS/WSS)
|
|
45
|
-
│ 仅需中心管理端暴露 8443 端口,无视客户端网络环境
|
|
46
|
-
▼
|
|
47
|
-
┌────────────────────────────────────────────────────────┐
|
|
48
|
-
│ 中心控制端 (Central Hub) │
|
|
49
|
-
│ │
|
|
50
|
-
│ - 管理员在线认领锁定 (TOFU) / Token 自动化放行 │
|
|
51
|
-
│ - 借由反向长连接随时下发指令、Cookie同步、采集探针 │
|
|
52
|
-
└────────────────────────────────────────────────────────┘
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## 📦 安装与调用
|
|
58
|
-
|
|
59
|
-
### 1. Python / PyPI 安装(推荐)
|
|
60
78
|
```bash
|
|
61
79
|
pip install wimotek-edge-agent
|
|
62
80
|
```
|
|
63
|
-
安装后直接获得系统全局命令 **`edge-agent`**。
|
|
64
81
|
|
|
65
|
-
|
|
82
|
+
From source:
|
|
83
|
+
|
|
66
84
|
```bash
|
|
67
|
-
|
|
85
|
+
git clone https://github.com/wimotek/wimotek-edge-agent.git
|
|
86
|
+
cd wimotek-edge-agent
|
|
87
|
+
pip install -e .
|
|
68
88
|
```
|
|
69
|
-
|
|
89
|
+
|
|
90
|
+
### Node.js CLI Runner
|
|
91
|
+
|
|
70
92
|
```bash
|
|
71
93
|
npm install -g wimotek-edge-agent
|
|
94
|
+
# or directly execute:
|
|
95
|
+
npx wimotek-edge-agent --help
|
|
72
96
|
```
|
|
73
97
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
98
|
+
## Environment variables
|
|
99
|
+
|
|
100
|
+
| Variable | Required | Default | Description |
|
|
101
|
+
|----------|----------|---------|-------------|
|
|
102
|
+
| `EDGE_AGENT_DATA_DIR` | no | `./edge_agent_data` | Persistent data directory for trust DB, audit log, local bypass token |
|
|
103
|
+
| `EDGE_AGENT_TOKEN_SECRET` | yes | - | HMAC secret, >= 32 bytes |
|
|
104
|
+
| `EDGE_AGENT_TOKEN_AUDIENCE` | no | `edge-agent` | Token audience claim |
|
|
105
|
+
| `EDGE_AGENT_TOKEN_ISSUER` | no | `central` | Token issuer claim |
|
|
106
|
+
| `EDGE_AGENT_TOKEN_MAX_TTL_SECONDS` | no | `600` | Max token TTL (seconds) |
|
|
107
|
+
| `EDGE_AGENT_SESSION_TICKET_TTL_SECONDS` | no | `300` | Session ticket TTL (seconds) |
|
|
108
|
+
| `EDGE_AGENT_TOFU_HEARTBEAT_SECONDS` | no | `10` | TOFU quarantine heartbeat interval |
|
|
109
|
+
| `EDGE_AGENT_REQUIRE_LOCAL_BYPASS_TOKEN` | no | `true` | Require local bypass token for loopback |
|
|
110
|
+
| `EDGE_AGENT_REVERSE_TUNNEL` | no | auto | Force reverse tunnel (`true`/`false`) |
|
|
111
|
+
| `EDGE_AGENT_NAT_TYPE` | no | `unknown` | Network NAT type (`nat4`, `symmetric`, etc.) |
|
|
112
|
+
| `EDGE_AGENT_NODE_UUID` | reverse only | - | Agent node UUID |
|
|
113
|
+
| `EDGE_AGENT_PUBLIC_KEY_FINGERPRINT` | reverse only | - | Agent public key fingerprint |
|
|
114
|
+
| `EDGE_AGENT_JOIN_TOKEN` | reverse only | - | Join token for reverse tunnel connection |
|
|
115
|
+
| `EDGE_AGENT_TLS_SERVER_NAME` | no | - | TLS SNI hostname |
|
|
116
|
+
| `EDGE_AGENT_CERTIFICATE_PIN_SHA256` | no | - | TLS certificate SHA-256 pin |
|
|
117
|
+
|
|
118
|
+
Generate a high-entropy secret:
|
|
77
119
|
|
|
78
|
-
### 1. 命令行直接启动 (CLI)
|
|
79
120
|
```bash
|
|
80
|
-
|
|
81
|
-
|
|
121
|
+
wimotek-edge-agent generate-secret
|
|
122
|
+
```
|
|
82
123
|
|
|
83
|
-
|
|
84
|
-
edge-agent --hub-url https://hub.yourdomain.com:8443 --reverse
|
|
124
|
+
## CLI usage
|
|
85
125
|
|
|
86
|
-
|
|
87
|
-
edge-agent --hub-url https://hub.yourdomain.com:8443 --join-token hub_join_xxxxxx --reverse
|
|
88
|
-
```
|
|
126
|
+
Start a direct TLS / TCP JSON-line server:
|
|
89
127
|
|
|
90
|
-
### 2. 环境变量一键启动(容器化最佳实践)
|
|
91
|
-
无需修改命令,直接传入环境变量:
|
|
92
128
|
```bash
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
export REVERSE_TUNNEL="true" # 可选,默认 false;NAT4 无公网环境设为 true
|
|
96
|
-
edge-agent
|
|
129
|
+
wimotek-edge-agent listen --host 0.0.0.0 --port 8443 \
|
|
130
|
+
--cert /path/server.crt --key /path/server.key
|
|
97
131
|
```
|
|
98
132
|
|
|
99
|
-
|
|
100
|
-
```python
|
|
101
|
-
from wimotek_edge_agent import EdgeAgent
|
|
102
|
-
|
|
103
|
-
agent = EdgeAgent(
|
|
104
|
-
hub_url="https://hub.yourdomain.com:8443",
|
|
105
|
-
join_token="hub_join_xxxxxx", # 可选
|
|
106
|
-
node_name="Seoul-Worker-01", # 可选,留空自动按 IP 拼接
|
|
107
|
-
node_group="爬虫矩阵组", # 默认: 默认分组
|
|
108
|
-
cdp_port=9222, # 默认: 9222
|
|
109
|
-
reverse_tunnel=True # 开启 NAT4 反向长连接
|
|
110
|
-
)
|
|
133
|
+
Approve a pending TOFU node (admin out-of-band verification):
|
|
111
134
|
|
|
112
|
-
|
|
113
|
-
agent
|
|
135
|
+
```bash
|
|
136
|
+
wimotek-edge-agent approve --node-uuid node-xxx --fingerprint sha256:...
|
|
114
137
|
```
|
|
115
138
|
|
|
116
|
-
|
|
139
|
+
Revoke a compromised or decommissioned node:
|
|
117
140
|
|
|
118
|
-
|
|
141
|
+
```bash
|
|
142
|
+
wimotek-edge-agent revoke --node-uuid node-xxx
|
|
143
|
+
```
|
|
119
144
|
|
|
120
|
-
|
|
121
|
-
| :--- | :--- | :--- | :--- |
|
|
122
|
-
| `HUB_URL` | `--hub-url` | *无 (必填)* | 中心管理端 HTTPS/WSS 地址,如 `https://hub.domain.com:8443` |
|
|
123
|
-
| `JOIN_TOKEN` | `--join-token` | `""` (空) | 集群入网通行码。**留空走 TOFU 后台审核认领**;填入则走 Edge Agent 自动放行入网 |
|
|
124
|
-
| `REVERSE_TUNNEL`| `--reverse` / `--direct` | `false` | 是否开启出站反向长连接隧道。**无公网 IP/NAT4 环境设为 `true`**;有公网/局域网设为 `false` |
|
|
125
|
-
| `NODE_NAME` | `--node-name` | 自动嗅探 | 节点名称。未设置时自动以出口 IP 命名(如 `Node-123.45.67.89`),兜底为主机名 |
|
|
126
|
-
| `NODE_GROUP` | `--group` | `默认分组` | 节点所属集群分组,便于多策略调度分类 |
|
|
127
|
-
| `CDP_PORT` | `--port` | `9222` | 容器本地需要中继的主服务端口(如 Chromium 调试端口) |
|
|
128
|
-
| `LOCAL_CDP_HOST`| `--cdp-host` | `127.0.0.1` | 节点本地被中继服务的绑定地址 |
|
|
129
|
-
| `SERVICES` | `--services` | *无* | 多服务端口定义,格式:`cdp:9222,vnc:6080,api:8080` |
|
|
130
|
-
| `UUID_FILE` | `--uuid-file` | `/data/node_machine.id` | 硬件指纹持久化文件路径,保障重启后身份不漂移 |
|
|
145
|
+
List all managed nodes in trust store:
|
|
131
146
|
|
|
132
|
-
|
|
147
|
+
```bash
|
|
148
|
+
wimotek-edge-agent list-nodes --status trusted
|
|
149
|
+
```
|
|
133
150
|
|
|
134
|
-
|
|
151
|
+
Inspect a specific node record:
|
|
135
152
|
|
|
136
|
-
|
|
137
|
-
|
|
153
|
+
```bash
|
|
154
|
+
wimotek-edge-agent show-node --node-uuid node-xxx
|
|
155
|
+
```
|
|
138
156
|
|
|
139
|
-
|
|
140
|
-
FROM debian:bookworm-slim
|
|
157
|
+
Issue a single-use Edge Agent join token:
|
|
141
158
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
159
|
+
```bash
|
|
160
|
+
wimotek-edge-agent issue-token \
|
|
161
|
+
--node-group fleet-a \
|
|
162
|
+
--ttl 300 \
|
|
163
|
+
--node-uuid node-xxx \
|
|
164
|
+
--allowed-ip-cidr 203.0.113.0/24
|
|
165
|
+
```
|
|
146
166
|
|
|
147
|
-
|
|
148
|
-
RUN pip3 install --no-cache-dir --break-system-packages wimotek-edge-agent
|
|
167
|
+
Verify a token directly:
|
|
149
168
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
ENTRYPOINT ["/app/entrypoint.sh"]
|
|
169
|
+
```bash
|
|
170
|
+
wimotek-edge-agent verify-token --token <token_string> --source-ip 203.0.113.10
|
|
153
171
|
```
|
|
154
172
|
|
|
155
|
-
|
|
173
|
+
Read or generate the local bypass token:
|
|
174
|
+
|
|
156
175
|
```bash
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
chromium --remote-debugging-port=9222 --remote-allow-origins=* &
|
|
176
|
+
wimotek-edge-agent bypass-token
|
|
177
|
+
```
|
|
160
178
|
|
|
161
|
-
|
|
162
|
-
if [ -n "$HUB_URL" ]; then
|
|
163
|
-
echo "🚀 启动 wimotek-edge-agent ..."
|
|
164
|
-
edge-agent &
|
|
165
|
-
fi
|
|
179
|
+
## Programmatic usage
|
|
166
180
|
|
|
167
|
-
|
|
181
|
+
```python
|
|
182
|
+
import asyncio
|
|
183
|
+
from wimotek_edge_agent import Config, EdgeAgent
|
|
184
|
+
from wimotek_edge_agent.transport import JsonLineTransport
|
|
185
|
+
|
|
186
|
+
async def main() -> None:
|
|
187
|
+
config = Config.from_env()
|
|
188
|
+
agent = EdgeAgent(config)
|
|
189
|
+
|
|
190
|
+
async def data_handler(transport, ctx):
|
|
191
|
+
while True:
|
|
192
|
+
msg = await transport.read_message()
|
|
193
|
+
if msg.get("type") == "ping":
|
|
194
|
+
await transport.write_message({"type": "pong"})
|
|
195
|
+
|
|
196
|
+
agent.data_handler = data_handler
|
|
197
|
+
|
|
198
|
+
server = await asyncio.start_server(
|
|
199
|
+
lambda r, w: agent.handle_connection(
|
|
200
|
+
JsonLineTransport(r, w),
|
|
201
|
+
w.get_extra_info("peername")[0],
|
|
202
|
+
),
|
|
203
|
+
host="0.0.0.0",
|
|
204
|
+
port=8443,
|
|
205
|
+
)
|
|
206
|
+
async with server:
|
|
207
|
+
await server.serve_forever()
|
|
208
|
+
|
|
209
|
+
if __name__ == "__main__":
|
|
210
|
+
asyncio.run(main())
|
|
168
211
|
```
|
|
169
212
|
|
|
170
|
-
|
|
213
|
+
## Reverse tunnel / NAT4
|
|
171
214
|
|
|
172
|
-
|
|
173
|
-
```yaml
|
|
174
|
-
version: '3.8'
|
|
215
|
+
Implement `TunnelDialer` with your WebSocket stack, then launch:
|
|
175
216
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
- HUB_URL=https://hub.yourdomain.com:8443
|
|
184
|
-
- JOIN_TOKEN=hub_join_abcdef1234567890 # 可选:留空在控制台一键点击认领
|
|
185
|
-
- REVERSE_TUNNEL=true # NAT4 穿透开关
|
|
186
|
-
- NODE_GROUP=北美爬虫矩阵组
|
|
187
|
-
volumes:
|
|
188
|
-
- ./data:/data
|
|
217
|
+
```python
|
|
218
|
+
await agent.run_reverse_tunnel(
|
|
219
|
+
url="wss://central.example.com/tunnel",
|
|
220
|
+
dialer=your_dialer,
|
|
221
|
+
ssl_context=ssl_context,
|
|
222
|
+
server_hostname="central.example.com",
|
|
223
|
+
)
|
|
189
224
|
```
|
|
190
225
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
226
|
+
- Sends handshake fields (`node_uuid`, `public_key_fingerprint`, `join_token`, `nat_type`, `reverse_tunnel`);
|
|
227
|
+
- Supports TLS pinning via `EDGE_AGENT_CERTIFICATE_PIN_SHA256`;
|
|
228
|
+
- Quarantines in `pending_tofu` until approved by central administrator;
|
|
229
|
+
- Exponential backoff on reconnection attempts.
|
|
230
|
+
|
|
231
|
+
## Audit log
|
|
194
232
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
ports:
|
|
200
|
-
- "9222:9222" # 防火墙已开放端口
|
|
201
|
-
environment:
|
|
202
|
-
- HUB_URL=https://hub.yourdomain.com:8443
|
|
203
|
-
- REVERSE_TUNNEL=false # 默认即为 false,仅发起轻量 HTTP 登记,零长连接开销
|
|
233
|
+
Every `AccessDecision` is written to `EDGE_AGENT_DATA_DIR/audit.jsonl`:
|
|
234
|
+
|
|
235
|
+
```json
|
|
236
|
+
{"ts":"2026-11-06T12:00:00+00:00","event":"access_decision","node_uuid":"node-xxx","source_ip":"203.0.113.10","is_loopback":false,"decision":"allow_token","reason":"edge_agent_token_verified","network_profile":"direct","nat_type":"unknown","fingerprint":"sha256:...","node_status":"trusted"}
|
|
204
237
|
```
|
|
205
238
|
|
|
206
|
-
|
|
239
|
+
Ship this structured log file to your central logging pipeline (Loki, ELK, CloudWatch, OpenTelemetry). Raw join tokens are never logged.
|
|
240
|
+
|
|
241
|
+
## Security model
|
|
207
242
|
|
|
208
|
-
|
|
243
|
+
- **Token Secret**: >= 32 bytes HMAC secret.
|
|
244
|
+
- **Single-Use Replay Protection**: `jti` is stored in SQLite `used_tokens` until expiration. Subsequent attempts are rejected with `token replay detected`.
|
|
245
|
+
- **Identity & Network Binding**: Tokens can be bound to specific `node_uuid` and `allowed_ip_cidr` networks.
|
|
246
|
+
- **TOFU Quarantine**: Unapproved nodes only exchange heartbeats; business data relay is strictly forbidden.
|
|
247
|
+
- **No Downgrade**: Trusted nodes presenting without credentials cannot downgrade to TOFU.
|
|
248
|
+
- **Local Bypass Hardening**: `local_bypass.token` is generated with POSIX `0600` permissions.
|
|
249
|
+
- **Immediate Revocation**: Revoked nodes are denied on the next handshake packet across all network profiles.
|
|
209
250
|
|
|
210
|
-
|
|
211
|
-
2. **防公网扫描冒充**:未携带 `JOIN_TOKEN` 的未知连接一律进入隔离待审核队列(TOFU),未经管理端管理员后台显式认领的节点,绝不参与任何数据交互。
|
|
212
|
-
3. **安全通信**:长连接反向通道强制基于 TLS (WSS) 传输,天然防御中间人窃听与数据篡改。
|
|
251
|
+
## Commercial deployment checklist
|
|
213
252
|
|
|
214
|
-
|
|
253
|
+
- [ ] Set unique `EDGE_AGENT_TOKEN_SECRET` (>= 32 bytes) per environment.
|
|
254
|
+
- [ ] Mount `EDGE_AGENT_DATA_DIR` on persistent, encrypted storage.
|
|
255
|
+
- [ ] Verify `local_bypass.token` POSIX permissions (`0600`).
|
|
256
|
+
- [ ] Ship `audit.jsonl` to central security SIEM.
|
|
257
|
+
- [ ] Enable TLS; configure `EDGE_AGENT_CERTIFICATE_PIN_SHA256` for reverse tunnels.
|
|
258
|
+
- [ ] Restrict `wimotek-edge-agent approve` to admin-only bastion hosts or CI pipelines.
|
|
259
|
+
- [ ] Monitor `tofu_pending_queue_size` and `token_replay_rejections`.
|
|
260
|
+
- [ ] Execute `wimotek-edge-agent revoke` upon node decommissioning.
|
|
261
|
+
- [ ] Back up `trust_store.sqlite3` prior to upgrades.
|
|
215
262
|
|
|
216
|
-
##
|
|
263
|
+
## License
|
|
217
264
|
|
|
218
|
-
MIT
|
|
219
|
-
```
|
|
265
|
+
MIT. See `LICENSE`.
|
package/bin/cli.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const { spawn } = require('child_process');
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const packageDir = path.resolve(__dirname, '..');
|
|
6
|
+
const env = { ...process.env };
|
|
7
|
+
env.PYTHONPATH = env.PYTHONPATH ? `${packageDir}:${env.PYTHONPATH}` : packageDir;
|
|
8
|
+
|
|
9
|
+
const args = ['-m', 'wimotek_edge_agent', ...process.argv.slice(2)];
|
|
10
|
+
const py = spawn('python3', args, { stdio: 'inherit', env });
|
|
6
11
|
|
|
7
12
|
py.on('error', () => {
|
|
8
|
-
console.error('❌ 请确保宿主机已安装 Python 3
|
|
13
|
+
console.error('❌ 请确保宿主机已安装 Python 3 环境与 wimotek-edge-agent 依赖。');
|
|
9
14
|
process.exit(1);
|
|
10
15
|
});
|
|
11
16
|
|
|
12
17
|
py.on('close', (code) => {
|
|
13
|
-
process.exit(code);
|
|
18
|
+
process.exit(code ?? 0);
|
|
14
19
|
});
|
package/package.json
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wimotek-edge-agent",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Universal Edge
|
|
5
|
-
"main": "index.js",
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"description": "Universal Edge Reverse Proxy & Service Bridge Agent CLI Runner",
|
|
6
5
|
"bin": {
|
|
6
|
+
"wimotek-edge-agent": "./bin/cli.js",
|
|
7
|
+
"wimotek-agent": "./bin/cli.js",
|
|
7
8
|
"edge-agent": "./bin/cli.js"
|
|
8
9
|
},
|
|
9
10
|
"keywords": [
|
|
11
|
+
"wimotek",
|
|
10
12
|
"edge",
|
|
11
13
|
"agent",
|
|
12
14
|
"tunnel",
|
|
13
15
|
"reverse-proxy",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
+
"zero-trust",
|
|
17
|
+
"tofu",
|
|
18
|
+
"hmac-token"
|
|
16
19
|
],
|
|
17
|
-
"author": "wimotek",
|
|
18
|
-
"license": "MIT"
|
|
20
|
+
"author": "Wimotek <wimotek@gmail.com>",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=16.0.0"
|
|
24
|
+
}
|
|
19
25
|
}
|
package/pyproject.toml
CHANGED
|
@@ -6,15 +6,46 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "wimotek-edge-agent"
|
|
9
|
-
version = "1.0.
|
|
9
|
+
version = "1.0.0.6"
|
|
10
10
|
description = "Universal Edge Reverse Proxy & Service Bridge Agent"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.9"
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Wimotek", email = "wimotek@gmail.com" },
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Operating System :: OS Independent",
|
|
24
|
+
"Topic :: Internet :: Proxy Servers",
|
|
25
|
+
"Topic :: Security :: Cryptography",
|
|
26
|
+
]
|
|
13
27
|
dependencies = [
|
|
14
28
|
"httpx>=0.24.0",
|
|
15
29
|
"websockets>=11.0",
|
|
16
30
|
]
|
|
17
31
|
|
|
32
|
+
[project.license]
|
|
33
|
+
text = "MIT"
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
dev = [
|
|
37
|
+
"pytest>=7.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
18
40
|
[project.scripts]
|
|
19
|
-
edge-agent = "wimotek_edge_agent.agent:main"
|
|
41
|
+
wimotek-edge-agent = "wimotek_edge_agent.agent:main"
|
|
20
42
|
wimotek-agent = "wimotek_edge_agent.agent:main"
|
|
43
|
+
edge-agent = "wimotek_edge_agent.agent:main"
|
|
44
|
+
|
|
45
|
+
[tool.setuptools.packages.find]
|
|
46
|
+
where = [
|
|
47
|
+
".",
|
|
48
|
+
]
|
|
49
|
+
include = [
|
|
50
|
+
"wimotek_edge_agent*",
|
|
51
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from .agent import EdgeAgent
|
|
2
|
+
from .config import Config
|
|
3
|
+
from .models import (
|
|
4
|
+
AccessDecision,
|
|
5
|
+
AccessDecisionResult,
|
|
6
|
+
ConnectionContext,
|
|
7
|
+
NodeRecord,
|
|
8
|
+
TrustStatus,
|
|
9
|
+
)
|
|
10
|
+
from .policy import AccessPolicyEngine
|
|
11
|
+
from .trust_store import TrustStore
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"EdgeAgent",
|
|
15
|
+
"Config",
|
|
16
|
+
"AccessDecision",
|
|
17
|
+
"AccessDecisionResult",
|
|
18
|
+
"ConnectionContext",
|
|
19
|
+
"NodeRecord",
|
|
20
|
+
"TrustStatus",
|
|
21
|
+
"AccessPolicyEngine",
|
|
22
|
+
"TrustStore",
|
|
23
|
+
]
|