Wireguard:新一代魔法上网工具
文章目录
序言
WireGuard 是最新一代开源 VPN 工具,相较于IPsec和OpenVPN等大多数古老魔法,具有易于配置、快速且安全的特点。
通过 WireGuard 用户无论是想提升上网体验,还是想在服务器之间组网都变得更加简单。从 2020 年 1 月开始,它已经并入了 Linux 内核的 5.6 版本,这意味着大多数 Linux 发行版的用户将拥有一个开箱即用的 WireGuard。
本文简单介绍一下 WireGuard 使用,以及基于 wireguard 的 kubernetes cni 插件 kilo。
1.WireGuard
WireGuard是基于C语言编写,简单说来具备以下特性:
- 基于UDP协议
- 核心部分:加密密钥路由
- 公钥和 IP 地址列表(AllowedIPs)关联起来
- 每一个wg接口都有一个私钥和一个 Peer 列表
- 每一个 Peer 都有一个公钥和 IP 地址列表
- 发送包时,AllowedIPs起到路由表的功能
- 正常情况下,Peer的每个AllowedIPs,应该填写一条静态路由到wireguard设备!!!
- 接收包时,AllowedIPs起到权限管理的功能:Packet的Source IP位于服务端的 AllowedIPs 列表时被接收,否则被丢弃
2.安装
由于WireGuard已经被和入了Linux内核,使用WireGuard时我们只需升级内核到5.6以上版本,并且安装客户端工具 wireguard-tools 即可,以下是在Centos7上的安装步骤:
|
|
|
|
3.配置
安装完成后,可以使用ip link命令在服务器上添加 wireguard 类型的虚拟网卡。不同服务之间可以通过该虚拟网卡进行通信。
|
|
上述命令在服务器上创建了设备 wg0 并配置地址为 10.200.200.2/24。
用户通过以下命令生成配置,并启动wg0网卡。其中 /etc/wireguard/privatekey 和 /etc/wireguard/publickey 文件是 wg0 的密钥/公钥,局域网中不同 wg0 之间通过交换公钥实现连接。
|
|
添加以下IP规则(PS:有必要的话写入 /etc/sysconfig/iptables)
|
|
4. WireGuard 创建局域网
场景1
Server A:有公网IP Server B:位于局域网中无公网IP,但可以正常访问 Server A (wg0 地址配置为 10.200.200.11)
实现:Server A 可以通过 WireGuard 创建的虚拟网卡访问 Server B
Server A 上 WireGuard 配置文件如下:
|
|
Server B 上 WireGuard 配置文件如下:
|
|
场景2
在以下机器之间创建子网10.200.200.0/24,包含以下机器:
- 10.200.200.2 :Server A 具有公网IP
- 10.200.200.47:Server B 无公网IP(局域网所在网段为172.24.135.0/24)
- 10.200.200.11:Server C 无公网IP(与Server B位于不同局域网)
实现:
- 使子网之间的 VPN IP 可以相互访问
- ~~Server C 可以访问172.24.135.0/24的其他机器,~~实现Server B和Server C可以相互访问
Server A 作为中继服务器配置如下:
|
|
并添加以下路由规则:
|
|
Server B配置如下:
|
|
Server C配置如下:
|
|
kilo
将Kubernetes 和 WireGuard 结合的CNI插件:Kilo,该插件有以下能力。
1. CNI网络插件
Kilo 可以替代Flannel、Calico等常规网络插件,为Pod提供集群内的网络IP,此种模式下我们可以实现:
- 将多个不同网络的机器,加入到同一个K8S中进行管理,而这些节点不一定需要有稳定的公网IP(PS:这种能力非常适合一些IoT、边缘计算场景)~~
限制条件:
- 所有节点必须安装WireGuard(建议直接将系统内核升级到5.6以上版本)
- 所有节点必须提供一个可访问的UDP端口(默认是51820)
- Kilo在不同Region之间创建网络,需要知道节点的确切位置。Kubernetes Node 可以使用 topology.kubernetes.io/region为每个Node打标签,或者为每个Node添加kilo.squat.ai/location annotation
- 每个Region中的至少一个节点必须是其他Node可访问的,即每个Region中要有一个公网IP,可用用 kilo.squat.ai/force-endpoint指定这个endpoint的访问地址
关于Kilo的组网细节参考官方文档:topology
2. 附加网络工具
Kilo为K8S网络提供功能扩展,当使用Flannel为网络插件,并且以vxlan模式工作时,可以通过以下方式安装kilo。
|
|
Kilo在每台主机的宿主机网络运行,启动后会进行以下操作:
-
为每台宿主机创建一张wireguard,名称为kilo0
-
在每台宿主机上创建对应的iptables规则,PS:但是宿主机上51820的UDP端口依然要手工创建Iptable规则
-
为每台机器创建Key和配置文件,并且持久化在**/var/lib/kilo**目录
-
默认创建的VPN子网为10.4.0.0/16,可以通过-subnet指定
-
根据**–mesh-granularity**配置,Kilo创建的网络拓扑有所不同:
-
location:这种模式下一个Region中只有一个Node工作,该节点称为Master用户可以手动指定,也可以由Kilo自动选择。
-
full:所有节点加入到VPN网络中,并且相互称为Peer。此时kilo0设备会替代flannel.1设备,拦截所有发到POD IP的包,并根据WireGurad配置文件的allowedIPs信息发送到相应节点!
-
3. 存在问题
- 修改kilo的配置会影响flannel的路由配置,此时需要重启flannel容器来恢复路由
- 区域路由模式时(–mesh-granularity=location),出现多个node绑定同一个VPN IP(原因可能是抢夺Leader时,没有清理设备信息)。
- 一些配置修改不方便需要通过Annotations:https://github.com/squat/kilo/blob/master/docs/annotations.md
4. 参考配置
作为附加网络工具时,实现场景二的功能,参考一下配置:
- ds配置(不影响flannel原有网络):
|
|
-
ds配置nodeSelector只部署一个节点
-
Node打对应标签
|
|
- Peer 配置
|
|
-
公网中继服务器配置
1 2 3
[Peer] AllowedIPs = 10.4.0.1/32,172.24.135.0/24 PublicKey =
-
公网添加静态路由
1 2
route add -net 172.24.135.0/24 netmask 255.255.255.0 wg0 route add -net 10.4.0.0/16 netmask 255.255.255.0 wg0
WGSD
wgsd(Github)是基于CoreDNS插件实现的Wireguard Peer 发现插件,用来实现 NAT to Nat 的Peer直连。
该工具能够正常工作基于以下前提:
- Peer 双方的NAT出口能够接受任意主机发送网络包
wgsd的原理如下:
- 部署一个 WireGuard Peer 作为注册中心,该中心有一个稳定公网IP,所有NAT后的Peer主动连接到注册中心。
- 注册节点上部署CoreDNS插件,插件基于DNS-SRV来发布注册中心上的所有Peer信息
- NAT Peer 上配置所有 Nat Peer 的公钥,而不配置 EndPoint
- 每个Nat Peer 上有定时运行的wgsd-client程序,该程序根据Peer的公钥去DNS上查询其对应EndPoint,并更新到本地。
上述 WireGuard Peer 直连的方案实际上是基于nat 打洞来工作的,并非在所有环境都能成功。
通常情况下NAT包括以下四种工作模式:
- Full cone NAT:一个内部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有发自iAddr:port1的包都经由eAddr:port2向外发送,任意外部主机都能通过给eAddr:port2发包到达iAddr:port1。
- Address-Restricted cone NAT:一个内部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有发自iAddr:port1的包都经由eAddr:port2向外发送。任意外部主机(hostAddr:any)通过给eAddr:port2发包到达iAddr:port1的前提是:iAddr:port1之前发送过包到hostAddr:any. “any"也就是说端口不受限制。
- Port-Restricted cone NAT:在Address-Restricted cone NAT的前提下,任意外部主机(hostAddr:port3)通过给eAddr:port2发包到达iAddr:port1的前提是:iAddr:port1之前发送过包到hostAddr:port3。
- Symmetric NAT:对每个外部主机或端口的会话都会映射为不同的端口。
实际场景中,设备可能工作在多层NAT之后,处在一种混合模式的场景下,除非是一些云服务商专门提供的NAT主机,否则上面这个工具基本没什么卵用。
NAT打洞是P2P技术中非常重要的内容,可以参考以下资料学习:
结论
当前github上有许多基于WireGuard的有趣开源项目,包括以下:
最后,本文是从个人的学习笔记中整理而来的。没有经过详细验证,可能存在错漏之处,请各方大佬见谅。
参考
文章作者 yoaz
上次更新 2022-02-26
许可协议 MIT