18|VPN:怎样构建安全的企业网络?

你好,我是谢友鹏。

上节课我们学习了如何通过 TLS 协议在公网中安全传输数据。TLS 协议通过在传输层和应用层之间添加一层安全协议,实现了加密、认证和完整性校验。然而,TLS 更适用于点对点的安全通信场景,对于某些需要更通用解决方案的情况,TLS 并不是最优选择。

例如,一个公司的多个办公地点希望通过公网连接,形成一个逻辑上的统一网络,不仅需要确保通信的安全性,还希望异地操作能像局域网内一样方便,比如访问远程办公的共享文件夹,而不需要额外的加密配置。此时,VPN(虚拟专用网络)就成为一种理想的解决方案,它通过在网络层建立安全的隧道,既满足了数据加密的需求,又让跨网络的操作更加流畅和便捷。

VPN 原理

在正式讲解今天的内容之前,需要说明一下,这节课讨论的 VPN 特指工作在 IP 层、具有安全功能的 VPN,不包括基于 SSL 的 VPN(如 OpenVPN)

VPN是什么?

VPN(Virtual Private Network,虚拟专用网)是一种通过公共网络来安全地扩展专用网络的技术。我画张图来帮助你更直观地理解它的作用。

如上图所示,VPN 通过在公共网络中创建一个虚拟的、加密的隧道,使用户可以安全地在公共网络上传输数据,仿佛他们的设备直接连接到了专用网络上一样。这种技术不仅提升了专用网络的功能和安全性,还可以让用户在公共网络上访问原本无法直接访问的资源,因此 VPN 常被应用于远程办公、跨分支机构组网等场景。

怎样既安全又通用?

简单来说,VPN的核心理念就是“公网私用”。那它是如何做到既安全又通用的呢?其实,其安全机制和TLS类似,无外乎是加密、认证、完整性校验和防重放。与 TLS 不同的是,用于企业组网的VPN 通常不是在传输层和应用层之间插入安全协议,而是在网络层(IP 层)实现了这些功能

我画了一张TLS和VPN在TCP/IP模型中的位置和各层的典型协议,方便你更直观地理解。


如上图所示,因为VPN工作在网络层,无论上层应用协议是什么(比如应用层是 HTTP、WebSocket、ftp,或比如传输层使用TCP或UDP),所有数据最终都会通过 IP 层传输。因此,VPN 可以对任意基于 IP 的通信进行加密和保护。而不需要像TLS那样在每个协议上都要自己再套一层TLS的壳。

IPSec vs WireGuard

工作在IP层的VPN协议中,IPSec协议是目前网络设备中支持最广泛的协议,同时被Linux之父誉为“艺术品”的WireGuard协议也值得关注。我列了个表格对比了两种协议的特性。

通过以上对比可以看出,IPSec的优势在于存量网络设备支持较为完善,缺点在于复杂度高。而WireGuard优势在于简洁,已经被集成到了Linux内核,但是传统的网络设备支持有限。

组网

对 VPN 有了初步的认识后,我们继续学习其组网知识。不同子网的用户能够像直连到专用网络上一样,跨越公网发送和接收数据,主要归功于 VPN 的加解密功能不在客户端进行,而是通过 VPN 网关来完成。因此,对于用户来说,只需要将流量通过路由引导到 VPN 网关,剩下的隧道建立和加解密等功能都由VPN网关处理即可。

虽然部分VPN协议支持传输模式(保留原始 IP,只对 IP 的有效载荷进行加密),但在实际应用中,子网之间的互通一般使用隧道模式,因为隧道模式可以封装完整的IP数据包,适用于更广泛的场景。我绘制了一张典型的隧道模式 VPN 组网图供你参考。

如图所示,子网1和子网2通过两个VPN网关建立了一个安全的隧道。子网内的设备如果需要与对端子网通信,只需要将目标子网的路由指向本地的VPN网关。这样,数据包就会被发送到VPN网关,而VPN网关会完成数据包的隧道封装和加密。

接下来,我们看一下隧道模式下数据包的封装变化。

如上图所示,当子网1的设备需要访问子网2的设备时,数据包的流转过程如下:

  1. 子网1的设备通过路由,将报文发送到本地VPN网关。

  2. VPN网关接收到数据包后,会对其进行封装。首先,在原始数据包的外层添加一个新的公网IP头,指向对端VPN网关。然后对原始数据包进行加密,生成隧道报文。

  3. 封装好的数据包通过公网发送到对端VPN网关(通常使用UDP协议监听固定端口,比如Wireguard vpn默认使用51820端口,IPSec vpn默认使用500和4500端口)。

  4. 对端VPN网关收到报文后,首先进行解封装,移除隧道头。然后解密报文并完成认证检查。

  5. 解密后的原始数据包会被转发到子网2内的目标设备,像普通路由报文一样处理。

整个过程对于子网中的设备来说是完全透明的。它们既不需要额外配置,也无法感知到跨越公网的过程,仿佛只是在一个局域网内通信。

前面我们是基于子网之间网络打通的场景展开讨论的。对于出差在外的用户,由于无法像子网那样通过固定的 VPN 网关连接到其他子网,他们通常会在自己的终端设备(如笔记本、电脑或手机)上安装 VPN 软件,使自己的设备充当临时的 VPN 客户端网关。通过这种方式,用户可以在外部网络中安全地访问公司内部资源。

关键概念

无论是通过固定网关的子网连接,还是外部用户的临时接入,本质上都是通过路由将流量引导至VPN,然后通过VPN将流量封装进隧道,穿越公网后发送到目的网络所在的VPN。

这里还需要回答几个关键问题:

  1. VPN 网关是怎样知道需要其他VPN保护哪些子网流量的?

  2. VPN 网关又是怎样知道将哪些流量的请求发往哪些 VPN 的?

  3. VPN 网关之间是怎样使用相同的加密、认证等材料的?

这些信息通过 VPN 隧道建立时的 协商(Handshake) 来完成。协商过程主要是为了

确定使用的加密算法、认证算法、交换双方要保护的子网范围等信息。

有些VPN协议还定义了交换密钥方法,比如IPsec协议中的密钥交换协议ike。这里我们可以看看华为文档中IPsec 协议中的 IKE(Internet Key Exchange)与 IPsec 的关系图。

图片
图片来自:support.huawei.com

如上图所示,VPN 隧道建立时,首先会通过 IKE 协议协商出 IKE SA(安全联盟),其中包含密钥。然后,在 IKE SA 的保护下,协商出 IPsec SA,用于加密、认证和保护流量。

相比之下,WireGuard 协议简化了很多流程,没有密钥协议过程,直接使用预先配置的非对称密钥完成隧道建立。

不同VPN有不同的表达方式,我将一些比较共性和关键的概念列个表格方便你理解。

VPN 实战

如果学完这些理论,你还是有些迷糊,那么我们就继续在实战中学习吧。

实验设计

首先,我们来看一下今天实验的网络拓扑图:

如上图所示,假设图172网段的网络是公共网络。今天的目标是通过配置 VPN,在公共网络(172 网段)上建立安全的加密通道,打通两个子网(10.10.1.0/24 和 10.10.2.0/24)的通信。

开始实战

子网的配置需要跟你的实验环境进行调整,后面是我自己的实验环境,可以给毛呢做个参考。

配置子网

首先,我们需要配置两个子网:将 device1 和 vpn1 添加到子网 10.10.1.0/24,device2 和 vpn2 添加到另一个子网 10.10.2.0/24。

让我们来一起完成配置过程。

第一步,创建子网。

在虚拟机中添加两个网络,分别属于 10.10.1.0/24 和 10.10.2.0/24 网段。

具体步骤是这样的。首先,打开 VMware Fusion,进入“设置”->“网络”。然后,解锁网络配置,点击加号 (+) 来添加一个新的虚拟网络。最后,将子网IP和掩码填入。

图片

第二步,将虚拟机添加到对应的子网

依次进入“虚拟机”-“设置”->“添加网络适配器”,选择刚才创建的虚拟网络。

图片

此时登陆虚拟机可以看到新配置的虚拟网卡:

$ ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:c8:e2:26 brd ff:ff:ff:ff:ff:ff
    altname enp2s1
3: ens37: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 00:50:56:26:eb:0a brd ff:ff:ff:ff:ff:ff
    altname enp2s5

第三步,启动网卡并配置 IP。

首先用下面命令启动网卡。

sudo ifconfig ens37 up

然后用下面命令配置ip。

sudo ifconfig ens37 10.10.1.10 netmask 255.255.255.0 up

第四步, 四个虚拟机都配置完成后,我们进行简单的网络验证来验证网络连通性。

此时,device1 与 device2 不通,但在各自子网内部,设备能够互通。而且vpn1 和 vpn2 之间也能正常互通。我们可以用ping验证。

#device1 ping device2 不通
$ ping 10.10.2.20
PING 10.10.2.20 (10.10.2.20) 56(84) bytes of data.
^C
--- 10.10.2.20 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3069ms

#device1 ping vpn1 能通
$ ping 10.10.1.2
PING 10.10.1.2 (10.10.1.2) 56(84) bytes of data.
64 bytes from 10.10.1.2: icmp_seq=1 ttl=64 time=1.33 ms
64 bytes from 10.10.1.2: icmp_seq=2 ttl=64 time=1.16 ms

#vpn1 ping vpn2 能通
$ ping 172.16.253.138
PING 172.16.253.138 (172.16.253.138) 56(84) bytes of data.
64 bytes from 172.16.253.138: icmp_seq=1 ttl=64 time=2.14 ms
64 bytes from 172.16.253.138: icmp_seq=2 ttl=64 time=1.21 ms

#vpn2 ping device2 能通
$ ping 10.10.2.20
PING 10.10.2.20 (10.10.2.20) 56(84) bytes of data.
64 bytes from 10.10.2.20: icmp_seq=1 ttl=64 time=0.859 ms
64 bytes from 10.10.2.20: icmp_seq=2 ttl=64 time=1.46 ms

配置 VPN

搞定子网后,我们就可以开始配置vpn了。首先安装wireguard相关工具。

sudo apt install wireguard-tools

然后在两个VPN上生成各自的私钥和公钥。我已经生成的公私钥为vpn1的privatekeypublickey,vpn2的privatekeypublickey,你也可以直接使用。

#生成私钥
wg genkey > privatekey
#生成公钥
wg pubkey < privatekey > publickey

参照vpn1的配置文件/etc/wireguard/wg0.conf和vpn2的配置文件/etc/wireguard/wg0.conf,进行修改,然后用后面的命令启动VPN。

$ sudo wg-quick up wg0

两边的VPN都启动后,可以查看一下VPN的状态。

vpn1:~$ sudo wg show
interface: wg0
  public key: YiL95lWnimaMT4Zj5orOqADBxwf+bLKx3Y7OF5yQ4S8=
  private key: (hidden)
  listening port: 51820

peer: rZqn0uL9IiNA2sWrVkbTymPiTgpWbBkByTH1/QHBRRA=
  endpoint: 172.16.253.138:51820
  allowed ips: 10.10.2.0/24

配置被保护流量的路由

VPN隧道建立完成后,我们需要在子网设备上配置路由,使得流量能够通过VPN隧道转发到对端子网。如下操作,device1上配置去对端网段的路由都以vpn1为网关。

#device1上配置去10.10.2.0/24网段的流量,都以vpn1为网关
$ sudo ip route add 10.10.2.0/24 via 10.10.1.2 dev ens37

#验证一下去device2的路由是否生效
$ ip route get  10.10.2.20
10.10.2.20 via 10.10.1.2 dev ens37 src 10.10.1.10 uid 1000

同理,device2上配置去对端网段的路由都以vpn2为网关。

#device2上配置去10.10.1.0/24网段的流量,都以vpn2为网关
$ sudo ip route add 10.10.1.0/24 via 10.10.2.2 dev ens37

#验证一下去device1的路由是否生效
$ ip route get 10.10.1.10
10.10.1.10 via 10.10.2.2 dev ens37 src 10.10.2.20 uid 1000
    cache

至此,配置结束,我们在device1上访问一下device2,会发现可以连通了。

$ ping 10.10.2.20
PING 10.10.2.20 (10.10.2.20) 56(84) bytes of data.
64 bytes from 10.10.2.20: icmp_seq=1 ttl=62 time=4.47 ms
64 bytes from 10.10.2.20: icmp_seq=2 ttl=62 time=3.16 ms
64 bytes from 10.10.2.20: icmp_seq=3 ttl=62 time=3.24 ms
64 bytes from 10.10.2.20: icmp_seq=4 ttl=62 time=3.22 ms

如果你想继续观察一下VPN报文,使用sudo wg-quick down wg0 关闭VPN功能,然后启动VPN和流量访问的时候,使用下面命令在VPN上抓包。

$ sudo tcpdump -i any port 51820 -w wireguard.pcap

我们可以用Wireshark打开抓包文件wireguard.pcap,它并没有暴露子网流量的IP,还对数据进行了加密。

好,我们的VPN实验到此结束。

小结

今天的内容就是这些,我给你准备了一个思维导图回顾要点。

这节课我们了解了VPN的原理与应用场景。在公共网络中,VPN 通过创建加密隧道,将多个地理位置分散的网络节点逻辑上连接成一个安全的专用网络。这使得跨网络的操作如同在同一局域网内一样便捷。

然后,我们对比TLS和VPN工作等网络层,分析了其具备更高的通用性的原因。

之后,我们对比了两种典型的 VPN 协议:IPsec 和 WireGuard。IPsec 以广泛的设备兼容性见长,但复杂度较高。而 WireGuard 则以简单高效著称,适合现代化需求。再之后,我们学习了VPN打通子网场景的组网,还了解了一些关键概念。

最后,我们将在实践中学习了如何配置 WireGuard VPN 隧道,实现跨子网的互联互通,建议你课后也动手试试看。

思考题

  1. 通过这节课的学习,你明白 VPN 的隧道究竟是什么了吗?

  2. 使用 VPN 的隧道模式从理论上自己的IP地址会被包含在隧道里面了,那从管控者的角度出发,还有什么办法知道你的原始IP地址吗?

欢迎你在留言区和我交流互动,如果这节课对你有启发,也推荐你分享给身边更多朋友。

精选留言

  • 美妙的代码

    2025-03-21 01:17:14

    wireguard 使用的场景是,两个独立网络都需要公网IP吗? 不能在两个普通家用网络环境下,打通两个环境下的网络。
    作者回复

    VPN能工作的前提是VPN网关的四层网络能通,而且互通的两端至少有一端能listen接收到外部报文 。家庭网络因为nat 的缘故是没法主动listen 接收外部报文的,所以wireguard 没办法直接打通两个家庭网络。如果你想实现家庭网络直接互通,可以看一下p2p网络相关资料,通过nat 打洞是有可能实现的,具体情况还取决于两个家庭网络的nat 类型。

    2025-03-21 12:40:12