源/目标检查只是一道关卡,不是整条 VPN 路径
转发实例除了 Linux 路由和防火墙规则,还需要 AWS 层面的权限。请在实际承担转发的实例上检查源/目标校验。
VPN 终结在一台 EC2 实例上,你能连到该实例的隧道地址,可本该经它转发到另一台私有主机的流量却消失了。这是两个不同的测试,混为一谈会白白浪费几个小时。第一个测试问的是你能否到达该实例;第二个测试要求它为一个并不属于自己的目标转发流量,这需要 Linux 转发、防火墙策略、远端的路由,以及一项与客体操作系统毫无关系的 AWS 层权限。控制台里没有任何地方提示这层差别。症状看起来像路由故障,通常却并不是。
动手之前先把两个测试分开
能到达网关只证明了隧道、到其地址的路由,以及放行这次交互的安全组。为另一台主机转发则什么都证明不了:它用的是不同的源地址、不同的目标,以及一台未必为此而建的实例。把两个测试分开写下来,并记下哪一个失败,因为两者的修正分别在不同的控制台里。只为终结隧道而建的网关实例没有理由替别的目标转发,它的默认配置也正体现了这一点。所以第二个测试需要自己的一套配置,而不是在第一个上做点小调整。
能 ping 通网关、却 ping 不通网关后面的主机,不是时有时无的故障。那是一个从未被告知可以转发的实例的正常表现。
碰任何设置之前,先把路径写下来
记录客户端前缀、承担转发的实例或网卡、目标子网和回程路由。VPC 路由表里指向某台实例的条目,并不会把那台实例的操作系统配置成转发;客体内核即便开了转发,也不会创建 VPC 路由。这段关系的两端都必须存在,而 它们由权限不同的人在不同地方分别编辑。
然后检查真正承担转发的那台组件上的源/目标检查设置,而不是 VPC 里的每一台实例。AWS 的文档说明了为什么替他人转发的实例必须关闭这项检查,也说明了为什么这是逐实例的决定,而不是整个 VPC 的默认值。
四道边界,而检查只是其中一道
把这条路径当成四个问题,按顺序回答。第一个失败的答案就是问题所在,其余任何一道都补不回来。
| Boundary | Question it answers |
|---|---|
| VPC route tables | Do the destinations and replies select the intended gateway? |
| Forwarding instance | Do the AWS check and the guest OS both permit forwarding? |
| Access policy | Do security groups, ACLs and host rules allow the exchange? |
| Destination | Can the service accept that source and return a reply? |
顺序重要,因为检查很便宜:路由一页就能看完,检查只是一个属性,而目标的意见通常是最后才被问到的。
转换会改变目标看到的源
路由式设计保留客户端的源地址,因此目标需要一条回到客户端前缀的回程路由。转换式设计则呈现网关的地址,这去掉了那项要求,代之以网关上的状态表。请按你真正打算采用的架构来决定,而不是因为某个无关的例子用了它就以为可以照搬。
如果你做转换,就把规则限定在客户端前缀和预期目标上。如果你保留源地址,就确认远端确实知道这条路由,而不是假定它自己会学到。
从原始客户端测试,然后把改动保留下来
在网关上发出的请求可能成功,而转发来的请求却失败,因为源不同、转发情形也不同。做过针对性修正之后,用同一个客户端重做那个失败的确切测试,并确认回包真的回来了,而不只是请求到达了。
最后,把设置放进网关的受管配置里,让替换出来的实例也能拿到。依赖手工例外的成功测试,会在下一次重建时失效,而当初发现它的人不会在那儿记得为什么。