ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

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

Weave Net Fast Datapath 加密实现详解:基于 XFRM 的 ESP 传输模式与 AES-GCM 网络云原生【免费下载链接】weaveSimple, 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 3632 字节 AES-GCM 密钥 4 字节盐值、nonceSize 32HKDF 派生所用的随机 nonce 长度加密算法在 xfrmState 中注册为内核 XFRM 的rfc4106(gcm(aes))ICV完整性校验值长度为 128 位。符号约定原文档使用如下记号来描述连接方向与对象SAin入方向inbound的 IPsec 安全关联Security AssociationSAout出方向outbound的 IPsec 安全关联SPout出方向的 IPsec 安全策略Security Policy用于将出站流与SAout匹配起来。SA 密钥派生Key Derivation对于每个连接方向Weave 使用不同的 AES-GCM 密钥与盐值。两个方向上的密钥对均由 HKDFRFC 5869派生公式如下SAin[KeyAndSalt] HKDF(sha256, ikmsessionKey, saltnonceIn, infolocalPeerName) SAout[KeyAndSalt] HKDF(sha256, ikmsessionKey, saltnonceOut, inforemotePeerName)其中sessionKey共享会话密钥由 Mesh 库在本地 peer 与远端 peer 建立控制面control planeTCP 连接时协商得出两个方向的 SA 共享同一个 sessionKeynonceIn/nonceOut各自随机生成的 32 字节 nonce通过已加密的控制面通道在两端之间交换。对照源码 deriveKey它调用hkdf.New(sha256.New, sessionKey, nonce, info)其中info是 8 字节的 peer 名称binary.BigEndian.PutUint64(info, uint64(peerName))与文档中infolocalPeerName/inforemotePeerName的表述一致。nonce 由 genNonce 通过crypto/rand生成每次建立连接都是全新的随机值。这种同源会话密钥 不同方向随机 nonce 不同 peer 身份信息的设计保证了两个方向上的 AES-GCM 密钥相互独立即使一个方向的密钥泄露也不会直接波及另一个方向。SPI 分配两个 peer 之间的方向性安全连接用SPISecurity Parameter Index安全参数索引来标识。内核要求SPI 与目的 IPdst IP的组合在安全关联中必须唯一。为了避免分配冲突Weave 采取的策略是出方向outbound的 SPI 在远端 peer 上生成。也就是说发起方Peer A为从 B 到 A这个方向SA_BAA 侧的入方向向内核请求分配 SPI然后把该 SPI 通过加密控制面消息告知 BB 收到的 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.要点解读对称交叉初始化A 侧在本地创建的是B 发往 A的入方向 SASA_BA并把自己随机生成的 nonce_BA 和内核分配的 spi_BA 通过InitSARemote消息发给 BB 收到后用它本地派生出相同的 SA_BA 密钥作为出方向SA并创建对应的出方向策略 SP_BA。反向A 到 B完全对称。密钥一致性保证A 用(sessionKey, nonce_BA, peerName A)派生的密钥与 B 收到消息后用相同输入派生的密钥完全一致因此两侧无需再单独传输密钥。控制消息类型在 router/fastdp.go 中定义了FastDatapathHeartbeatAck与FastDatapathCryptoInitSARemote两种控制消息 tagControlMessage按 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 DetailsXFRM 框架整个加密实现基于内核的IP 包变换框架 XFRMIP 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 与 xfrmPolicySA状态Proto XFRM_PROTO_ESP、Mode XFRM_MODE_TRANSPORT传输模式、ReplayWindow 256、ESN true启用扩展序列号、AEAD 算法为rfc4106(gcm(aes))、ICVLen 128SP策略匹配srcIP/dstIP的/32网络、协议为 UDP、方向为XFRM_DIR_OUT并携带Mark值与掩码均为标记值策略模板指向对应的 ESP 传输模式 SA。iptables 标记规则内核 VXLAN 驱动不会在 IP 流描述符中设置隧道的目的端口因此 XFRM 策略查找无法匹配包含端口条件的 SPout也就无法只对 peer 间的隧道流量进行加密。为此 Weave 采用如下变通方案用 iptables 给此类出站数据包打标记mark并在策略选择器selector中设置相同的标记有趣的是iptables_mangle模块最终会把缺失的目的端口补进流描述符中挑战在于挑选一个不会干扰其他网络应用的标记值。例如 Kubernetes 默认使用114和115Weave 因而选用117即 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 LevelsIP 安全级别见 draft-mcdonald-simple-ipsec-apiWeave 需要额外安装 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.gomark 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 位扩展序列号 ESNRFC 4304。在源码中对应xfrmAllocSpiState里的ESN: true与ReplayWindow: 256net/ipsec/ipsec.go。MTU 计算除 VXLAN 自身的开销外MTU 计算还需计入ESP 头部开销共 34–37 字节加密后的载荷按 4 字节对齐由以下部分组成组成部分字节数SPI4序列号Sequence Number4ESP IV8Pad Length1NextHeader1ICV16Padding0–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.gofast 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抓包断言两台主机之间的VXLANUDP 目的端口 6784流量完全不存在即明文 VXLAN 不出现而ESPIP 协议号 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 深入研读。赞分享网络云原生【免费下载链接】weaveSimple, resilient multi-host containers networking and more.项目地址https://gitcode.com/gh_mirrors/weave4/weave点击查看免费下载相关推荐Firefox Send 端到端加密原理与实现基于 Web Crypto API 的 AES-GCM ECE 流式加解密实战解析Firefox Send 端到端加密原理与实现基于 Web Crypto API 的 AES GCM ECE 流式加解密实战解析 Firefox Send后端前端Tock AES-GCM Capsule基于底层 AES 硬件与纯软件 GHASH 的 GCM 实现解析Tock AES GCM Capsule基于底层 AES 硬件与纯软件 GHASH 的 GCM 实现解析 导读 Tock 内核的 capsules aes g操作系统嵌入式嵌入式OSElectric 端到端加密示例基于 sync 的 AES-GCM 数据加密实战Electric 端到端加密示例基于 sync 的 AES GCM 数据加密实战 导读 examples/encryption 是 Electric 官方仓库后端数据同步数据库人工智能AI AgentMCP 服务上一篇Jellyfin媒体服务器完全攻略打造个人专属的影视中心下一篇KKS-HF_Patch 项目完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进