一个能连上却什么都访问不到的 VPN,通常会被描述成防火墙问题,而人们习惯采取的补救办法是把隧道接口放进受信任区。这样做在流量能走通这个意义上确实有效,但它同时放行了远多于预期服务的流量。这里涉及的两套策略并不相同:一套放行外部传输到达正在监听的套接字,另一套授权解密后的流量到达某个具体资源。把它们当成同一个设置,正是把窄放行变成宽放行的原因。这两件事在不同的地方决定,所以这个错误才如此容易发生。

两套策略,一条隧道

外层策略回答一个简单问题:来自这个源的报文能否到达本机的 UDP 1194?内层策略回答另一个问题:该隧道背后已通过认证的客户端能否以这个协议、在这个端口上到达这个目标?前者关乎套接字,后者关乎路径,firewalld 用不同的对象来建模,因为它们在各自不同的环节被决定。一个是本机套接字的属性,另一个是穿过它的路径的属性。

实际后果是:隧道能通,说明不了第二套策略的任何情况;而第二套策略正确,也不会让第一套变得多余。

放行真正的对外监听

先检查已经分配了什么,而不是先假设。读取活动区域,列出真正承载入站流量的区域,并查看已安装的服务定义,因为服务名称描述的只是一组端口,并不能说明本机监听是否与之匹配。

firewall-cmd --get-active-zones
firewall-cmd --zone=public --list-all
firewall-cmd --info-service=openvpn

如果监听确实在该区域上是 UDP 1194,就精确地打开那个端口和传输方式,然后在测试之后把同一条具体规则持久化。也要检查基于源的分配,因为绑定到源地址段的区域可能在接口区域看到流量之前就先截住它。

单独授权解密后的目标

连接到运行在 VPN 服务器自身上的服务,属于本地输入策略。转发到局域网内另一台主机的连接则需要转发策略,需要内核中启用的转发,以及一条回程路由——这三项是彼此独立的要求,人们却常常把它们并成一项。现代 firewalld 的策略对象描述入口区域与出口区域之间的定向流量,那里才是表达哪些 VPN 源可以到达哪些私有服务的合适位置。

明确列出允许的源,其余一律落到拒绝。对外部服务的放行并不是那套策略,无论区域布局看起来多么像。

为什么信任接口是错误的捷径

把隧道接口放进一个目标为全部接受的区域,会让所有解密流量到达主机暴露的每一项服务,包括你还没审查过的服务。在运行中的机器上把受信任区改成限制性的做法更糟,因为其他接口和源地址段可能已经依赖它的含义,你一改行为就会变。若需要窄策略,就新建一个;不要改造共用区域。

还要保证隧道区域的分配在拥有该配置的组件上保持稳定。重启时丢失分配会产生一种故障,看起来像防火墙规则问题,实际上却是持久化问题。

验证三件事,其中包含一次拒绝

从外部测试外层连接,从已连接的客户端测试一个已授权的内层服务,再测试一个应当保持不可达的服务。第三项测试才是区分策略与副作用的那一项,也正是人们因为看起来都正常而跳过的那一项。如果被拒绝的服务仍有回应,说明你放行的是一个区域,而不是一项服务。

把区域、端口、传输方式和策略对象记进服务器笔记。否则下次改动这台主机时,又会从同一个猜测开始。

相关文章