news 2026/10/9 2:05:12

Weave Net Fast Datapath 加密实现详解:基于 XFRM 的 ESP 传输模式与 AES-GCM

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Weave Net Fast Datapath 加密实现详解:基于 XFRM 的 ESP 传输模式与 AES-GCM
  • 网络
  • 云原生

【免费下载链接】weave

Simple, resilient multi-host containers networking and more.

项目地址:https://gitcode.com/gh_mirrors/weave4/weave
点击查看免费下载

本文深入解析 Weave Net 中 fast datapath(快速数据通路,基于 OVS/ODP 的 VXLAN 覆盖网络)的加密实现细节,涵盖加密协议选型、SA 密钥派生、SPI 分配、连接建立握手、iptables 标记规则、ESN 防重放与 MTU 计算等核心机制。读者将理解 Weave 如何在不可信网络环境中对 VXLAN 隧道流量实现机密性与完整性保护,并能对照 net/ipsec/ipsec.go 与 router/fastdp.go 的源码验证每个环节的落地方式。

加密方案概览

在高层次上,fast datapath 加密采用ESP 协议(RFC 2406)的传输模式(Transport Mode):每个数据包使用AES-GCM 模式(RFC 4106)加密,密钥长度为32 字节,外加4 字节盐值(salt)。这一组合提供了以下安全属性:

  • 数据机密性(Data confidentiality):载荷内容不可被窃听者读取;
  • 数据源认证(Data origin authentication):接收方能够确认数据确实来自声称的对端;
  • 完整性(Integrity):数据在传输过程中未被篡改;
  • 防重放(Anti-replay):通过序列号机制阻止攻击者重放已捕获的数据包;
  • 有限的流量流机密性(Limited traffic flow confidentiality):由于 fast datapath 的 VXLAN 数据包被整体加密,观察者无法从密文中直接识别 VXLAN 隧道头,从而隐藏了部分流量特征。

从仓库源码看,这一方案在 net/ipsec/ipsec.go 中有明确的常量定义:keySize = 36(32 字节 AES-GCM 密钥 + 4 字节盐值)、nonceSize = 32(HKDF 派生所用的随机 nonce 长度),加密算法在 xfrmState 中注册为内核 XFRM 的rfc4106(gcm(aes)),ICV(完整性校验值)长度为 128 位。

符号约定

原文档使用如下记号来描述连接方向与对象:

  • SAin:入方向(inbound)的 IPsec 安全关联(Security Association);
  • SAout:出方向(outbound)的 IPsec 安全关联;
  • SPout:出方向的 IPsec 安全策略(Security Policy),用于将出站流与SAout匹配起来。

SA 密钥派生(Key Derivation)

对于每个连接方向,Weave 使用不同的 AES-GCM 密钥与盐值。两个方向上的密钥对均由 HKDF(RFC 5869)派生,公式如下:

SAin[KeyAndSalt] = HKDF(sha256, ikm=sessionKey, salt=nonceIn, info=localPeerName) SAout[KeyAndSalt] = HKDF(sha256, ikm=sessionKey, salt=nonceOut, info=remotePeerName)

其中:

  • sessionKey(共享会话密钥):由 Mesh 库在本地 peer 与远端 peer 建立控制面(control plane)TCP 连接时协商得出,两个方向的 SA 共享同一个 sessionKey;
  • nonceIn/nonceOut:各自随机生成的 32 字节 nonce,通过已加密的控制面通道在两端之间交换。

对照源码 deriveKey:它调用hkdf.New(sha256.New, sessionKey, nonce, info),其中info是 8 字节的 peer 名称(binary.BigEndian.PutUint64(info, uint64(peerName))),与文档中info=localPeerName/info=remotePeerName的表述一致。nonce 由 genNonce 通过crypto/rand生成,每次建立连接都是全新的随机值。

这种"同源会话密钥 + 不同方向随机 nonce + 不同 peer 身份信息"的设计,保证了两个方向上的 AES-GCM 密钥相互独立,即使一个方向的密钥泄露也不会直接波及另一个方向。

SPI 分配

两个 peer 之间的方向性安全连接用SPI(Security Parameter Index,安全参数索引)来标识。

内核要求SPI 与目的 IP(dst IP)的组合在安全关联中必须唯一。为了避免分配冲突,Weave 采取的策略是:出方向(outbound)的 SPI 在远端 peer 上生成。也就是说,发起方(Peer A)为"从 B 到 A"这个方向(SA_BA,A 侧的入方向)向内核请求分配 SPI,然后把该 SPI 通过加密控制面消息告知 B;B 收到的 SPI 恰好就是自己出方向(SA_BA)所用的 SPI,从而天然满足"{SPI, dstIP} 全局唯一"的内核约束。

源码印证:InitSALocal(发起方本地初始化入方向 SA)调用 netlink.XfrmStateAllocSpi 让内核分配 SPI,并注释说明"内核保证 {dstIP, spi} 唯一";随后该 SPI 随InitSARemote消息发送给远端,远端在InitSARemote中复用同一 SPI 建立出方向 SA(见 xfrmState 与 msgInitSARemote 的序列化格式:nonce 在前、SPI 在后)。

此外,每个 SA 建立还会记录在spiInfo/spis两张映射表中(键为(srcPeer, dstPeer, connUID)组成的 24 字节spiID,见 getSPIId),用于后续Destroy时的精确清理。

连接建立流程(Connection Establishment)

加密连接建立在fastdp.fwd.Confirm()时触发。完整流程如下(Peer A 与 Peer B 对称执行):

Peer A Peer B ----------------------------------------------------------------------------------------------------------------- fastdp.fwd.Confirm(): fastdp.fwd.Confirm(): install iptables blocking rules, install iptables blocking rules, nonce_BA = rand(), nonce_AB = rand(), {key,salt}_BA = hkdf(sessionKey, nonce_BA, A), {key,salt}_AB = hkdf(sessionKey, nonce_AB, B), spi_BA = allocspi(), spi_AB = allocspi(), create SA_BA(B<-A, spi_BA, key_BA, salt_BA), create SA_AB(A<-B, spi_AB, key_AB, salt_AB), send InitSARemote(spi_BA, nonce_BA). --> <-- send InitSARemote(spi_AB, nonce_AB). --> recv InitSARemote(spi_BA, nonce_BA): recv InitSARemote(spi_AB, nonce_AB): <-- {key,salt}_BA = hkdf(sessionKey, nonce_BA, A), {key,salt}_AB = hkdf(sessionKey, nonce_AB, B), create SA_BA(B<-A, spi_BA, key_BA, salt_BA), create SA_AB(A<-B, spi_AB, key_AB, salt_AB), create SP_BA(B<-A, spi_BA), create SP_AB(A<-B, spi_AB), install marking rule. install marking rule.

要点解读:

  1. 对称交叉初始化:A 侧在本地创建的是"B 发往 A"的入方向 SA(SA_BA),并把自己随机生成的 nonce_BA 和内核分配的 spi_BA 通过InitSARemote消息发给 B;B 收到后,用它本地派生出相同的 SA_BA 密钥作为出方向SA,并创建对应的出方向策略 SP_BA。反向(A 到 B)完全对称。
  2. 密钥一致性保证:A 用(sessionKey, nonce_BA, peerName A)派生的密钥,与 B 收到消息后用相同输入派生的密钥完全一致,因此两侧无需再单独传输密钥。
  3. 控制消息类型:在 router/fastdp.go 中定义了FastDatapathHeartbeatAck与FastDatapathCryptoInitSARemote两种控制消息 tag;ControlMessage按 tag 分发,其中 handleCryptoInitSARemote 在收到消息后调用ipsec.InitSARemote,并在成功后将isOutboundIPSecEstablished置位、重置心跳定时器——只有出方向 SA 建立完成后才会开始发送心跳。

在 router/fastdp.go 的Confirm()实现中可以看到完整触发链:仅当ipsec != nil && sessionKey != nil时才进入加密分支(即isEncrypted = true),调用InitSALocal生成控制消息并通过sendControlMsg(FastDatapathCryptoInitSARemote, controlMsg)发送给远端。而在 FastDatapath.Stop() 中,若连接被拆除,会调用ipsec.Destroy清理两侧的 SA、策略与 iptables 规则。

实现细节(Implementation Details)

XFRM 框架

整个加密实现基于内核的IP 包变换框架 XFRM(IP packet transformation framework)。文档作者特别指出:XFRM 的公开文档极少、框架复杂度高,推荐的参考资料是 Rami Rosen 所著《Linux Kernel Networking: Implementation and Theory》第 10 章。当前仓库的所有 SA/SP 操作(分配 SPI、增删状态与策略、Flush 清理)都通过vishvananda/netlink库的XfrmState*/XfrmPolicy*系列 API 完成(见 net/ipsec/ipsec.go)。

关键的内核对象构造如下(xfrmState 与 xfrmPolicy):

  • SA(状态):Proto = XFRM_PROTO_ESP、Mode = XFRM_MODE_TRANSPORT(传输模式)、ReplayWindow = 256、ESN = true(启用扩展序列号)、AEAD 算法为rfc4106(gcm(aes))、ICVLen = 128;
  • SP(策略):匹配srcIP/dstIP的/32网络、协议为 UDP、方向为XFRM_DIR_OUT,并携带Mark(值与掩码均为标记值),策略模板指向对应的 ESP 传输模式 SA。

iptables 标记规则

内核 VXLAN 驱动不会在 IP 流描述符中设置隧道的目的端口,因此 XFRM 策略查找无法匹配包含端口条件的 SPout,也就无法只对 peer 间的隧道流量进行加密。为此 Weave 采用如下变通方案:

  • 用 iptables 给此类出站数据包打标记(mark),并在策略选择器(selector)中设置相同的标记;
  • 有趣的是,iptables_mangle模块最终会把缺失的目的端口补进流描述符中;
  • 挑战在于挑选一个不会干扰其他网络应用的标记值。例如 Kubernetes 默认使用1<<14和1<<15,Weave 因而选用1<<17(即 0x20000);
  • 该变通方案还带来一个硬性前提:内核版本至少为 4.2。

出站标记规则如下:

iptables -t mangle -A OUTPUT -j WEAVE-IPSEC-OUT iptables -t mangle -A WEAVE-IPSEC-OUT -s ${LOCAL_PEER_IP} -d ${REMOTE_PEER_IP} \ -p udp --dport ${TUNNEL_PORT} -j WEAVE-IPSEC-OUT-MARK iptables -t mangle -A WEAVE-IPSEC-OUT-MARK --set-xmark ${MARK} -j MARK

由于 Linux 并未实现 RFC 草案中的 "IP Security Levels"(IP 安全级别,见 draft-mcdonald-simple-ipsec-api),Weave 需要额外安装 iptables 规则,防止在已建立安全连接的 peer 之间意外发送未加密流量。

对入站流量:为每个 ESP 数据包打上标记,并丢弃未打标记的隧道流量:

iptables -t mangle -A INPUT -j WEAVE-IPSEC-IN iptables -t mangle -A WEAVE-IPSEC-IN -s ${REMOTE_PEER_IP} -d ${LOCAL_PEER_IP} \ -m esp --espspi ${SPIin} -j WEAVE-IPSEC-IN-MARK iptables -t mangle -A WEAVE-IPSEC-IN-MARK --set-xmark ${MARK} -j MARK iptables -t filter -A INPUT -j WEAVE-IPSEC-IN iptables -t filter -A WEAVE-IPSEC-IN -s ${REMOTE_PEER_IP} -d ${LOCAL_PEER_IP} \ -p udp --dport ${TUNNEL_PORT} -m mark ! --mark ${MARK} -j DROP

对出站流量:丢弃已打标记但未匹配任何 SPout的流量(这类流量意味着将明文发送给对端):

iptables -t filter -A OUTPUT ! -p esp -m policy --dir out --pol none \ -m mark --mark ${MARK} -j DROP

这些规则在源码中有完整且严格对应的实现。链名与标记常量定义于 net/ipsec/ipsec.go:mark = uint32(0x1) << 17、markStr = "0x20000/0x20000",四条链分别为 mangle 表的WEAVE-IPSEC-IN、WEAVE-IPSEC-IN-MARK、WEAVE-IPSEC-OUT、WEAVE-IPSEC-OUT-MARK以及 filter 表同名链。基准规则(OUTPUT/INPUT 跳转链、--set-xmark打标记、出站未匹配策略即 DROP)在 resetIPTables 中安装;针对具体 peer 与 SPI 的规则(入站 ESP 打标、丢弃未标记的 UDP 隧道包、出站定向打标)在 rulesDropNonEncrypted 中生成,其中入站打标规则通过-m esp --espspi 0x...精确匹配特定 SPI。

ESN(扩展序列号)

为防止序列号循环(SeqNo 回绕)导致重放攻击成为可能,Weave 使用64 位扩展序列号 ESN(RFC 4304)。在源码中对应xfrmAllocSpiState里的ESN: true与ReplayWindow: 256(net/ipsec/ipsec.go)。

MTU 计算

除 VXLAN 自身的开销外,MTU 计算还需计入ESP 头部开销,共 34–37 字节(加密后的载荷按 4 字节对齐),由以下部分组成:

组成部分字节数
SPI4
序列号(Sequence Number)4
ESP IV8
Pad Length1
NextHeader1
ICV16
Padding0–3

即固定 34 字节 + 最多 3 字节对齐填充 = 34–37 字节。

这一点与 docs/fastdp.md 的说明互相印证:默认数据通路接口 MTU 被静态配置为1376 字节,可适配大多数底层网络(如 GCE 的 1460 字节 MTU,其 84 字节差值正好容纳加密 VXLAN 的开销);该值可通过WEAVE_MTU环境变量在启动时覆盖(见 prog/weave-kube/launch.sh 中router_bridge_opts对--mtu的处理)。

加密的启用与关闭

加密仅在设置了共享密码时生效。在 prog/weaver/main.go 的determinePassword中:优先使用命令行--password参数,否则读取环境变量WEAVE_PASSWORD;两者皆为空则输出 "Communication between peers is unencrypted." 并返回 nil(不启用加密),否则输出加密提示并以字节形式传入。在createOverlay中,enableEncryption参数最终传入weave.NewFastDatapath(iface, port, enableEncryption)(prog/weaver/main.go),fast datapath 初始化时据此创建并 Flush 一次 IPsec 模块(见 router/fastdp.go)。

FastDatapath.Stop()时会对 IPsec 做Flush(true)(destroy 模式),一次性删除由 Weave 建立的 XFRM 策略、SA 以及 iptables 链和规则(router/fastdp.go)。

两个相关的启动开关(prog/weaver/main.go):

  • --no-fastdp:完全禁用 fast datapath(回退到 Sleeve 覆盖网络);
  • --no-bridged-fastdp:禁用桥接 fast datapath。

在 Kubernetes 部署场景下,可通过 DaemonSet 环境变量WEAVE_NO_FASTDP和WEAVE_MTU进行调节(prog/weave-kube/launch.sh),对应清单模板见 prog/weave-kube/weave-daemonset-k8s-1.9.yaml。

集成测试验证

仓库的集成测试 test/111_fastdp_encryption_2_test.sh 直接验证了本文档描述的加密行为:

  • 以--password wfvAwt7sj启动两台主机的 Weave,断言status connections输出包含encrypted *fastdp,并检查加密连接的 metrics;
  • 用tcpdump抓包断言:两台主机之间的VXLAN(UDP 目的端口 6784)流量完全不存在(即明文 VXLAN 不出现),而ESP(IP 协议号 50)流量存在——证明隧道流量确实被整体加密;
  • 重置连接后,断言ip xfrm state、ip xfrm policy均为空,且 mangle 表WEAVE-IPSEC-IN/WEAVE-IPSEC-OUT链中不再有-A规则——证明 Destroy 与 Flush 能完整回收 SA、策略与 iptables 规则。

小结

Weave Net 的 fast datapath 加密是一套完全运行在内核 XFRM 框架之上、面向传输模式 ESP 的轻量方案:通过 Mesh 控制面共享 sessionKey、以 HKDF 按方向派生 AES-GCM 密钥、由内核分配 SPI 保证{SPI, dstIP}唯一性、用 iptables 标记(0x20000)解决 VXLAN 无端口导致的策略匹配难题,并以 ESN + 重放窗口提供防重放保护。启用时只需为所有 peer 配置相同的WEAVE_PASSWORD(或--password),内核版本需不低于 4.2,且建议结合WEAVE_MTU校验底层网络的 MTU 余量。相关实现可对照 net/ipsec/ipsec.go、router/fastdp.go 与 test/111_fastdp_encryption_2_test.sh 深入研读。

  • 网络
  • 云原生

【免费下载链接】weave

Simple, resilient multi-host containers networking and more.

项目地址:https://gitcode.com/gh_mirrors/weave4/weave
点击查看免费下载
上一篇:Jellyfin媒体服务器完全攻略:打造个人专属的影视中心
下一篇:KKS-HF_Patch 项目完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 2:04:27

模板消息错误消息优化:从错误码规范到链路追踪的工程实践

做了快十年的模板消息平台&#xff0c;我最大的体会是&#xff1a;模板这玩意儿&#xff0c;看着简单&#xff0c;真出起问题来能把人逼疯。尤其是错误消息——用户那边只收到一句"发送失败"&#xff0c;后台日志里躺着一串又臭又长的堆栈&#xff0c;模板ID、参数名…

作者头像 李华
网站建设 2026/10/9 2:02:29

ui生成提示词实战:用TaoToken统一Key打通HTML移动端与PC端双端适配

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/9 2:01:05

编译好的Chromedriver特征抹除与配套浏览器实战指南

简介&#xff1a;这是一份面向爬虫开发者与自动化测试人员的Chromedriver资源&#xff0c;针对反爬检测场景&#xff0c;提供已抹除自动化特征的Windows 10专用驱动&#xff0c;并配套完整浏览器环境&#xff0c;解决常规驱动易被识别、导致脚本失效的问题。压缩包共491个文件&…

作者头像 李华