到达对等 VPC:AWS Client VPN 与 bastion 之选
两条路径都可行,但断裂的位置不同。比较端点路由、回程路由,以及 bastion 成为诚实边界的三种情形。
一个 Client VPN 端点可以到达与其关联 VPC 对等的 VPC,而让这件事合法并不需要 bastion。真正值得做的选择是流量在哪里易手:是落在关联子网、再穿过对等连接的端点路由,还是对等 VPC 里一台终止会话的主机。两条路径都能用,坏掉的位置却不同,所以决定关乎归属与审计,而非 AWS 允许什么。下面是我怎么在两者之间取舍,以及让路由路径成立的四个条目。
两条路径,一个端点,不同的归属
在路由路径上,客户端流量到达端点,被转换成关联子网中 Client VPN 网络接口的地址,再经 A 到 B 的对等连接离开该子网。VPC B 不终止任何 VPN 会话;它看到的是来自 VPC A 的普通流量,所以它的回程路由指向 VPC A,而不是客户端地址池。
在 bastion 路径上,客户端先到达一台主机。A 中的 bastion 仍让最后一跳跨过对等连接,于是你保留了 peering 的工作,又加了一次会话。B 中的 bastion 也需要一条来自客户端的路径,而当这条路径就是同一条端点路由时,你就得到了路由设计再加一跳。只有当 bastion 已经存在、已经获批,并且它背后的东西需要的是会话边界而不是网络边界时,bastion 才真正省事。
四个条目让路由路径成立
AWS 在Client VPN 工作原理页面记录了这个场景,实践中它归结为两三个团队拥有的四个条目。网段只是示例;对等网段必须唯一,回程网段必须与你的规划一致。
| Control | What it must say |
|---|---|
| Endpoint route | 10.70.0.0/16 targets the association subnet |
| Authorization rule | The approved group may reach 10.70.0.0/16 |
| VPC A association-subnet table | 10.70.0.0/16 targets the peering connection |
| VPC B resource-subnet table | VPC A's range targets the same peering connection |
路由与许可是两套独立的控制。端点路由正确但缺少匹配的授权规则,客户端什么也得不到;为端点无法路由的目标配置授权规则,只会给它一个黑洞。两者必须指向同一个网段。
端点路由指向端点自己 VPC 内的子网,绝不指向对等连接。VPC 路由表指向对等连接,绝不指向实例或接口。在两处之间复制一个值,保存时不会有任何抱怨,却什么也不路由。
由于关联子网会转换客户端源地址,B 必须回程路由到 VPC A,而不是客户端地址池。把客户端网段送过对等连接看起来对称,能通过评审,却会静默失败,因为 B 永远看不到源地址属于客户端的报文。
安全组与许可的最后一米
路由只负责把报文送进 B;决定权仍在 B。对于同区域中处于活动状态的对等连接,B 里的安全组可以引用应用到 Client VPN 关联上的安全组,这样规则既窄又能扛住地址变化。在无法引用安全组的地方,应显式放行关联子网的网段,而不是放宽到 0.0.0.0/0,后者会把路由错误变成没有解释的超时。
然后检查路由永远碰不到的东西:两个子网上的网络 ACL、应用的白名单或令牌受众,以及 DNS。对等连接不会复制私有托管区,所以笔记本可能握着一条通向无法解析地址的可用路由,而对等连接也不会给证书增加任何信任。把端点指向能为 B 作答的解析器,再确认私有名称与证书彼此匹配。
何时 bastion 才是诚实的答案
我保留三个触发器来有意识地选择 bastion。对等 VPC 属于一个不会为你的网段添加回程路由、或不接受安全组引用的团队。访问必须逐会话审批或记录,而应用自己承载不了。又或者最后一跳必须留在 B 内,因为服务只在那里解析,其 TLS 身份被钉在一个内部名称上。
这些都不是绕过对等不具备传递性这一事实。非传递性限制的是 B 里的资源能做什么:它们不能把 A 当作通往与 A 对等的第三个 VPC 的中转。它从来不意味着 VPN 用户无法直接到达对等 VPC,而为绕开这一误读所建的 bastion,就是一台毫无理由需要打补丁的主机。
反向的错误随时间代价更高:把每个团队都赶进那台唯一已存在的 bastion,然后发现它的安全组、路由表和补丁窗口成了生产依赖。写清这台主机服务的是哪个触发器,并在触发器消失时让它退役。
Transit Gateway 与多个关联会改变算式
如果端点直接挂到 Transit Gateway 而不是子网,模型就变了:客户端不再被转换成关联子网中的接口地址,网关路由表则必须同时承载客户端网段和通往对等 VPC 的挂载。规模化时这更干净,但工作量从四个条目转移到网关路由表。
多个关联会让检查成倍增加。端点路由属于端点,但每个关联子网都需要一张带真实对等下一跳的路由表。一个关联上的会话可能成功,另一个却没有回程路径,所以每个都要测。
能快速找到断点的验证顺序
按顺序执行这些步骤;每一步都可能在下一步失败时仍然通过,而客户端超时几乎从不说清是哪一步坏了。
- 从客户端解析应用名称,确认地址落在对等网段内。
- 连接,然后阅读终止该会话的那个关联的端点连接日志。
- 在该关联子网上,确认路由表把对等网段指向一条活动的对等连接。
- 在 B 的资源子网上,确认存在接口网段的回程条目以及匹配的安全组规则。
- 测试一个被允许的操作和一个必须保持不可达的资源;后者能抓住调试残留。
- 任何 split-tunnel 路由变更后都要重连,因为正在运行的隧道不会接收新的路由集合。
有两个症状值得记住。到达 B 却没有回应的 SYN,几乎总是缺失的回程路由。连接完成之后又被重置,通常是安全组、ACL 或应用本身。两者都不会以原因的形式出现在端点日志里,所以请把四个条目连同各自的负责人一起留档。
如果三个触发器一个都不成立,就把路由路径做完,并把这四个条目记录下来。如果有一个成立,就只为那道边界保留 bastion,把端点路由留给你不需要在前面加会话的服务。