桌面图形界面持有管理连接,所以想自己开一条连接的监控脚本什么也读不到,更糟的是界面不再响应提示。常见的结论是守护进程不稳定。在社区版守护进程里,这个限制是设计使然:控制接口一次只服务一个已连接的管理客户端,而这个数字与 VPN 能承载多少用户毫无关系。

一个套接字,一个持有者

管理通道只接受一个已连接的客户端。当第一个仍处于活动状态时来了第二个,它要么等待,要么被拒绝,并不存在藏在某个选项后面的并行订阅模式。断开当前持有者会让守护进程接受下一个,这是一次交接,而不是第二条通道。

这让每个额外工具都成了竞争者。如果图形界面持有连接,轮询脚本要么连不上,要么只有在界面放弃之后才能连上,而且这个顺序在下次重连时还会重演。如果脚本先连上,图形界面就失去了控制路径,它的提示也随之失效。两个工具都不会报告冲突,因为每个只看得见自己失败的那条命令。

What you needMechanism that fitsWhat it cannot do
Periodic list of connected clientsStatus file written on an intervalDeliver events as they happen
Interactive prompts and session controlThe single management connectionServe two controllers at once
Multiple consumers of eitherOne owner process that fans outExist without you writing it

决定由哪个组件持有控制权

为交互通道选一个持有者,并让它成为唯一连接的东西。管理连接的图形界面、应答认证提示的脚本、终止会话的控制器都算持有者,而这个角色只能由一个来担任。

当图形界面持有连接时,使用该界面提供的集成,而不是与它争抢。和持有者争抢套接字会产生间歇性故障,在用户看来像是随机发生的,而调试的人通常只看到竞争的后半段。记下重启后哪个进程先连接,因为这个顺序每次都决定了谁胜出。比界面先启动的监控会一直占着通道,直到界面放弃。

让采集器使用状态快照

大多数监控需要的是一份清单,而不是一段对话。按固定间隔写出的状态文件就能回答这个问题,而且不必触碰控制通道,在图形界面保持连接的同时继续工作。

status /run/openvpn/server.status 10
management /run/openvpn/server.sock unix

间隔就是新鲜度的预算,所以要按照看板真正需要的来设定,而不是取看起来最安全的那个最小值。每隔几秒写一次的快照很便宜;每隔几秒就重连控制套接字的脚本则不便宜,因为每次重连都在和持有者竞争。

快照既不是历史,也不是事件流。在一个间隔内来去匆匆的连接永远不会出现,因此靠轮询一个不断自我覆盖的文件无法满足审计要求。如果你需要知道某个用户到底有没有连上过,快照就是错误的工具。

分发是一种设计,而不是一种模式

如果多个消费方确实需要实时的管理数据,就把一个可信组件放在套接字前面,让它把经过严格挑选的观测结果发布给其余各方。这个组件持有重连、认证提示以及什么可以安全暴露的决定权。

要有意识地构建它:定义允许哪些查询,记录是谁发起的,并避免让分发层意外变成远程控制面板。守护进程没有可以打开的多客户端模式,也没有任何配置行能造出一个。把持有者视为安全边界的一部分,因为它掌握着能断开人们连接的接口。重启它应当是例行操作,并有文档化的恢复路径。

把套接字当作特权,而不是指标

管理接口可以断开用户,改变状态,并读取点名到人的事件。它的密码只用于认证客户端,并不加密传输,因此网络监听者会把这段对话暴露给任何能观察到它的人。

优先使用本地套接字或严格受限的监听器,并检查你的采集器实际指向的是哪个进程,因为服务器产品自带的管理 API 行为并不相同。指向错误守护进程的采集器会得出自信却错误的结论。在调试一个什么都不返回的查询之前,先确认路径和所属进程。

相关文章