为什么 Azure 上的 VPN 设备虚拟机会丢失回程路径
Azure 虚拟机中的 VPN 设备需要 UDR、网卡转发标志和客户机策略三者一致。跟随一个分支请求走过这三处。
运行 VPN 设备的 Azure 虚拟机身处两个彼此独立的决策系统之中。数据包从哪个子网离开,由 Azure 用路由表和网卡转发设置决定。是否把解密后的数据包继续转发,由设备自身的操作系统决定。一条建立得完美无缺的隧道,仍然可能在第二个系统上失败,而多数此类部署就停在这里。
一条路径的三个归属方
取一个分支网络 192.168.50.0/24 和一个工作负载子网 10.0.10.0/24,设备位于 10.0.0.4 在其自己的子网中。一个请求会触及三处独立的配置。
| Decision | Configured in | How it fails |
|---|---|---|
| Where the workload subnet sends branch traffic | Azure route table entry | Traffic leaves the subnet and never reaches the appliance |
| Whether a NIC may accept traffic not addressed to it | Azure NIC IP forwarding | Packets arrive and disappear at the interface |
| Whether the guest forwards decrypted traffic | Guest OS or vendor appliance policy | Tunnel is up, workload is unreachable |
| Whether the workload accepts the source | NSG and service policy | Requests delivered, replies refused |
在多数组织里,每一行都由不同的团队负责,所以这个故障通常以三张工单而不是一张的形式出现。
指向设备的那条路由
把路由表关联到工作负载子网,并为分支前缀指定类型为 Virtual appliance 的下一跳,地址是 10.0.0.4 。请使用设备可达的私有地址,绝不要使用 它面向公网的 VPN 入口。下一跳必须是工作负载子网已经能够到达的地址。除非你有意决定替换默认路由,否则不要改动工作负载其余的路由设置。
把设备保持在它自己的子网中,并确认把分支流量送往设备的那条路由,不会同时把设备自身的出站路径也一并捕获。这样的环路看起来像一条没有任何回应的健康隧道,而在凌晨 2 点排查它实在令人痛苦。
所有人都忘掉的网卡标志
Azure 有一项按网卡设置的 IP 转发开关,默认是关闭的。它之所以存在,是因为转发型网卡会收到并非发给自己的数据包,而对其他所有人来说,静默丢弃这些包才是安全的默认做法。
az network nic update --resource-group rg-net --name appliance-nic --ip-forwarding true 会为一个网络接口打开这个开关。Microsoft 的 网卡转发指南 要求在每个承担转发的已附加网卡上都设置该项,所以只有一块网卡的设备仍然需要在这块网卡上设置它。
这个标志不是路由,也不是防火墙规则。打开它只授予许可,别的什么也不做。
客户机对解密后的数据包做什么
隧道终止之后,设备自身的协议栈来做下一个决定。在 Linux 客户机上,IPv4 转发是一个运行时设置,并且 sysctl -w net.ipv4.ip_forward=1 只维持到下次启动。改为把它持久化到 /etc/sysctl.d/ 下的一个文件里。厂商设备的等价机制各不相同,而把 Linux 的说明照搬到厂商平台上,通常完全不起作用。
客户机的防火墙策略又是另一回事,工作负载的网络安全组也是。允许 UDP 500 和 4500 到达虚拟机的公网地址,只是保护了隧道;它并不能说明一个解密后的分支请求能否到达工作负载的某个端口。
跟随一个请求和它的回应
挑一条被允许的流量,从头到尾追一遍。分支需要一条通往 10.0.10.0/24 的路由,经由站点连接;设备需要一条通往工作负载子网的投递路径;工作负载子网则需要一条回到分支的回程路由。
尽早决定:设计是保留分支的源地址,还是对它做地址转换。NAT 会改变工作负载看到的东西,所以它的访问规则应当描述你真正选择的模型,而不是一个猜测的网关地址。
一次成功的握手只能证明那条链路上的一环。当回应经由同一台设备返回,并且工作负载自身的策略允许它通过时,路径才算完整。