每个 Azure 点到站点客户端在通过身份验证时会从地址池里拿到一个地址,并且只在这条连接存续期间保留它。既没有预留表,也没有按用户建立的映射,更没有哪项网关设置表示“永远把 172.16.0.10 给这个人”。正是这同一个机制解释了人们后来撞上的两种症状:一条 NSG 规则不再匹配它从前匹配的用户,以及一份允许清单悄悄放进了没人主动添加的机器。把规则换成更聪明的 IP 规则两种症状都治不了,因为规则所指名的东西,会按一张你并不掌控的时间表被重新分配。

地址池是容量,不是身份。它存在的意义是让并发隧道各自拿到唯一地址,并在租约结束的那一刻把它们回收。想通这一点之后,有用的问题就不再是“我怎么把这个客户端钉住”,而是“我能针对什么写规则,而网关不会把它回收”。

客户端连接时网关到底做了什么

网关持有配置好的客户端地址池,并把它当成一张租约表。连接时它取下一个空闲地址,实践中就是当前可用的最低地址,并把这个地址分配给隧道适配器,直到客户端断开或租约到期。决定结果是顺序而不是身份:在平静一段时间之后第一个重新连上的人,会拿到那一刻恰好空着的最低地址。

地址池的大小会掩盖这一行为。只比测试人数多一两个地址的实验池看起来是确定性的,因为同一台笔记本往往每天早上都按同样的顺序重新连接。加一台机器、改一下池的大小,或者让某个会话连着跨越午休,这个模式就会崩掉。地址从来都不稳定,稳定的是那支队伍。

点到站点配置的任何改动也会重置租约空间。换一种身份验证方式、改过大小的池、新的池网段,或者一座拆掉重建的网关,都会把客户端送回一个已经和它们旧地址对不上的池。那次改动里没有任何一处碰到你的 NSG,所以故障看起来像是自己冒出来的。

这件事大约一分钟就能看到。连上,在客户端的连接详情里记下隧道地址,断开,再连另一台机器,然后把第一台重新连上。你拿回来的地址取决于第二台机器占着什么,而没有任何门户设置能按需把上一个地址还给你。

基于客户端 IP 的 NSG 其实就是一条关于连接顺序的规则

人们最先写的规则很明显:在管理虚拟机的网卡或子网上放一条入站规则,把 VPN 客户端的内部地址当作源。它很短,写的那天就能通过测试,而只要池里不止一个空闲地址,它就会失效。

由此产生两种失效方式,其中只有一种看起来像缺陷。合法用户被拒绝,因为此刻正有别人占着规则所指名的地址,这件事以一张恼人的支持工单形式出现。或者,一个本不该来的用户被放了进来,因为他继承了一个规则仍然信任的地址,而这件事不会以任何形式出现,直到有人去审计访问权限。

由于规则跟着租约走,实际生效的策略读起来是“第一个连上的人获得管理访问权”。这是把连接顺序描述乔装成了意图,任何规则卫生都不会让它变成意图的表达。

客户端租约和网关地址是两回事

大部分混淆来自一个词。网关有一个相对稳定的公网 IP;客户端持有的池内私有地址并不稳定。对于没有区域冗余的 VPN 网关,公网 IP 是动态分配的,但它能扛过改大小、重置和例行维护——只有当网关本身被删除并重建时它才会变。区域冗余和区域级网关 SKU 使用标准 SKU 的公网 IP,而且那次分配必须是静态的。

本地对端在它自己的配置里需要的正是这份稳定性,而它对于识别某一个客户端毫无说明。当合作方问他们会看到哪个地址时,答案是站点到站点场景下网关的公网 IP,或者一个共享的 NAT 网段——绝不会是某台笔记本的隧道租约。

组池给你的是可以放心写规则的网段

虚拟 WAN 点到站点支持用户组,每个组可以被分配自己的客户端地址池。成员资格由身份决定,因此客户端落进哪个网段变得可预测:运维在一个网段,外部承包方在另一个网段,而网段是防火墙或 NSG 规则不必猜测就能指名的东西。

由此得到的规则集有一个可以审阅的形状:

  • 每个受众一个池,按并发会话的峰值来定大小,而不是按人数;
  • 组成员资格靠身份来管理,而不是每来一个人就去改规则;
  • NSG 或 Azure 防火墙规则针对池网段来写,绝不针对单条租约;
  • 对于永远不该共用同一网段的受众,给一个独立的中心或网关。
Rule targetSurvives a reconnectWhat it still cannot express
Client tunnel addressNoFollows connection order and admits whoever holds the address next
Whole client poolYesGrants every connected client identical access
Virtual WAN group poolYesOnly as reliable as group membership
Gateway public IPUntil the gateway is recreatedIdentifies the site, not the person

把整个池放进允许清单是诚实的,但很粗糙:那个网段里每个连上的客户端都拿到同样的访问权。这是一个值得大声说出来的策略决定,而不是在评审时被发现的疏漏。凡仍然需要按人回答的事情,都属于通过角色分配落在资源上的控制,而不属于包过滤。

当部署无法迁到虚拟 WAN 时

许多网关仍然是普通 VPN 网关,而迁到虚拟 WAN 并不是随手一改。务实的答案是:把按用户的判断从包过滤挪到本来就清楚用户是谁的那一层。

资源级身份是最便宜的一种。存储、SQL 和 Key Vault 都支持 Entra ID 身份验证并按用户或按组分配角色,因此 VPN 只需要证明网络可达。带具名账户的跳板机对管理类工作起到同样的作用,因为主机记录了人,隧道只负责搬运数据包。把客户端登记进 DNS 并放行名字而不是号码,等于把规则抬高一层。应用层身份——证书主体、令牌声明、组成员资格——在需要作出判断的是应用而不是网络时发挥作用。

对于坚持要固定源地址的合作方,答案是站点到站点或 ExpressRoute,并给出一个定义好的对端前缀。他们放行对端前缀,出现在他们那一侧的地址属于网关,不会因为有人重启笔记本而改变。

在改下一份允许清单之前,先检查地址池

地址池的两个特性造成了人们归咎于客户端的大部分行为。池太小会让租约回收得很快,于是地址看起来总在移动,任何基于地址的规则都从设计上就显得不可靠。池与本地网段或虚拟网络的地址空间重叠时,会造成路由上的含糊,而没有任何防火墙规则能修好它。

在碰任何规则之前,把三样东西放到同一页上:点到站点池、虚拟网络地址空间、本地网段。它们不能重叠,池要容得下每一个并发客户端,还要留出重新连接的余量。

然后按这个顺序把环闭上:

  • 从两台机器按两种顺序分别连接并对比地址;如果它们可以互换,任何基于地址的规则都不安全。
  • 检查网关是否为虚拟 WAN;如果是,请用组池而不是按地址写规则。
  • 问一句:当规则命中了错误的人会发生什么;如果答案是一起访问事件,就把控制挪到身份上。
  • 把哪个网段属于哪个组,记在和 NSG 定义同一个仓库里。
  • 每次改动池、身份验证或网关之后都重新测试,因为这些改动会在不通知的情况下重写映射。

相关文章