📌 转载说明:本文首发于微信公众号《闫工的算力工具箱》 原文链接:https://mp.weixin.qq.com/s/e43aRRzPR3wexjmA0OkkcQ
【闫工的工具箱 · 第 24 弹|提效干货】#
大家好!我是闫工。
我们这边多客户通过 SSLVPN 接进来,各自访问自己的裸金属服务器。每加一个访问需求,客户提工单 → 我排期 → 手工登录防火墙敲命令。一个“就加一个 IP”的需求,客户得等我半天。
更麻烦的是越权和留痕。图省事直接授权一整个 /24 段,客户就能横向摸到同网段其他机器;规则加多了以后,同一条策略被不同客户各建好几条,规则表越滚越乱;出问题了想查"谁在什么时候改了什么",翻不出来。
后来我干脆做了个门户:客户自己提交,后端自动下发,全程留痕。这篇把架构、设计、踩的坑都写出来。
— — —
先说说人工开白名单到底烦在哪#
| 痛点 | 具体表现 | 后果 |
|---|---|---|
| 效率低 | 客户提工单 → 我排期 → 手工登录敲命令 | 一个简单开通要等数小时 |
| 易越权 | 为省事直接授权整个 /24 网段 | 客户可横向访问同网段其他机器 |
| 规则碎片化 | 同 server、同 port 被多个客户 IP 各建一条 | 规则表爆炸,没人敢动 |
| 无审计 | 手工操作不留记录 | 出问题追不到人 |
四个问题里,越权和碎片化是最要命的——前者是安全风险,后者是维护灾难。所以这个门户不只是"把工单搬到网页上",核心是把规则模型重新设计一遍。
— — —
这个门户长什么样#

图:客户经 SSLVPN(或可选域名)接入门户 VM,门户后端 SSH 到防火墙管理口下发白名单,防火墙双机 RBM 主备自动同步
访问路径有两条:
直连
客户连上 SSLVPN 后,浏览器直接访问门户的静态 IP(在 Trust 区);
域名(可选)
经一台 docker nginx 反代到门户 443。这条路有个坑,后面第五节讲。
下发路径是:门户后端用运维账号 SSH 到防火墙管理口,调用 H3C 命令生成或撤销白名单,防火墙双机通过 RBM 从主同步到备。整个过程客户看不到命令,也不需要知道防火墙在哪。
几个关键组件:
| 组件 | 干什么的 |
|---|---|
| 门户 VM | Web 界面 + 后端脚本 + 数据库,库里存 legacy / active 两套策略数据 |
| nginx 反代 | docker 部署,接入可选域名 |
| 防火墙 | H3C F5000 系列,白名单策略 + 14 个 wg_*_src 源对象组 |
| 数据库 | 策略双轨:legacy(老规则)→ active(迁移后),迁移期并行 |
📌 为什么要有两套数据?迁移不是一次做完的,得分批。legacy 是历史遗留的散乱规则,active 是迁移后的规范规则。每迁完一批就核对一次,核对通过才把 legacy 那批作废。这样迁移能分批推进,不用停机切换。
— — —
核心设计:一条规则管一批 IP#
这是整个项目里我想得最久的一个点。
按"客户 + IP"逐条建规则的后果是什么? 同一台服务器、同一个端口,被多个客户的 IP 各建一条 rule,规则表很快爆炸。
我的做法是共享规则模型:同一组 (server, port) 的多个授权 IP,共用一条 rule,IP 的差异下沉到源对象组(src object-group)。
举个例子:多个客户都要访问 10.27.0.1:9203,那就只维护 1 条 rule,把各客户 IP 都加进同一个 src 对象组;也可以按客户拆成 wg_客户_src 组,让一条 rule 引用多个组。
这套模型我在真机上验证过,提交和撤销的全链路行为正确。
还有一条容易被忽略的规则:提交的 IP 一律按 /32 归一,存裸 IP(不带 /32 后缀)。
理由很实在:同一个 IP,如果有时写 10.27.0.1、有时写 10.27.0.1/32,在做比对和去重的时候就会被当成两个不同的地址,规则碎片就是这么来的。
— — —
门户怎么用:批量提交、双角色、审计留痕#
批量提交:单条失败不影响其他#
- 输入框支持逗号分隔多个 IP,中英文逗号都认(兼容不同输入法);
- 逐个 IP 校验,单个失败不影响其他——成功的正常入库,失败的单独提示;
- 提交后弹 loading 模态框,预期 30~45 秒,因为后端要真的 SSH 到防火墙上把策略下发下去。
双角色门户#
左侧菜单按角色动态渲染,客户看到的和管理员看到的完全是两套:
| 角色 | 菜单项 |
|---|---|
| admin | 开通新客户 / 客户列表 / 审计日志 |
| 客户 | 添加白名单 / 我的白名单 |
还有个减少退回工单的小设计:按客户预置必填项提示。比如某个客户必须带端口 12222、9203,某个客户必须授权某个特定服务器 IP 以防规则碎片——客户一登录,页面上就醒目提示,不用我每次口头交代。
审计留痕#
提交和撤销操作全部写审计日志,admin 可按客户、时间查询。
撤销走的是"在已有规则上增删成员"的语义(add_to_existing),而不是重建整条 rule——这样既保留规则连续性,也不会因为撤销操作引入新的规则 ID。
— — —
我踩的坑:一个 /32 引发的撤销失效#

图:表单提交时的校验提示——源 IP 若不在该客户任一授权网段内会被拒绝,并明确提示当前授权网段
这是整个项目里最值得记的一个坑,而且是真机验证时才暴露的。
现象:共享规则模型在真机验证时,提交 /32 授权正常,但撤销之后防火墙上规则还在。
排查过程:提交成功、撤销命令也执行了、防火墙没报错,但规则就是没掉。
根因:生成规则地址行的函数,对 /32 生成的是
subnet 10.27.0.1 255.255.255.255而生成撤销行的函数,对同一个地址生成的是
host 10.27.0.1两条命令的写法不对称。防火墙是按字面写法匹配的,撤销命令找不到对应条目,于是静默失效——连个报错都没有。
修复:统一 /32 在正向与撤销路径下的写法,要么都用 host,要么都用 subnet 255.255.255.255,保证可逆。
⚠️ 闫工经验谈:凡是"生成—撤销"成对出现的脚本逻辑,必须真机正反各跑一遍。只验证正向下发,一定漏掉这类不对称 bug。
顺带还有个小坑:传入 10.27.0.1/32 时解析服务端 zone 报错,原因是 ip_network() 默认 strict 模式,对带主机位的 /32 后缀会抛异常。改用 ip_network(strict=False) 就好了。
这两个坑其实是一个源头——代码内部对 IP 的表示没统一。一处按裸 IP 处理,一处按带掩码处理,两边就会打架。所以前面说"提交的 IP 一律按 /32 归一存裸 IP",不只是为了去重,也是为了少一类 bug。
— — —
客户那边怎么用#
前提是已经连上 SSLVPN。
登录
浏览器访问门户地址,输账号密码;
首次登录强制改密
初始密码必须先改;
添加白名单
填服务器 IP、端口、源 IP。源 IP 支持批量逗号分隔,中英文逗号都识别;单个 IP 失败不影响其他;
等待下发
提交后弹 loading,后端 SSH 到防火墙下发,预期 30~45 秒;
在我的白名单核对
查看已提交与已生效的记录。
撤销在「我的白名单」里选条目操作,生效时间跟下发一样,30~45 秒。
还有一个坑:内网域名接入。最后的落地方式是本机 hosts + docker nginx 反代的 conf.d 配置,内网通过 hosts 访问生效。
客户侧的使用流程就这么简单。如果你想在自己的环境里搭一套,下面这几个部署要点可以参考。
— — —
部署要点#
| 项 | 配置 |
|---|---|
| 系统 | Ubuntu 22.04,nginx 监听 443(TLS)反代到本地 uvicorn 127.0.0.1:8000 |
| 应用 | FastAPI + SQLite(wl.db),systemd 托管 |
| 下发通道 | 门户后端以运维账号 SSH 到防火墙管理口,调用 H3C 命令(Paramiko / Netmiko 建通道) |
| 双机冗余 | RBM 主 → 备 auto-sync;备墙要单独镜像运维账号和对应规则段 |
双机这块有个容易漏的点:主备同步的是策略配置,但运维账号、特定规则段这些要单独在备墙上镜像一份。否则主墙故障切过去,门户的下发通道直接就断了——客户点提交,卡在 loading 上转圈。
— — —
老规则迁移和权限收紧#
迁移是分批做的,五步:
建源对象组
用运维账号建 14 个
wg_客户_src对象组;老规则改名 + 源对象组化
8 家客户全部完成,交付一份命名对照表(旧规则名 ↔ 新对象组);
DB 对齐
legacy → active 逐客户核对。比如某客户 13 条、另一个客户 5 条(端口 12222、9203 要对齐)、再一个客户 11 条,还有客户的 server_ip 需要修正;
清理冗余
删掉某客户的 41 条冗余规则,既消除数据冗余,也消除潜在权限风险;
权限收紧:/24 → /32
7 家客户的授权网段从 /24 收窄到实际裸金属的 /32,消除横向越权;同时补上遗漏的服务器条目,把授权只留实际需要的那一个 /32,从源头掐掉规则碎片。
先在单个客户上跑通全链路试点(提交 + 撤销,含 add_to_existing 语义),确认无误后其余客户分批迁移。
— — —
这套门户解决了什么#
客户不用等我
提交即下发,30~45 秒生效,不用走工单排期
越权从根上堵住
授权粒度收到 /32,“顺手给个 /24"这种事在门户上做不出来
规则不再爆炸
共享规则模型 + IP 归一,规则表从"没人敢动"变成"看得清”
留痕可查
谁什么时候提交了什么、撤销了什么,admin 一查就有
可分批迁移
legacy / active 双轨,不用停机切换
技术栈很轻:FastAPI + SQLite 就够,一个人能维护
— — —
结尾 · 互动#
你们那边的白名单、防火墙策略是怎么管的?直接通过CLI还是netconf实现?如果也在做类似的事,踩过什么坑,评论区聊聊。
📖 推荐阅读