为什么繁忙的 IPsec 隧道会提前重设密钥:时间与流量上限
字节上限可能在小时远未结束时就被触发。比较软、硬生存期,关联所用的计数器,以及替换交换。
大约每五十分钟,繁忙链路上的隧道会短暂中断几秒钟,而第一个嫌疑对象是时钟。关联可以因时间上限或字节计数而终止,哪一个边界先到,就由它让关联退役。在承载真实流量的链路上,流量上限可能在配置的一小时远未结束时就触发。所以「太早」是关于时钟的说法,而不是关于关联的说法。
数关联在数什么,而不是数接口
接口的字节总量、仪表板的合计吞吐量以及关联自身的计数器是三个独立的数字,只有其中一个会与上限比较。把入站和出站关联连同各自的标识分别记录下来,这样触及单个方向的重设密钥就会表现为有方向的事件,而不是一个谜。关联计数器在重设密钥时也会重新开始,这就是为什么从接口取的总量在增长,而真正重要的数值却被重置。
这个算术值得做一次,好让数量级不再显得随意。以一 gibibyte 为计数预算,按每分钟 128 mebibyte 的稳定速率消耗,八分钟就会用完,而这是单位换算,不是对你隧道的测量。如果得出的数字远低于时间上限,那么机制就是流量,再怎么盯着时钟也解释不了这个间隔。如果它远高于上限,那么字节上限就不是你的触发点,查找方向在别处。
软阈值与硬阈值是两种不同的事件
软阈值会在硬上限结束关联之前很早就请求替换,而实现会在你配置的内容之上叠加自己的余量与随机化。这就是为什么观测到的间隔几乎从不是整数。IPsec 架构描述了以时间和字节计数表示的生存期,并区分两种阈值,其中更早的到期时间起决定作用。如果把印出来的某个生存期当作时间表,你就会错开一个余量的距离。
从运行状态读取实际策略,而不是从文件里的数字去推断,因为余量属于实现,不属于你的意图。不要为了压住症状就把上限一路拉到最大值:按计划重设密钥的隧道只是在按设计行事,更长的生存期只会把事件往后推,同时让已泄露的密钥多可用一段时间。当替换本身失败时,上限是报信者,而不是过错。
从运行状态读取实际生存期
在 strongSwan 上,swanctl --list-sas 会打印关联摘要及其重设密钥时间与生存期,因此守护进程打算执行的值无需猜测就能看到。在没有守护进程视图的 Linux 主机上,ip xfrm state 会报告配置的软、硬字节与包上限,并列出当前计数器。这两种读法回答的是不同问题,都值得留在工单里。
swanctl --list-sas
ip -s xfrm state
把打印出来的软阈值与你测得的间隔相比,因为从硬上限下方某个余量开始的替换是正常的,而从不开始的替换则不正常。如果守护进程显示一个生存期,而内核状态显示另一个,你看到的就是两个不一致的层,这本身就是发现。
观察替换 SA 的交换
把三种续期分开看待,因为它们失败的方式不同:IKE SA 的重设密钥会建立新的控制关联,CHILD SA 的重设密钥会替换数据关联,而重新认证则重复身份交换。在 IKEv2 中,每一端各自决定自己的生存期,而不是协商一个共享值,因此不是你发起的交换也很平常。perfect forward secrecy 不匹配是新的 child SA 恰好在重设密钥间隔上失效的常见原因,而且它看起来完全像定时器故障,直到有人去读提议。
把旧关联与其后继关联,以及产生它的那次交换相比较。标识消失属于例行替换;提议被拒、响应缺失,或没有可用的后继状态,则是另一个归属者负责的另一种事件。在改动任何东西之前先保留这些证据,因为与版本相关的说明、对端的提议以及协商出的生存期,才能让一周之后、日志已经轮转的案情仍然读得懂。
证明续期,而不是把它藏起来
验收部署时,应走过一次你计划过的续期,而不是一次恰好发生在你身上的续期。在维护窗口内强制执行一次重设密钥,然后确认之后两个方向都在承载数据,且应用结果没有变化,而不只是隧道指示灯是绿的。记录是哪一个上限被触发,以及涉及哪一次交换。
这种形态的结论经得起推敲,而一个让连接安静了一个下午的改动过的定时器数值则经不起。如果只有定时器动了,证据也就跟着动了。