当两层分别在不同机器上终结时,嵌套 IPsec 更容易推演。四台网关、两条隧道,以及一个决定设计是否成立的问题:内层隧道处理完报文之后,外层隧道实际看到的是什么?回答好这个问题,选择器、路由和排障顺序就会自然确定。答错的话,你会花一整天去调一条技术上已经起来的隧道。

四网关模型

外层网关 A 和 B 在两个站点之间建立第一条隧道。A 后面是内层网关 C,其过境地址为10.60.0.2;B 后面是内层网关 D,其过境地址为10.70.0.2。应用网段位于 C 和 D 之后,示例中的每个地址都刻意不重叠。

application net -> C -> A == outer IPsec == B -> D -> application net
                       \---------- inner IPsec ----------/

C transit: 10.60.0.2      D transit: 10.70.0.2
A and B:    underlay addresses only

把两层拆到四台主机上,意味着每台机器只守一道边界。只用一台主机同时跑两层,就要在同一台机器上调和两套策略、两张路由表和两种故障模式;这确实可行,但观测难度大得多。

每层只剥掉自己的保护

C 为 D 加密应用报文。结果被寻址为从 C 到 D,抵达 A 的正是它。后续一切都依赖这次重写。

A 再为 B 加密一次。B 解开外层,看到的是一条从 C 到 D 的报文,并将其以仍然加密的状态转发出去。D 剥掉内层保护,交付应用报文。

因此 A 和 B 能看到内层端点及其元数据,但它们并不是解密应用载荷的那一方。这是设计本身的真实属性,并不等于说 C、D 或应用主机值得信任。

外层选择器写的是内层网关

大多数这类方案就败在这里。对于基于策略的外层隧道,你协商的选择器必须包含 A 和 B 实际处理的地址:10.60.0.2/32和10.70.0.2/32,并且本地与远端的顺序要正确。

把最终的应用子网放进外层选择器是不行的,因为报文到达 A 时,内层封装早已改写了 A 需要保护的内容。此时外层策略匹配不到任何流量,隧道会起来却什么都不传。

也不要把握手限制在 UDP 500。内层连接有自己的数据路径,它按协商结果使用 ESP 或 UDP 封装,外层策略必须放行对应协议。

在每个网关上用swanctl --list-sas核对结果,并确认子安全关联报告的是你预期的地址,而不是你假设的地址。如果列表显示的是应用子网,说明外层策略写错了层。先改选择器再去查路由,因为路由看起来会一切正常,而计数器不会动。

转发与递归陷阱

选择器不能替代路由。A 和 B 必须在两个方向上转发 C 与 D 之间的流量,这意味着要开启 IP 转发、要有指向隧道的路由,并且对端存在回程路径。

如果外层隧道使用 XFRM 接口,路由负责选择接口,而协商出的策略仍然约束它承载什么。接口不会扩大受保护范围,它只改变内核如何取走报文。

陷阱是递归。A 到 B 外层端点的路由必须走底层网络,而不是 A 正在建立的隧道,否则封装会试图在自己的内部穿行,连接永远建立不起来。

加层之前先看地址转换

在调其他任何东西之前,先看 A 和 B 上的源 NAT。一条在 IPsec 策略生效前就改写 C 地址的规则,可能破坏商定的选择器,也可能改变 D 在另一侧收到的内容。

两层并不会让大范围伪装更安全。它隐藏了对端看到的地址,而这恰恰是隧道起来了、应用却不工作时最需要的信息。

如果 NAT 规则确实必要,就写下每一侧以为自己是在和哪个地址通信。这一行能解决大多数关于是隧道还是转换的争论,也能告诉下一位工程师一年后删除规则时该从哪里看起。ping 做不到这些。

证明 fail-closed 并检查 MTU

路由消失本身并不等于 fail-closed 策略。另一张路由表、一条默认路由或一条策略规则都可能悄悄提供退路,唯一能确认的办法是把外层隧道停掉,观察应用流量如何表现。请在有维护窗口时主动做这件事,而不是偶然发现。

测试三种状态:外层隧道断开、内层隧道断开,以及两者恢复后的复原。在每个网关上使用策略计数器,因为两条已建立的 IKE 会话只能证明控制面协商成功。

两层封装都要留预算。IKE 能通只是小包的结果,加上两个头部之后,全尺寸应用报文仍可能失败;请用已知载荷大小在真实路径上测试,而不是假设数字刚好凑得上。算术很简单,路径不是。

相关文章