VPN技术


VPN简介

VPN,即虚拟专用网络(Virtual Private Network),以下从基本概念、工作原理、主要类型、应用场景及相关法律法规等方面进行介绍:

基本概念

VPN是一种通过互联网在公用网络上建立专用网络,进行加密通讯的技术。它可以让用户的设备在公共网络环境下,如咖啡店、机场的免费Wi-Fi,像在专用网络中一样安全地传输数据,保护用户的网络隐私和安全。

工作原理

  • 隧道技术:这是VPN的核心技术,它将原始数据封装在新的数据包中,通过互联网传输。就好像在互联网这个大的公共道路上,为数据开辟了一条专用的“隧道”,数据在这个“隧道”中传输,不会受到外界的干扰和窥探。
  • 加密技术:对传输的数据进行加密处理,确保数据的保密性和完整性。只有合法的接收方才能使用特定的密钥对数据进行解密,获取原始信息。

  • 身份认证技术:用于验证用户或设备的身份,确保只有授权的用户能够访问VPN网络。常见的身份认证方式有用户名/密码认证、数字证书认证等。

主要类型

  • 远程访问VPN:主要用于个人用户远程访问企业内部网络。比如员工在家办公时,通过远程访问VPN连接到公司的内部网络,就可以像在公司办公室一样访问公司的资源,如文件服务器、数据库等。
  • 站点到站点VPN:通常用于连接企业的多个分支机构或不同的办公地点。它可以将不同地点的局域网连接起来,形成一个虚拟的广域网,使各个分支机构之间能够安全、高效地进行数据传输。

应用场景

  • 企业办公:方便员工在外出差或在家办公时安全地访问企业内部资源,提高工作效率,同时保障企业数据的安全。

  • 跨境业务:企业在全球范围内开展业务时,通过VPN可以在不同国家和地区的分支机构之间建立安全的通信通道,实现数据的共享和协同工作。

  • 个人隐私保护:用户在使用公共网络时,通过VPN可以隐藏自己的真实IP地址,加密网络流量,防止个人信息被窃取或监控,保护个人隐私。

法律法规

在中国,使用未经电信主管部门批准的VPN等“翻墙”设备或软件属于违法行为。只有通过电信主管部门批准设立的专用通道,企业和个人才能合法地建立VPN连接。对于企业来说,需要向电信主管部门提交申请,说明VPN的使用目的、范围、技术方案等,经过审核批准后才能建设和使用。个人用户如果有访问境外合法网站或资源的需求,也应该通过正规的、合法的渠道,如申请特定的网络服务等。 VPN在网络安全和远程访问等方面发挥着重要作用,但在使用时必须遵守相关法律法规和规定,确保合法、安全地使用。

搭建OpenVPN服务

生成所需密钥和证书

OpenVPN 使用 Easy-RSA 来管理PKI所需要的密钥和证书. Easy-RSA 现在有2和3两个主要版本, 使用方式略有不同. 下面分别介绍用法. 可以根据自己使用的版本选择一种来操作.

Easy-RSA 2

安装

在Ubuntu 上使用 apt 安装的是Easy-RSA 2:

# apt-get install -y easy-rsa

安装完成后, 可以在 /usr/share/easy-rsa/目录下找到生成密钥对和证书的脚本. 这些脚本会将生成的密钥和证书放在当前目录, 为了安全, 我们将这些脚本复制到 /root目录下:

# cp -r /usr/share/easy-rsa /root
生成CA密钥和证书

接下来的操作都是在 /root/easy-rsa 目录下进行的.

首先, 我们需要生成CA根密钥和证书, 用来给VPN Server和Client的证书进行签名.

  1. 修改 vars 文件 vars 文件里定义了后续生成密钥和证书所需要的环境变量. 在文件里找到定义 KEY_COUNTRY, KEY_PROVINCE, KEY_CITY, KEY_ORG, 和 KEY_EMAIL 变量的部分, 根据自己的实际情况修改为需要的值. 这几个值都不能留空. 如下
export KEY_COUNTRY="CN"
export KEY_PROVINCE="BJ"
export KEY_CITY="BJ"
export KEY_ORG="MyCompany"
export KEY_EMAIL="support@mycompany.com"
其它变量的意义可以参考文件中的注释, 一般不需要修改.
修改保存后, 执行以下命令来使这些变量生效供后续操作使用:
# source ./vars
  1. 生成密钥和证书 接下来执行以下脚本来生成CA的密钥和证书
# ./build-ca
脚本会提示确认证书和密钥所需的字段, 默认值是在 *vars* 文件里指定的. 脚本执行完后, 会在 *keys* 目录下生成CA的密钥 *ca.key* 和证书 *ca.crt* .
生成VPN Server密钥和证书

有了CA密钥和证书, 就可以生成VPN Server所需要的密钥和证书了. 执行以下脚本:

# ./build-key-server myvpn

脚本需要一个参数来指定证书和密钥的CN, 这里就是 myvpn , 根据自己的需要来指定对应的值. 脚本在执行时, 同样会提示需要确认和输入的字段值. 脚本执行完成后, 同样会在 keys 目录下生成VPN Server的密钥和证书. 密钥和证书的文件名前缀都是指定的CN, 后缀分别是 crtkey . 在这里就是 myvpn.crt 和 myvpn.key .

生成Client密钥和证书

Client端同样需要CA签名过的密钥和证书来. 执行以下脚本:

# ./build-key tom

类似于VPN Server的密钥证书生成脚本, 这个脚本参数同样是Client的CN. 根据提示确认和输入必要参数后, Client所需的密钥 tom.key 和证书 tom.crt 也会保存在 keys 目录下.

对于每个Client, 都需要生成一套密钥和证书.

生成Diffie Hellman参数

Diffie Hellman参数用于VPN Server和Client之间进行公钥交换. 执行以下脚本:

# ./build-dh

这个脚本执行完成以后, 可以在 keys 目录下找到生成的文件 dh2048.pem . 文件名中的2048是密钥长度, 可以在 vars 文件中设置, 默认为2048.

Easy-RSA 3

安装

在CentOS7上, 首先要确认是否安装了 epel 源:

# yum repolist

如果源列表中没有 epel 源, 需要安装:

# yum install -y epel-release

然后就可以安装 easy-RSA 了:

# yum install -y easy-rsa
# yum list installed easy-rsa

可以看到这里安装的是 Easy-RSA 3 . 安装目录在 /usr/share/easy-rsa . 对于不同的具体版本, 这个目录下的内容可能会有不同:

# ls -l /usr/share/easy-rsa/
总用量 4
lrwxrwxrwx 1 root root    5 7月  16 18:21 3 -> 3.0.3
lrwxrwxrwx 1 root root    5 7月  16 18:21 3.0 -> 3.0.3
drwxr-xr-x 4 root root 4096 7月  16 19:41 3.0.3

如以上情况中, 实际的安装目录在 3.0.3 子目录下. 为了安全, 将安装目录复制到 /root目录下:

# cp -r /usr/share/easy-rsa/3.0.3 /root/easyrsa

后续密钥和证书操作都在 /root/easyrsa 目录下进行.

生成CA密钥和证书

在生成密钥和证书前, 需要进行初始化:

# ./easyrsa init-pki

这个操作会在当前目录下创建 pki 子目录, 接下来的操作生成的文件都会保存在这个子目录里. 如果这个 pki 子目录已经存在, 这个操作会将子目录下所有的文件清空. 所以, 如果希望重新生成所有的密钥和证书资源, 也可以使用这个命令.

接下来就可以生成CA的密钥和证书了:

# ./easyrsa build-ca

这个命令会要求输入密钥的密码和证书的CN. 这个密钥在后续给VPN Server和Client的证书签名里, 会用到. 命令完成后, 会在 pki 目录下生成密钥文件 ca.key 和证书文件 ca.crt . 有了CA的密钥和证书, 就可以生成VPN Server和Client的密钥和证书了.

生成VPN Server的密钥和证书

首先, 需要生成Server的密钥和签名请求:

# ./easyrsa gen-req myvpn

命令的输入参数是使用这套密钥和证书的实体名, 这个名字会用来标识生成的文件, 并作为证书默认的CN. 同样, 这个命令会提示输入密钥密码和CN. 其中密钥在后续启动VPN Server时需要验证, 而CN的默认值就是命令的参数. 命令完成后, 会在 pki/reqs 下生成签名请求文件, pki/private 下生成密钥文件. 在这个例子中文件名分别为 myvpn.reqmyvpn.key .

然后对生成的请求进行签名, 生成VPN Server的证书:

# ./easyrsa sign-req server myvpn

这个命令接收两个参数, 第一个是证书类型, 这里是 server , 第二个是证书使用的实体名, 需要和上一步生成签名请求的实体名一致, 这里同样为 myvpn . 命令会提示要求确认证书信息, 并输入CA的密钥密码. 命令执行完成后, 会在 pki/issued 目录下生成CA签名的证书, 在这个例子里, 文件名是 myvpn.crt .

生成VPN Client的密钥和证书

生成Client需要的密钥和证书与生成Server的密钥和证书基本一致. 比如我们希望创建一个为用户 tom 创建密钥和证书:

# ./easyrsa gen-req tom
# ./easyrsa sign-req client tom

唯一的不同是 sign_req 的第一个参数需要指定为 client . 以上两个命令执行完成后, 会生成文件 pki/private/tom.key , pki/reqs/tom.reqpki/issued/tom.crt .

生成Diffie-Hellman参数文件

为了在Server和Client之间交换密钥, 需要生成Diffie-Hellman参数文件:

# ./easyrsa gen-dh

命令执行完成后, 会在 pki 目录下生成长度为2048位的Diffie-Hellman参数文件 dh.pem .

安装和配置VPN Server

安装

在Ubuntu下, 执行

# apt-get install -y openvpn

在CentOS下, 需要首先确认安装了 epel 源, 然后执行以下命令来安装 OpenVPN :

# yum install -y openvpn

配置

OpenVPN 安装完成后, 可以在 /usr/share/doc/openvpn 目录下找到示例配置文件. 目录在不同的版本或者Linux下可能会略有不同, 比如 /usr/share/doc/openvpn-2.4.6 , 目录结构也会略有不同. 将 server.conf 文件复制到 /etc/openvpn/server 目录下, 命名为VPN Server的CN. 如果没有这个目录, 可以手动创建.

# cp /usr/share/doc/openvpn/sample/sample-config-files/server.conf /etc/openvpn/server/myvpn.conf

然后将CA的证书, VPN Server的证书和密钥, 以及Diffie-Hellman参数文件复制到 /etc/openvpn/server 目录下:

# cp /root/easyrsa/pki/ca.crt /etc/openvpn/server
# cp /root/openvpn/easyrsa/pki/issued/myvpn.crt /etc/openvpn/server
# cp /root/easyrsa/pki/private/myvpn.key /etc/openvpn/server
# cp /root/easyrsa/pki/dh.pem /etc/openvpn/server/

接下来修改配置文件. 这里只做最基本的修改:

  1. 修改Server密钥和证书文件名 找到 certkey 两个配置项, 原始值分别为 server.crtserver.key . 这里修改为 myvpn.crtmyvpn.key :
cert myvpn.crt
key myvpn.key  # This file should be kept secret
  1. 修改Diffie-Hellman参数文件名 找到 dh 配置项, 修改为 dh.pem :
dh dh.pem
  1. 关闭 TLS-auth 找到 tls-auth 配置项, 如果配置项存在, 将其注释掉或者删除, 因为这里我们没有生成所需要的资源.

激活IP转发

我们使用的是TUN工作模式, VPN Server上需要激活操作系统的IP转发功能, 这样VPN Server才能正常的作为VPN的网关工作.

执行以下命令激活当前系统运行时的IP转发功能:

 # sysctl -w net.inet.ip.forwarding=1

同时, 在 /etc/sysctl.conf 文件中添加

net.ipv4.ip_forward=1

以便在系统重启后, 仍然会自动激活IP转发.

配置防火墙

如果VPN Server所在的操作系统上安装了防火墙, 需要为 OpenVPN 进行配置.

CentOS

首先我们可以通过以下命令查看 OpenVPN 的相关信息:

# firewall-cmd --permanent --info-service=openvpn
openvpn
  ports: 1194/udp
  protocols:
  source-ports:
  modules:
  destination:

上面的配置中, OpenVPN 服务开启的是默认的 1194/udp 端口. 如果我们希望使用非默认端口, 比如 2194/udp , 可以使用以下命令将新端口加入服务配置, 并将原有默认端口删除:

# firewall-cmd --permanent --service=openvpn --add-port=2194/udp
# firewall-cmd --permanent --service=openvpn --remove-port=1194/udp

接下来我们可以查看防火墙的已激活配置:

# firewall-cmd --permanent --list-services
ssh

上面的例子里, 防火墙只激活了 ssh 服务. 我们需要将 OpenVPN 激活

# firewall-cmd --permanent --add-service=openvpn

要使上面的配置生效, 需要重装防火墙配置:

# firewall-cmd --reload

作为系统服务启动

先检查是否有我们希望使用的服务配置文件. 在 /lib/systemd/system 目录下查看是否有 openvpn-server@.service 文件. 如果没有, 复制 openvpn@.service 文件为 openvpn-server@.serivce , 然后将文件中指向 /etc/openvpn 目录的值, 都修改为 /etc/openvpn/server 目录. 例如:

WorkingDirectory=/etc/openvpn/server
ExecStart=/usr/sbin/openvpn --daemon ovpn-%i --status /run/openvpn/%i.status 10 --cd /etc/openvpn/server --script-security 2 --config /etc/openvpn/server/%i.conf --writepid /run/openvpn/%i.pid

有了 openvpn-server@.service 文件, 执行以下命令激活并启动系统服务:

# systemctl enable openvpn-server@myvpn
# systemctl start openvpn-server@myvpn

服务名 openvpn-server@myvpn@ 后面的部分 myvpn/etc/openvpn/server 下配置文件的前缀, 在我们的例子里是 /etc/openvpn/server/myvpn.conf . 可以根据实际的配置情况相应调整.

在启动服务时, 会提示使用 systemd-tty-ask-password-agent 命令输入密码. 在当前终端上直接执行

# systemd-tty-ask-password-agent

然后根据提示输入创建VPN Server密钥时指定的密码.

启动后可以查看服务状态是否为 Active :

# systemctl status openvpn-server@server

启动成功的话, 可以看到一个新增的TUN设备, 因为默认 OpenVPN 是使用TUN. 其IP地址为VIP的子网网关, 默认为10.8.0.1 :

# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:16:3e:13:0e:9c brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.228/24 brd 172.16.0.255 scope global dynamic eth0
       valid_lft 314765499sec preferred_lft 314765499sec
10: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/none
    inet 10.8.0.1 peer 10.8.0.2/32 scope global tun0
       valid_lft forever preferred_lft forever

默认配置下, OpenVPN 的日志输出到系统日志, 可以查看文件 /var/log/syslog 或者使用 journalctl 命令查看.

使用密码文件

在上面的例子中, 启动 OpenVPN 服务时, 需要使用 systemd-tty-ask-password-agent 命令手工输入VPN Server密钥的密码. 这种方式十分不方便, 这里介绍读取密码文件的配置方式.

首先, 在VPN Server配置文件所在的目录下, 将密码保存到和配置文件前缀相同的 .pass 文件里. 在这个例子里, 我们将密码保存到 /etc/openvpn/server/myvpn.pass :

# echo "mypassword" > /etc/openvpn/server/myvpn.pass

接下来修改系统服务的配置文件. 打开 /lib/systemd/system/openvpn-server@.service 文件, 找到 Service部分的 ExecStart 配置项, 在启动命令中添加参数 --askpass %i.pass, 如下例:

ExecStart=/usr/sbin/openvpn --status %t/openvpn-server/status-%i.log --status-version 2 --suppress-timestamps --config %i.conf --askpass %i.pass

保存后, 再创建服务 openvpn-server@myvpn 并启动时, 就会自动读取密码文件中的密码了.

配置Client

不同的系统下使用的 OpenVPN 客户端是不同的, 不过需要的配置和资源是相同的. 这里, 我们先准备Client需要的配置和资源.

在 /root下创建一个目录 vpnclient/tom 来存放用户 tom 所需要的所有资源.

同样, 在 /usr/share/doc/openvpn 下找到 client.conf 文件, 将其复制到 /root/vpnclient/tom 目录下. 然后将CA证书, 以及客户端的密钥和证书也放到这个目录下:

# cp /usr/share/doc/openvpn/sample/sample-config-files/client.conf /root/vpnclient/tom/tom.conf
# cp /root/easyrsa/pki/ca.crt /root/vpnclient/tom
# cp /root/easyrsa/pki/private/tom.key /root/vpnclient/tom
# cp /root/easyrsa/pki/issued/tom.crt /root/vpnclient/tom

接下来修改配置文件, 使其与之前Server端的配置一致.

  1. 指定Server地址 找到 remote 配置项, 将地址和端口改为期望值. 端口默认为1194, 如果Server端没有修改, 这里保留1194的值. 如:
remote myvpn.com 1194
  1. 修改密钥和证书文件名 找到 certkey 配置项, 将其修改为当前用户的文件名, 如:
cert tom.crt
key tom.key
  1. 关闭 TLS-auth 找到 tls-auth 配置项, 如果配置项存在, 将其注释掉或者删除, 因为这里我们没有生成所需要的资源.
客户端安装和运行

不同操作系统需要使用不同的客户端软件, 接下来介绍Linux, Mac OS和Windows上的客户端的主要用法.

后续操作都是将前一步生成好的所有客户端配置文件和资源文件下载到客户端系统后进行的.

Linux

CentOS和Ubunut下也可以和VPN Server端一样直接安装 openvpn , 然后将客户端配置文件放到一个安全的目录, 比如 /root/tom . 接下来有三种方式来启动客户端.

在终端前台运行

进入配置文件目录, 如 /root/tom , 然后执行:

# openvpn --config client.conf

然后命令会提示输入密钥密码, 也就是我们在生成客户端密钥时指定的密码. 命令的日志会在当前终端上输出.

在终端后台运行

在终端后台启动和运行 OpenVPN 时, 程序没有办法从终端获取密码输入, 我们只能使用文件的方式来提供密码. 将密码保存到文本文件里:

# echo "mypassword" > /root/tom/tom.pass

接下来可以在任意目录执行以下命令启动 OpenVPN

# openvpn --config /root/tom/tom.conf --cd /root/tom --daemon --askpass /root/tom/tom.pass

OpenVPN 的日志会出现在系统日志中.

作为系统服务启动

将客户端配置文件, 证书和密钥都复制到 /etc/openvpn/client 目录下, 如果没有 client 目录, 可以手工创建. 然后再将客户端密钥密码保存到 /etc/openvpn/client/tom.pass 文件中. 具体文件名前缀和配置文件保存一致.

在 /lib/systemd/system 目录下查找 openvpn-client@.service 文件. 如果没有, 复制 openvpn@.service 文件为 openvpn-client@.service 文件, 然后将文件中的使用 /etc/openvpn 目录的地方都改为 /etc/openvpn/client 目录. 同时, 在启动命令中添加密码文件参数 --askpass %i.pass . 如下例如示:

WorkingDirectory=/etc/openvpn/client
ExecStart=/usr/sbin/openvpn --daemon ovpn-%i --status /run/openvpn/%i.status 10 --cd /etc/openvpn/client --script-security 2 --config /etc/openvpn/client/%i.conf --writepid /run/openvpn/%i.pid --askpass /etc/openvpn/client/%i.pass

然后就可以激活并启动服务了:

# systemctl enable openvpn-client@tom
# systemctl start openvpn-client@tom

OpenVPN 的日志会出现在系统日志中.

以以上三种方式的任一一种连接VPN成功以后, 可以查看到OpenVPN创建的TUN设备, 类似:

2: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/none
    inet 10.8.0.10 peer 10.8.0.9/24 scope global tun0
       valid_lft forever preferred_lft forever

同时, 也可以PING通VPN网关, 如默认配置下:

# ping -c 5 10.8.0.1
PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
64 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=5.78 ms
64 bytes from 10.8.0.1: icmp_seq=2 ttl=64 time=5.48 ms
64 bytes from 10.8.0.1: icmp_seq=3 ttl=64 time=5.54 ms
64 bytes from 10.8.0.1: icmp_seq=4 ttl=64 time=6.83 ms
64 bytes from 10.8.0.1: icmp_seq=5 ttl=64 time=5.55 ms

--- 10.8.0.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4007ms
rtt min/avg/max/mdev = 5.481/5.841/6.831/0.512 ms

Mac OS

在Mac OS上, 我们需要安装 Tunnelblick客户端来连接VPN.

安装完成后找开 Tunnelblick , 进入 配置 窗口, 再同时打开访达, 进入存放配置, 证书和密钥文件的目录, 然后将配置文件拖入 Tunnelblick 的配置列表

图片

添加完配置后, 选中配置, 然后点击右下角的 连接 来连接到VPN Server

图片

连接成功, 同样可以在终端PING通VPN网关. 如果连接不成功, 可以查看 Tunnelblick 上的日志排查问题.

Windows

Windows系统上, 可以在OpenVPN Community Download页面上找到Windows安装程序的下载地址. 下载并根据提示安装成功后, 在用户目录下会多出一个 OpenVPN 目录. 将客户端配置, 密钥和密钥文件复制到这个目录的 config 子目录下. 接着启动 OpenVPN GUI 程序, 然后可以在右下角提示栏, 在弹出窗口中点击 Settings 来修改配置:

图片

Advance 窗口中, 将 Extension 项改为期望值. 在本例中, 应当为 conf :

图片

保存修改后, 在提示栏中再次点击 OpenVPN 图标, 然后在弹出菜单中点击 Connect 来连接VPN Server:

图片

连接成功后, 可以在 cmd 窗口中PING通VPN网关.