Rosenpass
Rosenpass 是一种开源的抗量子安全密钥交换协议,旨在保护 WireGuard VPN 连接免受未来量子计算威胁。Rosenpass 与 WireGuard 并行运行,将抗量子安全的共享密钥注入 WireGuard 的预共享密钥接口。所有 VPN 流量仍然只通过 WireGuard 传输,WireGuard 的二进制文件和协议保持不变,保留了 WireGuard 本身的所有安全保证。
Rosenpass 使用 Rust 编写,主要开发工作在 GitHub 上协调,并根据 MIT 和 Apache 2 许可证发布。
安装
安装 rosenpass 包,该包提供了 Rosenpass 及其辅助工具 rp。
测试
为了快速测试安装是否成功,请运行 rosenpass 和 rp 这两个工具并带有 help 命令,以显示简短的使用提示。
$ rosenpass help
$ rp help
配置
本节介绍如何在两台设备之间设置增强型 Rosenpass WireGuard 连接。技术上来说,这两台设备之间没有区别。但为清晰起见,我们将它们命名为 server 和 client。
准备密钥对
每台设备都需要生成一个由密钥和公钥组成的密钥对。
为双方生成密钥
以下命令生成密钥并将它们存储在新创建的 server.rosenpass-secret 和 client.rosenpass-secret 目录中。
[server]$ rp genkey server.rosenpass-secret
[client]$ rp genkey client.rosenpass-secret
提取公钥
以下命令计算公钥并将它们存储在新创建的 server.rosenpass-public 和 client.rosenpass-public 目录中。
[server]$ rp pubkey server.rosenpass-secret server.rosenpass-public
[client]$ rp pubkey client.rosenpass-secret client.rosenpass-public
将每个 -public 目录复制到另一方
双方都需要对方的 -public 目录,并且需要将其放置在已存在的 -secret 和 -public 目录旁边。如果您有两台机器的 SSH 访问权限,可以使用以下命令:
[server]$ scp -r server.rosenpass-public user@client:/path/to/directory
[client]$ scp -r client.rosenpass-public user@server:/path/to/directory
这样就完成了密钥对的设置。
启动增强型 Rosenpass WireGuard VPN
在以下两个命令中,将 $SERVERIP 替换为客户端可以访问服务器的 IP 地址。这可能是一个公共可路由的 IP 地址、本地网络中的 IP 地址,甚至是回环地址 127.0.0.1。
同样,将 $DEVICE 替换为服务器接收 $SERVERIP 数据包的网络设备的名称。
您可以使用以下命令查找有关网络设备和 IP 地址的信息:
[server]$ ip a
启动 VPN
在 server 和 client 上启动 Rosenpass 和 WireGuard 进程。这将创建一个名为 rosenpass0 的 WireGuard 网络接口,允许在下一步分配内部 IP 地址,并为内部网络添加路由。
在以下两个命令中,请记住将 $SERVERIP 替换为 client 可以访问 server 的 IP 地址。
[server]# rp exchange server.rosenpass-secret \ dev rosenpass0 \ listen $SERVERIP:9999 \ peer client.rosenpass-public \ allowed-ips 192.168.21.0/24
[client]# rp exchange client.rosenpass-secret \ dev rosenpass0 \ peer server.rosenpass-public \ endpoint $SERVERIP:9999 \ allowed-ips 192.168.21.0/24
分配 IP 地址
在此示例中,我们在 VPN 内使用来自内部网络 192.168.21.0/24 的地址。您可以随意尝试其他地址,但请确保在所有必要的命令中调整 IP 地址和网络。
[server]# ip a add 192.168.21.1 dev rosenpass0
[client]# ip a add 192.168.21.2 dev rosenpass0
为 WireGuard 网络添加路由
验证路由表中是否包含内部网络 192.168.21.0/24 的条目。可以使用以下命令进行此操作:
$ ip route
其输出应包含关于 192.168.21.0/24 网络的一行,并提及 rosenpass0 接口。
… 192.168.21.0/24 dev rosenpass0 scope link …
如果不存在这样的行,可以使用以下命令添加路由:
# ip route add 192.168.21.0/24 dev rosenpass0
请记住在服务器和客户端上都进行验证并执行此操作。
配置防火墙
不确定您是否在防火墙后面?您可以跳过此步骤,如果连接无法正常工作,可以稍后再回来。
在此示例中,服务器需要在两个端口上可访问:9999 用于 Rosenpass 连接,10000 用于 WireGuard 连接。端口 9999 在下一步使用的命令中明确配置。WireGuard 端口由 rp 工具隐式设置为 Rosenpass 端口号加一,在此示例中为 10000。
配置您的防火墙,允许端口 9999 和 10000 上的传入 UDP 数据包。
如果您使用 Uncomplicated Firewall,您可以使用以下命令添加规则,以允许此示例设置所需的传入连接。请记住将 $SERVERIP 替换为客户端可以访问服务器的 IP 地址,并将 $DEVICE 替换为服务器接收 $SERVERIP 数据包的网络设备的名称。
[server]# ufw allow in on $DEVICE \ from any to $SERVERIP \ port 9999 \ proto udp \ comment 'Rosenpass'
[server]# ufw allow in on $DEVICE \ from any to $SERVERIP \ port 10000 \ proto udp \ comment 'WireGuard'
新的防火墙规则应如下所示:
server # ufw status
Status: active To Action From -- ------ ---- $SERVERIP 9999/udp on $DEVICE ALLOW Anywhere # Rosenpass $SERVERIP 10000/udp on $DEVICE ALLOW Anywhere # WireGuard
如果您使用 nftables,您可以使用以下命令添加一条满足 Rosenpass 要求的规则。此命令假定适当的防火墙表和链名称为 filter 和 input;这两种名称在 nftables 的示例配置中是标准的。请记住将 $SERVERIP 替换为客户端可以访问服务器的 IP 地址,并将 $DEVICE 替换为服务器接收 $SERVERIP 数据包的网络设备的名称。
[server]# nft add rule \
inet filter input iif $DEVICE \
udp dport { 9999, 10000 } \
ip daddr $SERVERIP accept
请确保保存此规则,使其在重启后仍然有效。一种方法是将其添加到 /etc/nftables.conf。
验证设置
测试 Rosenpass 握手
作为第一个测试,请检查 Rosenpass 是否成功交换了共享密钥并将其作为预共享密钥 (PSK) 传递给了 WireGuard。
在服务器和客户端上,您可以运行以下命令来查看 WireGuard 当前正在为连接使用的预共享密钥。请注意,这会显示本应保密的加密密钥材料,请注意谁能够看到您计算机的屏幕。
# wg show rosenpass0 preshared-keys
输出应显示一行,由两个 base64 编码的字符串组成,用空格分隔。第二个字符串是预共享密钥。这在两台机器上应该是相同的。Rosenpass 大约每两分钟更改一次。
q1ySvWXjsS2l0Apu2f9YZLw7pLT4+QXfIZVTpMBO01I= (redacted)
同样,在服务器和客户端上,您可以显示 WireGuard 连接的状态。
# wg show rosenpass0
在客户端上,您应该会看到类似以下的输出,其中 $SERVERIP 与之前配置的 IP 地址匹配。
interface: rosenpass0 public key: 1NQJ1iObOnkkWlqDU6bhqGPEjCIIvKTKjI10XE0t7DA= private key: (hidden) listening port: 52922 peer: q1ySvWXjsS2l0Apu2f9YZLw7pLT4+QXfIZVTpMBO01I= preshared key: (hidden) endpoint: $SERVERIP:10000 allowed ips: 192.168.21.0/24
而在服务器上,您应该会看到类似以下的输出,WireGuard 监听端口为 10000。
interface: rosenpass0 public key: q1ySvWXjsS2l0Apu2f9YZLw7pLT4+QXfIZVTpMBO01I= private key: (hidden) listening port: 10000 peer: 1NQJ1iObOnkkWlqDU6bhqGPEjCIIvKTKjI10XE0t7DA= preshared key: (hidden) allowed ips: 192.168.21.0/24
显示的服务器公钥应列为客户端对端 (peer) 的 ID,反之亦然。
如果您想持续监视 WireGuard 隧道和其预共享密钥的当前状态,可以在客户端和服务器上运行以下命令;这在调试时很有用,例如,查看双方是否保持使用相同的预共享密钥并同步交换。此命令将上述两个命令组合起来,每 2 秒重复一次。
# watch 'wg show all; wg show all preshared-keys'
测试 WireGuard 连接
您可以通过从客户端 ping 服务器的内部 IP 地址,反之亦然来测试 WireGuard 连接。
[server]$ ping 192.168.21.2
[client]$ ping 192.168.21.1
从服务器 ping 到客户端的连接可能只有在从客户端 ping 到服务器的连接启动后才能成功。
一切完成,ping 测试也成功了吗?
Rosenpass 现在将大约每两分钟为 WireGuard 生成一个新的 PSK 密钥,并使 WireGuard VPN 连接免受后量子计算机攻击。