AWS Client VPN 端点 DNS:为什么固定解析出的 IP 会失效
把 AWS Client VPN 端点的名称换成你解析出的地址,隧道之后就会停止工作。请保留导出时的名称及其随机前缀。
上周,dig +short 为你的 AWS Client VPN 配置文件里的端点名称返回了一个地址,隧道也连上了。这周同一个配置文件在你的笔记本上停在“Connecting”,而同事那份没动过的副本仍然可用。没有任何东西被封锁,证书也没有过期。有人把端点主机名换成了那个解析出来的地址,服务就不在那里应答了。导出时拿到的名称,正是为了扛住这种变化而设计的部分。
配置文件里的名称未必是被查询的那个名称
从 Client VPN 导出的配置文件通常带有 remote-random-hostname。打开该选项后,客户端会构造一个一次性标签,用点号把它和端点名称拼在一起,再解析这个组合名。端点所在区域的通配符记录会回应任意标签,所以凭空编出的前缀照样能解析,也正是这个原因,当你手动复现查询时,这一手法看起来毫无痕迹。
因此,当你把端点名称粘贴到终端并得到答案时,你解析的是另一个名字,而非客户端连接时使用的那个名字。这一不一致并不是配置文件里需要修正的缺陷。标签是有意重新生成的:该选项让缓存无法保留过期答案,而且它永远不会标识你的机器或会话。
我遇到过客户端完全忽略该选项的兼容性情况。AWS 记录了变通做法:保留真正的端点名称,并在前面加上一串随机字符和一个点,把它当作命名模式,而不是一个可以粘贴的值。把这一做法用在旧客户端上是合理的;把带前缀的字符串硬编码为端点则不合理。
为什么保存下来的答案无法一直正确
Client VPN 端点地址由 AWS 管理,会随时间变化,最佳实践文档对此说得很直白。抓到的答案只是一次解析的快照。把答案写死,服务一迁移,配置就指向了已下线的机器,而故障看起来很少像 DNS:你会得到连接超时或卡住的握手,于是人们去追路由和证书。
同一个答案写进 /etc/hosts 也会继承同样的失效,还多一个问题。hosts 条目能扛过重启、重新导出和“重装客户端”,所以地址一变,故障就回来。我见过一条记录几周里毫无影响,随后让所有带着它的机器集体失联,而全新安装的机器却正常连接。同一账号里一组故障、另一组正常,这种分化是你能拿到的最便宜的线索。
随机化的范围也要弄对。它发生在每次连接尝试。已建立的隧道不会重新解析端点,不会在会话中途切换服务器,单个应用请求也不会各自挑选新的 VPN 主机。只有下一次尝试才会重新解析,所以一个下午都正常的会话,说明不了明天早上会怎样。
隧道建立时服务会检查什么
Client VPN 要求你连接的地址与端点 DNS 名称解析出的某个地址相匹配。这一条要求解释了几种看似无关的故障:指向别处的自定义 DNS 记录、把流量转给真实端点地址的自定义前端,以及被改写成裸地址的配置文件。AWS 把“自定义记录加转发”这一组合记录为在较新 AWS 客户端上的故障。这项检查很窄;它并不是说所有别名都被禁止。
它也不是关于 VPN 协议的通用规则。数字形式的 remote 在普通 OpenVPN 部署里完全合法,很多部署就是这么跑的。约束来自受管的架构,而不是底层协议。
也正因如此,放宽证书校验是错误的反射动作。如果地址更换后配置文件失败,关掉服务器校验只是把错误挪个位置,既没有修好解析,也没有修好地址匹配要求,还留下一个什么都信的客户端。导出拿到的 CA、服务器校验和双向认证设置,请原样保留。
允许列表、出口与私有 DNS 是三个独立问题
笔记本连接之前必须先放行目的地的防火墙规则,针对的是外层监听。把端点名称、传输方式和配置端口交给网络负责人,再问他们的管控能否跟随服务的 DNS 行为。只记住一个抓来的地址的规则,是一张没写有效期的快照。如果管控只接受不可变的目的地,就在上线前把这个缺口定下来,而不是悄悄写死一个答案。
需要在隧道建立之后发出的请求拥有固定源地址的伙伴,诉求不同:那是出口。网站看到什么,取决于应用路由和拆分隧道策略,而不是客户端连到了哪个地址。走拆分隧道的流量可能根本碰不到 AWS。
隧道内部的私有 DNS 是第三层。下发给客户端的解析器在连接之后回答内部名称;隧道建立之前,它无法解析公网端点。端点解析失败与内部应用解析失败发生在不同阶段,混在一起就会把你引到错误的日志。
地址族也属于同一类清单。IPv4 的答案说明不了 IPv6 或双栈端点允许走哪条路,所以在一个地址族里拍下的快照,不能当作另一个地址族的证据。
在不固定任何东西的前提下检查一次连接
从导出原样的配置文件开始,读它实际要求什么:
grep -nE '^remote|remote-random-hostname' profile.ovpn
dig +short cvpn-endpoint-ID.prod.clientvpn.REGION.amazonaws.com
ss -tnp | grep -E ':(443|1194)'然后比较三样东西:配置文件里的端点名称、客户端为一次新尝试报告的地址,以及这个名字现在解析成什么。解析成功只证明记录有应答;传输与认证是分开的,端点也不必回应 ping。中间那一项只有客户端自己的日志能提供,所以要在尝试过程中抓,而不是事后补。
| What you see | Usual cause | Next check |
|---|---|---|
| One machine fails, others connect | Pinned address or stale hosts entry on that machine | Diff its profile and hosts file against a working copy |
| Everyone fails at once, no config change | The endpoint address rotated | Confirm the current endpoint configuration with the account owner |
| Tunnel up, internal names fail | Client DNS policy, not endpoint resolution | Inspect the resolver pushed after connection |
今天能应答的地址只说明今天;名称才是服务持续维护有效的东西。把观察记下来,发给端点的主人,让配置文件继续指向名称。
要丢掉两个习惯:为了绕过卡住的握手而去关证书检查,以及抱着“总有一个能粘住”的心态在端点名称前堆标签。标签要么通过通配符记录解析成功,要么问题就在别处。配置正确的配置文件仍然失败时,请提供准确的查询和连接事件,而不是一个更长的主机名。
收尾之前:配置文件仍然带着导出时的端点名称,没有任何 hosts 文件固定该地址,客户端日志里的 remote 与当前解析一致,防火墙规则点名的是端点而不是地址。这也是要交给下一个人的状态。