去年 6 月,Tigera[1] 首次宣布在 K8s 上支持用于集群内加密传输的开源 VPN - WireGuard[2]。我们从来不喜欢坐以待毙,因此我们一直在努力为这项技术开发一些令人兴奋的新功能,其中第一个功能是使用 Azure 容器网络接口(CNI)[3] 在 Azure Kubernetes 服务(AKS)[4] 上支持 WireGuard。
首先,这里简单回顾一下什么是 WireGuard 以及我们如何在 Calico 中使用它。
WireGuard 是一种 VPN 技术,从 Linux 5.6 内核开始默认包含在内核中,它被定位为 IPsec 和 OpenVPN 的替代品,旨在更加快速、安全、易于部署和管理。正如不断涌现的 SSL/TLS 的漏洞显示,密码的敏捷性会极大增加复杂性,这与 WireGuard 的目标不符,为此,WireGuard 故意将密码和算法的配置灵活性降低,以减少该技术的攻击面和可审计性。它的目标是更加简单快速,所以使用标准的 Linux 网络命令便可以很容易地进行配置,并且只有约 4000 行代码,使得它的代码可读性高、容易理解、审查。
WireGuard 是一种 VPN 技术,通常被认为是 C/S 架构,它同样能在对等的网格网络架构中配置使用,这就是 Tigera 设计的可以在 Kubernetes 中使用的 WireGuard 解决方案。使用 Calico,将所有启用 WireGuard 的节点相互对等形成一个加密的网格。它甚至支持在同一集群内同时包含启用 WireGuard 的节点与未启用 WireGuard 的节点,并且可以相互通信。
我们选择 WireGuard 并不是一个折中的方案。我们希望提供最简单、最安全、最快速的方式来加密传输 Kubernetes 集群中的数据,mTLS、IPsec 或复杂的配置不是我们想要的。事实上,你可以把 WireGuard 看成是另一个具有加密功能的 overlay。
用户只需一条命令就可以启用 WireGuard,而 Calico 负责完成剩余的工作,包括:
在每个节点创建 WireGuard 的网络接口。
计算编写最优的 MTU。
为每个节点创建 WireGuard 公钥私钥对。
向每个节点添加公钥,以便在集群中共享资源。
将所有节点编辑为对等节点。
使用防火墙标记(fwmark)编辑 IP route、IP tables 和 Routing tables,以此正确处理各自节点上的路由。
仅需指明意图,其他的事情都由集群完成。
下图显示了启用 WireGuard 后集群中的各种数据包流量情况。
同一主机上的 Pod:
数据包被路由到 WireGuard 表。
如果目标 IP 是同一主机上的 Pod,则 Calico 将在 WireGuard 路由表中插入一个 “ throw ” 条目,将数据包引导回主路由表。数据包被定向到目标 Pod 的 veth 接口,并且它将在未加密的情况下流动(在图中以绿色显示)。
不同节点上的 Pod:
在以下动画中,您可以看到 3 种流量:
注意:绿色表示未加密流量,红色表示加密流量。
动画演示[5]
在 AKS 上使用 Azure CNI 对 WireGuard 的支持带来了一些非常有趣的挑战。
首先,使用 Azure CNI 意味着不使用 Calico IPAM( IP 地址管理)管理 CIDR(无类域间路由)块分配的 Pod IP 。相反,它们是采用节点 IP 相同的分配方式从底层 VNet 分配的。这对 WireGuard 路由来说是一个有趣的挑战,以往我们可以在 WireGuard 配置中的 Allowed IPs 列表中添加一个 CIDR 块,相比之下,我们现在必须写出该节点所有 Pod IP。这需要 Calico 将 routeSource 的配置设为 workloadIPs。如果您使用的是 AKS 集群进行部署,便无需额外配置。
使用 wireguard-tools 中优秀的工具 wg[6],可以查看集群内节点允许通过的 IP 列表,其中包括每个节点的 Pod IP 和主机 IP(注意终端 IP 也在允许 IP 列表中)。在 AKS 上提供了业务流量加密和主机到主机的加密。
interface: wireguard.cali public key: bbcKpAY+Q9VpmIRLT+yPaaOALxqnonxBuk5LRlvKClA= private key: (hidden) listening port: 51820 fwmark: 0x100000 peer: /r0PzTX6F0ZrW9ExPQE8zou2rh1vb20IU6SrXMiKImw= endpoint: 10.240.0.64:51820 allowed ips: 10.240.0.64/32, 10.240.0.65/32, 10.240.0.66/32 latest handshake: 11 seconds ago transfer: 1.17 MiB received, 3.04 MiB sent peer: QfUXYghyJWDcy+xLW0o+xJVsQhurVNdqtbstTsdOp20= endpoint: 10.240.0.4:51820 allowed ips: 10.240.0.4/32, 10.240.0.5/32, 10.240.0.6/32 latest handshake: 46 seconds ago transfer: 83.48 KiB received, 365.77 KiB sent
第二个挑战是正确处理 MTU(最大传输单元)。Azure 设置的 MTU 是 1500[7],而 WireGuard 在数据包上设置了一个 DF(Don’t Fragment)标记。如果没有正确调整 WireGuard MTU,我们会在启用 WireGuard 时发现有丢包和低带宽。我们可以在 AKS 中通过 Calico 自动检测并为 WireGuard 的 MTU[8] 设置正确的开销来优化。
我们还可以将节点 IP 本身添加为对等节点允许通信的 IP ,并通过 AKS 中的 WireGuard 处理主机联网的 Pod 和主机到主机通信。主机到主机通信的方法是,当 RPF[9](反向路径转发)发生时,通过 WireGuard 接口获得路由返回的响应。通过在发送到目的节点的数据包上设置一个标记,然后配置内核以遵守 sysctl 中的 RPF 标记来解决这个问题。
现在使用 AKS 时,节点之间的业务流量和主机到主机通信都会被加密,仅需指明意图,其他的事情都由集群完成。