Add per-instance/user access whitelist
Features:
- New Instance.AccessMode: "open" (default) or "whitelist"
- New Instance.AllowNetworks + VPNUser.AllowNetworks: list of CIDRs
- Effective whitelist = instance allow_networks ∪ user allow_networks (dedup)
- Auto-generates client-connect.sh / client-disconnect.sh for OpenVPN:
* Reads ccd/<cn> to extract CIDRs
* Pushes "route <ip> <mask>" to client (client side)
* Inserts iptables ACCEPT rules in FORWARD chain (server side, defense in depth)
* Cleans up rules on disconnect
- server.conf auto-includes client-connect / client-disconnect directives
and push "redirect-gateway def1 bypass-dhcp" in whitelist mode
- ccd/<cn> file format: first line ifconfig-push (static IP), then one CIDR per line
- Editing instance allow_networks refreshes all users' ccd automatically
- New PUT /api/instances/:id/users/:uid endpoint
- CIDR format validation; reject malformed inputs with friendly errors
- Dashboard shows whitelist_instances count and per-instance allow_networks table
Docs:
- README: new section "三、访问控制(白名单模式)" with usage, validation, pitfalls
- docs/API.md: updated Instance / VPNUser model + create/update payloads
- Renumbered client usage section as 四
This commit is contained in:
@@ -26,7 +26,8 @@
|
||||
- [创建第一个实例](#创建第一个实例)
|
||||
- [创建客户端用户并下载配置](#创建客户端用户并下载配置)
|
||||
- [防火墙与公网暴露](#防火墙与公网暴露)
|
||||
- [三、客户端使用](#三客户端使用)
|
||||
- [三、访问控制(白名单模式)](#三访问控制白名单模式)
|
||||
- [四、客户端使用](#四客户端使用)
|
||||
- [配置文件说明](#配置文件说明)
|
||||
- [Windows](#windows)
|
||||
- [macOS](#macos)
|
||||
@@ -34,9 +35,9 @@
|
||||
- [Android](#android)
|
||||
- [iOS](#ios)
|
||||
- [验证连接](#验证连接)
|
||||
- [四、API 参考](#四api-参考)
|
||||
- [五、常见问题](#五常见问题)
|
||||
- [六、开发](#六开发)
|
||||
- [五、API 参考](#五api-参考)
|
||||
- [六、常见问题](#六常见问题)
|
||||
- [七、开发](#七开发)
|
||||
- [许可证](#许可证)
|
||||
|
||||
---
|
||||
@@ -48,6 +49,7 @@
|
||||
| 多实例管理 | 同一台机器上跑多个 OpenVPN 实例,每个独立端口/协议/子网/PKI |
|
||||
| 客户端证书 | 一键签发,自动生成 `.ovpn`(内嵌 CA/Cert/Key/TLS-Auth),无需额外文件 |
|
||||
| 固定 IP | 通过 CCD (`client-config-dir`) 为指定用户分配固定 VPN IP |
|
||||
| **访问控制(白名单)** | 实例/用户两层 allow_networks,合并生效;服务端 iptables 强制隔离 |
|
||||
| 启停控制 | Web 一键启动/停止实例,显示 PID 与状态 |
|
||||
| 流量审计 | 解析 `status-version 3` 输出,记录上下行字节/连接时长 |
|
||||
| 证书到期提醒 | 仪表盘统计 30 天内到期的证书,单独证书管理页查看完整清单 |
|
||||
@@ -359,6 +361,110 @@ firewall-cmd --reload
|
||||
|
||||
---
|
||||
|
||||
# 三、访问控制(白名单模式)
|
||||
|
||||
**核心需求**:VPN 用户登录后,只能访问你明确允许的内网网段,默认与所有内网隔离。
|
||||
|
||||
## 工作原理
|
||||
|
||||
每个实例有一个 `access_mode` 字段:
|
||||
|
||||
- `open`(默认):不限制,客户端可访问所有可达网段
|
||||
- `whitelist`:仅允许访问白名单中列出的内网网段
|
||||
|
||||
当 `access_mode=whitelist` 时:
|
||||
|
||||
1. **实例配置 `allow_networks`**:该实例下所有用户共享的允许网段
|
||||
2. **用户配置 `allow_networks`**:单个用户的额外允许网段(在实例基础上叠加)
|
||||
3. **实际生效** = 实例白名单 ∪ 用户白名单(去重)
|
||||
4. **服务端强制**:
|
||||
- OpenVPN 自动生成 `client-connect.sh` / `client-disconnect.sh` 脚本
|
||||
- 每个用户连接时,服务端的 FORWARD 链插入 iptables ACCEPT 规则,只放行到白名单网段的流量
|
||||
- 其他内网流量在服务端被 REJECT(客户端看到的是"无法连接",而非"超时")
|
||||
5. **客户端推送**:
|
||||
- 自动 `push "redirect-gateway def1 bypass-dhcp"` 让客户端把所有流量都走 VPN(否则白名单没意义)
|
||||
- 自动按白名单 `push route ...` 让客户端知道这些网段在 VPN 后
|
||||
|
||||
> 双重防护:即使客户端操作系统被绕过,iptables 仍会拒绝非法流量。
|
||||
|
||||
## 使用方法
|
||||
|
||||
### Web 端
|
||||
|
||||
1. **实例管理 → 新建/编辑实例**
|
||||
- "访问控制"下拉选 **"白名单(whitelist)"**
|
||||
- "允许网段"标签输入:每行一个 CIDR,如 `192.168.1.0/24`、`10.0.0.0/8`
|
||||
- 保存
|
||||
|
||||
2. **用户管理 → 编辑用户**(可选)
|
||||
- "额外允许网段":这个用户特有的、实例未列出的网段
|
||||
- 保存
|
||||
|
||||
3. **启动实例** —— 实例启动时,会执行一次 `iptables -A FORWARD -i tunX -j REJECT`(仅白名单模式)作为兜底
|
||||
|
||||
### 命令行(API)
|
||||
|
||||
```bash
|
||||
# 创建白名单实例
|
||||
curl -X POST http://localhost:8089/api/instances \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{
|
||||
"name": "internal",
|
||||
"port": 1194,
|
||||
"subnet": "10.8.0.0/24",
|
||||
"access_mode": "whitelist",
|
||||
"allow_networks": ["192.168.1.0/24", "10.0.0.0/8"]
|
||||
}'
|
||||
|
||||
# 创建用户,额外允许一个网段
|
||||
curl -X POST http://localhost:8089/api/instances/$IID/users \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"username":"alice","allow_networks":["172.16.0.0/16"]}'
|
||||
```
|
||||
|
||||
## 验证白名单生效
|
||||
|
||||
实例启动后,登录客户端:
|
||||
|
||||
```bash
|
||||
# 1. 客户端连上 VPN,确认 VPN IP 拿到
|
||||
ip addr show | grep 10.8.0
|
||||
|
||||
# 2. 测允许的网段 - 应通
|
||||
ping 192.168.1.1
|
||||
|
||||
# 3. 测未允许的网段 - 应 REJECT(ICMP net unreachable)
|
||||
ping 192.168.50.1 # 不在白名单,应该不通
|
||||
```
|
||||
|
||||
服务端验证 iptables 规则:
|
||||
|
||||
```bash
|
||||
iptables -L FORWARD -n --line-numbers
|
||||
# 应看到 -i tun0 -j REJECT 在底部,前面若干 -s <vpn-ip> -d <allowed-net> -j ACCEPT
|
||||
```
|
||||
|
||||
## 限制与注意
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | ---- |
|
||||
| 仅 IPv4 | IPv6 白名单需要扩展 client-connect.sh 使用 `route-ipv6`,目前未实现 |
|
||||
| 需要 root + iptables | 若运行在容器内/无 root,白名单模式会以"open"模式退化运行 |
|
||||
| 端口转发必须由客户端发起 | 客户端连入后,服务端只允许它主动访问白名单中的目标;不能用 VPN 当跳板从外部进入内网 |
|
||||
| 修改 allow_networks 后 | 已有用户需重新连接一次才能拿到新的 push route;新用户即时生效 |
|
||||
| 删除/吊销用户 | 会清掉 iptables 中对应的 ACCEPT 规则,不影响其他用户 |
|
||||
|
||||
## 常见误用
|
||||
|
||||
| 错误 | 后果 |
|
||||
| ---- | ---- |
|
||||
| 客户端关掉 VPN 网关 | 服务端 iptables 仍会拒绝非白名单流量,客户端访问不到 |
|
||||
| 客户端把 allowed 网段路由改成另一条 | 服务端 iptables 在 FORWARD 链过滤,客户端改路由无效 |
|
||||
| 忘记添加 DNS 服务器 | 客户端没法解析域名 —— 在"允许网段"加上 DNS 服务器的 IP(如 `8.8.8.8/32`) |
|
||||
|
||||
---
|
||||
|
||||
# 三、客户端使用
|
||||
|
||||
## 配置文件说明
|
||||
@@ -517,7 +623,7 @@ sudo dnf install -y NetworkManager-openvpn NetworkManager-openvpn-gnome # F
|
||||
|
||||
---
|
||||
|
||||
# 四、API 参考
|
||||
# 五、API 参考
|
||||
|
||||
所有 `/api` 路径(除 `/login`、`/health`)都需要 `Authorization: Bearer <token>`。
|
||||
|
||||
@@ -559,7 +665,7 @@ curl -X POST http://localhost:8089/api/instances \
|
||||
|
||||
---
|
||||
|
||||
# 五、常见问题
|
||||
# 六、常见问题
|
||||
|
||||
**Q: 服务启动后访问 8089 提示"无法连接"?**
|
||||
|
||||
@@ -621,7 +727,7 @@ server {
|
||||
|
||||
---
|
||||
|
||||
# 六、开发
|
||||
# 七、开发
|
||||
|
||||
```bash
|
||||
# 后端
|
||||
|
||||
Reference in New Issue
Block a user