服务启动了,客户端也连上了,可服务器端始终不出现路由。或者守护进程拒绝启动,并报出一个无法执行的命令。两种结果都出自同样的三行配置,而这三行通常是照着加固指南一起抄来的:切换到非特权账户、放弃用户组、更改文件系统根目录。三者中只有一项会隐藏文件,也只有一项 剥夺修改路由表的权限。把它们拆开来测,你才知道自己真正想要哪一行。

监狱取走了什么,而守护进程仍然需要

更换根目录发生在启动之后,所以守护进程保留已经打开的一切,却失去之后才会打开的一切。此后连接所运行的任何辅助程序,都必须存在于新根目录之内,连同它加载的共享库。只用配置文件和证书搭起来的监狱,两样都没有。

切换到非特权账户是另一项限制。交出 root 的进程即使二进制就在旁边,也可能无法修改路由或拉起网卡,因此这两种故障必须分开排查。

三个条件决定你需要哪种修法

第一个条件是你的构建如何安装路由。较新的 OpenVPN 版本在进程内配置网卡和路由表,而较旧的软件包和自定义配置则依赖外部工具,或依赖 up 与 down 脚本。如果日志报出某个命令,说明涉及外部工具,是监狱把它藏了起来。如果日志报的是权限错误,那问题就在账户上。

第二个条件是维护。复制二进制的监狱必须在提供它们的软件包每次升级时刷新,否则第一次升级就会留下一条断掉的隧道。第三个条件是某项控制是否真的需要 chroot;如果这项要求其实只是权限分离,那么只切换账户可能就够。

Signal in the logOther side of the boundaryRepair direction
Command not found after startupBinary and its libraries absent inside the new rootPopulate the jail, or drop the chroot line
Operation not permittedAccount lost the privilege to edit routesKeep the account privileged, or pre-create routes elsewhere
No such deviceJail lacks the tun device nodeCreate the node inside, or open it before the root change

一个能用的监狱必须包含什么

运行命令的监狱需要二进制、它链接的每一个库,以及守护进程稍后才打开的每个设备节点。把这些部件复制进去,在没有 VPN 的情况下单独测试:

ldd /usr/sbin/ip
chroot /etc/openvpn/jail /sbin/ip route show
chroot /etc/openvpn/jail /sbin/ip link set tun0 up

第一条命令列出依赖,而这一条恰恰最常被跳过。复制进来的二进制找不到库时,报错与二进制缺失并不相同,而从客户端看,两者都像 OpenVPN 故障。在监狱里手动运行该命令,不用重启服务就能复现故障。

把配置、证书和任何 CRL 也一并复制进监狱,因为守护进程期望在启动后重读的文件,一旦根目录变了就找不到。记下复制了什么,因为网络软件包的下一次升级会替换原件,把监狱留在旧副本上。

反过来缩小加固范围

如果监狱只是因为某份指南这么写才存在,那么删掉那一行、保留账户限制,是站得住脚的结果。守护进程保住自己的文件系统视图,问题也消失了,而降权仍然把 root 从长驻进程中拿走。

把剩下的写下来,也写下理由。配置悄悄丢了一项控制却没有备注,加固就是这样走偏的,而下一次审计会问那一行为什么不见了。

选择之前先把三行拆开

复制配置,禁用全部三条指令,确认客户端能连上、预期路由出现。然后再只启用账户相关的行,最后单独启用 chroot。 隧道在哪一步断掉,边界就在哪里,这样你就不必重建一个从来不是原因的监狱。

恢复路由之后,以更高的日志级别跑一次客户端会话,读出那条指明命令或权限失败的行。这一行比客户端最终报告的超时更有价值。

相关文章