为什么 Azure Point-to-Site VPN 不改变你的公网 IP
点到站点隧道只承载虚拟网络路由,因此在强制隧道和防火墙 SNAT 把出口移到 Azure 之前,你的公网 IP 一直停留在本地。
我在 Windows 笔记本电脑上连接 Azure VPN 客户端,打开一个回显地址的页面,看到的仍是家里路由器分配的那个公网地址。与此同时,10.20.0.4 上的跳板机可以应答,私有终结点名称也能解析,说明隧道并没有坏。点到站点网关只是照着它默认的配置在工作:承载私有前缀,把其余流量全部留在本地链路上。要拿到一个属于 Azure 的出口地址,这是路由设计的改动,而不是一次修复。
网关默认通告什么
网关会推送虚拟网络地址空间的路由,以及允许网关传输的对等网络和通过站点到站点连接或 BGP 学到的本地前缀。这个集合里没有 0.0.0.0/0。你的操作系统把默认路由留在 Wi-Fi 或以太网上,所以发往公网 API 的数据包根本不会进入隧道。
客户端在隧道内拿到的地址,是点到站点地址池分配的私有租约。它用于向 VNet 内的资源标识客户端;它不是互联网能看到的地址,也永远不会作为发往 SaaS API 的出站请求源出现。围绕这个租约去配置允许列表是不可能生效的,无论你等多久让它在服务商日志里出现。
拆分隧道与强制隧道并列对比
| Split tunnel, the default | Forced tunneling | |
|---|---|---|
| Internet traffic exits through | local ISP or office router | firewall or appliance inside Azure |
| Source address the API sees | your home or office IP | the firewall public IP |
| Inspection and logging in Azure | none | policy rules plus flow logs |
| Ongoing cost | gateway only | gateway, firewall hours, data processing |
| What usually breaks | nothing on the egress path | DNS, on-premises routes, overlapping local ranges |
只有第二行会改变远端服务看到的地址。那张表里其余的东西,都是当出口必须在 Azure 内被检查或转换时你要承担的成本和运维面。如果有人要求你让公网 IP 改变,他要的是整个右列,而不是对客户端做一点小调整。
在重建任何东西之前,有一个中间方案值得先说明。在 VNet 内放一台代理或网关虚拟机,可以为那些能被指向它的应用提供一个可控的源地址,而不必移动客户端的默认路由。这样常规浏览仍留在本地,同时又能满足只需要一次 API 调用从 Azure 发出的合作方。当需求实际上是关于全部流量时,这个方案会失败,因为任何忽略代理设置的东西依旧从本地出去。
让隧道承载默认路由
在虚拟网络网关上,把客户端所有互联网流量导入隧道的受支持做法,是往点到站点配置里加入自定义路由。两个半边覆盖整个 IPv4 空间,而且都比本地默认路由更具体,所以客户端无需删除任何东西就会优先选择它们:
Set-AzVirtualNetworkGateway -VirtualNetworkGateway GWOBJ -CustomRoute 0.0.0.0/1,128.0.0.0/1
那一行只是示意,不是可以照抄的完整命令:先用 Get-AzVirtualNetworkGateway 取到网关对象并替换掉 GWOBJ,运行前再确认 SKU 和部署模型接受自定义路由。同样的前缀也出现在门户的点到站点配置页面上;如果你还没有用脚本管理网关,在那里设置更稳妥。
改动这些前缀会让客户端包失效。要重新下载 VPN 客户端包并重装,因为路由是随配置文件一起下发的。用旧配置文件重连的客户端会保留旧路由集,你可能白花一小时去排查一个根本没到达它的改动。
在受保护的虚拟 WAN 中心里,等价做法是在与点到站点网关关联的中心路由表中加一条默认路由,由中心里的 Azure Firewall 接管流量。防火墙会把去往互联网的连接转换成它自己的公网 IP 地址,新的出口地址就来自这次转换。当一台防火墙有多个公网 IP 时,其中任何一个都可能成为源地址,所以允许列表必须把它们全部列上。
上面两种设计都是 IPv4。两个 /1 前缀对 IPv6 毫无作用,而点到站点的 IPv6 支持范围很窄,在承诺对等之前应该先测试这种组合。
先查路由,再查出口
重装客户端包并重新连接后,确认客户端确实装上了两个半边。在 Windows 上,Get-NetRoute -DestinationPrefix 0.0.0.0/1 以及对 128.0.0.0/1 的同一查询应当指向隧道接口,route print 会把两者都显示在你原有默认路由旁边。在 Linux 上,ip route show 必须列出这两个前缀;如果没有,说明配置文件从未带上它们。
随后从客户端再次检查公网地址,并读取同一条连接的防火墙日志。源地址应当是防火墙的公网 IP,端口已做过转换。如果两条路由都在、客户端却仍从本地出去,说明数据包到了 Azure 又从别的路径离开:网关子网上的用户自定义路由、自身被强制隧道回本地网络的防火墙,或者在转换之前就把流量丢弃的策略。
在同一会话里再测一个私有目标。改动之后跳板机突然不应答,是常见的信号:新前缀挤掉了某些东西,要么是先前通告过的更具体的本地路由,要么是现在指向一个没有为你的私有区域配置转发器的解析器。
什么时候该保留拆分隧道
如果目标只是访问一个私有 API、一个私有终结点或一个内部管理页面,默认行为更省钱也更安静。强制隧道会增加防火墙时长和数据处理费用、更长的路径,以及又一个所有客户端流量都可能失败的地方。它抓取的流量也远多于你真正关心的那一个目的地。
当需求是以出口来表述的时候才用它:合作方必须看到一个固定的 Azure 地址,安全团队要求连接被记录和检查,或者数据必须经由一个受控点离开。即使如此,这种设计给每个用户的都是共享出口,所以按用户追责必须来自应用层的身份,而不是源地址。
在结束改动之前,确认四件事:安装的客户端包是新的、两个 /1 路由落在隧道接口上、私有目标仍能应答,以及远端服务的日志里出现防火墙地址。