隧道起来了,ping 通了,所有人都签字确认。四小时后会话掉线,两端记下一条 proposal 或密钥交换错误,第一反应是网络哪里变了。什么都没变。能跑流量的隧道只证明了双方在认证方式和第一个子关联的保护方式上达成一致,并没有证明续期时将要求的密钥交换。不一致就藏在这两件事之间的空隙里。

连上不等于 PFS 设置一致

在 IKEv2 中,第一个子关联在认证交换期间创建,其密钥取自 IKE 关联已经产生的材料。该子关联没有单独的 Diffie-Hellman 交换,因此续期时才要求它的策略在建立阶段不会被检验。

续期是另一次交换。子关联重协商时,双方可能用 proposal 中指定的组做一次新的密钥交换,这正是第一次比较组的时刻。于是两个不一致的对端可以先完成认证、安装子关联、跑通流量,然后在重协商时失败。

不一致藏在 proposal 字符串的哪里

在 strongSwan 中组被追加到子 proposal 上,所以像 aes256gcm16-prfsha256-ecp256 这样的字符串看起来只是加密选择,其实还带着密钥交换的要求。只提供 aes256gcm16-prfsha256 的一方没有这个要求,两份列表在加密上相交,却在交换上分道扬镳。

把子 proposal 和 IKE proposal 当成两份独立的列表来读。IKE 列表里出现的组,对子列表什么也没说;一边读一份、一边改另一份,正是漏掉它的常见方式。

读失败日志,而不是你改过的文件

找到结束交换的那条 notify。子重协商返回「没有可接受的 proposal」指向 proposal 列表;重协商请求始终没有回音,指向路径或不再监听的对端。这两种要不同的修法,日志那一行的措辞会区分它们。

确认正在运行的配置,而不是磁盘上的那一份。保存了却没加载的文件,或从另一个 include 重新读取的连接,会造出改多少遍可见文件都修不好的不一致。

三个都被叫做重协商的事件

IKE 关联重协商、IKE 重新认证和子关联重协商是三种独立操作,各有各的 proposal 规则。在其中一个上报的失败,并不直接说明另外两个;把三者混在一起的日志,读起来像单一反复故障,实际却是三个。

注意对端点名的是哪个事件,然后只查该事件的 proposal。改一份列表,重新加载,再强制触发同一个事件。如果日志点名重新认证,要读的是 IKE proposal。如果点名子重协商,承载关键组的是子 proposal。

关掉续期不是修法

把重协商时间设为零,只是压住了失败的那次交换,隧道随后一直撑到被拆除或对端重启。你买到的是更长命的密钥,以及一次会在迁移、审计或厂商更新时再次找上你的不一致。把生存期拉得远超对端策略,也是同样的道理。

正确的做法是对齐 proposal。选一个双方都实现的组,放在两端子 proposal 里,并把续期策略保持在组织真正要求的范围内。

用那次失败的交换来证明

在维护窗口里缩短子重协商时间,让事件几分钟就来,而不是几小时;也可以手动触发一次子重协商。然后观察一次成功的续期,确认流量继续从中通过,因为 装上了子关联却丢掉应用流量的新手握 是另一种缺陷。

之后恢复正常生存期,并保留两份事件记录:失败的那次和成功的那次。你要的证明是连接能活过自己的生命周期,而不是活过一次 ping。

相关文章