上游 VPN 之后的下游客户端:路由还是 NAT?
上游 VPN 只认识客户端地址,因此转发另一个子网需要约定的路由或刻意的源地址转换。
一台网关为自己的设备运行 WireGuard,同时以 OpenVPN 客户端连接别人的网络。两个内网接口之间的转发能工作,于是很容易得出结论:下游子网现在已属于上游服务。并非如此。客户端拉到的路由只告诉网关把请求发往哪里,却完全没有说明远端网络如何把流量送回它从未听说过的设备。在添加任何一条规则之前,先选一种上游真正支持的返回模型。
先定返回模型,再动路由
在本文示例中,下游客户端使用 10.90.0.0/24,分配给网关的上游隧道地址是 10.80.0.6,已获准访问的远端资源是 172.20.0.30。有两种模型适合这种形态:保留下游源地址并让远端为其路由,或者 把源地址转换为网关自己的隧道地址。这个决定之后的一切都是机械操作,而决定本身需要服务方的负责人。上面两行中,一行是与远端的路由约定;另一行是你可以自行完成的本地策略变更。把两者混为一谈,正是十分钟的改动变成一场谈判的原因。
preserved: 10.90.0.23 -> 172.20.0.30
translated: 10.80.0.6 -> 172.20.0.30选一行并坚持下去。两行是备选方案而非步骤,混用会做出没人能在评审时解释清楚的设计。
路由式源地址保留
远端收到来自下游地址的请求,因此它需要一条受支持的路由、对该子网的 peer 归属,以及接受它的授权。这些都是远端设置,本地 Linux 路由无法创造它们。要明确地、书面地申请,写清前缀和承载它的隧道 peer,并预期答复取决于该服务是否支持站点到站点安排。
如果答复是可以,本地配置很小:开启转发、把 WireGuard peer 的 allowed-ips 覆盖下游网段,并用防火墙策略允许两个方向穿越。
刻意的源地址转换
如果服务只把流量送回已连接的客户端地址,就在出方向把源地址转换为该地址,并保留为回复做反向转换的 conntrack 状态。把规则限定在预期的下游源、预期的远端目的地和上游接口上。转换所有接口所有出向流量的规则,比这个需求大得多,日后会让你吃惊。
IPv6 需要单独设计;照抄一行 IPv4 masquerade 不是架构。测试转换后的路径要用新连接,而不是缓存中的连接。
本地数据路径仍要能用
转换并不能免除本地工作:网关仍需要通往下游目的地的路由、正确的 WireGuard peer 源归属、已开启的转发,以及接口之间较窄的防火墙策略。在网关本机发起的请求不会检验上述任何权限,这正是网关本地测试通过、下游设备仍然失败的原因。
要从真实的下游设备测试,而不是从网关测试。源地址正是这项练习的全部意义。
一个源意味着一个会话身份
远端服务看到的是网关已认证的会话及其转换后的地址,而不是每个下游设备各自的认证。要把按设备的权限与应用身份写清楚,并向服务方负责人确认:让一台网关代表多台设备究竟是否被允许。转换不是绕过按设备注册要求的办法;如果服务要求每台设备都要注册,就用那种模型,或去谈站点到站点安排。
把这份确认写在 runbook 里、紧挨着规则,因为下一位评审会问:这个设计是被批准的,还是只是图方便。
先定义断线状态,再测三种请求
要决定上游隧道断开时会发生什么。在禁止的地方,已授权的远端流量不应悄悄走普通 WAN 备用路径,因此允许穿越的防火墙策略也应当在失败时保持关闭。然后从真实的下游设备测三种情况:一个能通过的允许请求、一个会失败的禁止请求,以及一次让允许请求中断的上游故障。
每条规则用一行记录回滚办法,这样撤销改动时不必重建当初的意图。