基于证书认证的OPENVPN搭建实战

最近有个远程接入虚拟局域网的需求,简单的端口映射已经不能解决问题了,横向对比了一下GRE、PPTP、IPSEC、SSLVPN和OPENVPN,最后综合兼容性、易用性、跨平台性选择了OPENVPN的开源版本。

实验环境:

服务 版本 IP
内网Ubuntu 20.04.1 172.17.2.9
公网网关 Null 10.30.68.10
公网Client Null 10.30.68.69

实验目的:

  • 使公网Client可以获取内网172.17.2.0/24上的资源

先决条件:

  • 网关将UbuntuOVPN端口映射至UDP-10.30.68.10:1194上
  • Ubuntu可以访问互联网

实验步骤:

一、更新apt源、安装所需软件

1
ubuntu@ubuntu:~$ sudo apt update && sudo apt -y install openvpn easy-rsa openssl

二、建立公钥基础设施(根CA)

先将easy-rsa目录复制到/etc/openvpn下,这将确保更新软件包时不会丢失对脚本的任何更改。

1
2
ubuntu@ubuntu:/etc/openvpn$ sudo mkdir /etc/openvpn/easy-rsa/
ubuntu@ubuntu:/etc/openvpn$ sudo cp -r /usr/share/easy-rsa/* /etc/openvpn/

签发根CA证书:

1
2
3
ubuntu@ubuntu:/etc/openvpn$ cd /etc/openvpn/easy-rsa/
ubuntu@ubuntu:/etc/openvpn/easy-rsa$ sudo ./easyrsa init-pki
ubuntu@ubuntu:/etc/openvpn/easy-rsa$ sudo ./easyrsa build-ca nopass

三、签发服务器证书

1
ubuntu@ubuntu:/etc/openvpn/easy-rsa$ sudo ./easyrsa build-server-full server nopass

这里同样会询问一些生成证书的常见问题

同样因为实验环境,均选择默认值即可。

所有证书和密钥均已在子目录/pki中生成,复制到/etc/openvpn/

1
ubuntu@ubuntu:/etc/openvpn/easy-rsa$ sudo cp pki/{issued/server.crt,private/server.key,ca.crt} /etc/openvpn

生成DH参数:

1
ubuntu@ubuntu:/etc/openvpn$ sudo openssl dhparam -out dh2048.pem 2048

生成tls-auth key

1
ubuntu@ubuntu:/etc/openvpn$ sudo openvpn --genkey --secret /etc/openvpn/ta.key

四、签发客户端证书

VPN客户端也将需要证书来向服务器进行身份验证。通常,需要为每个客户端创建一个不同的证书。

1
2
ubuntu@ubuntu:~$ cd /etc/openvpn/easy-rsa/
ubuntu@ubuntu:/etc/openvpn/easy-rsa$ sudo ./easyrsa build-client-full client1

使用安全方法将以下文件复制到客户端:

  • /etc/openvpn/ta.key
  • /etc/openvpn/easy-rsa/pki/ca.crt
  • /etc/openvpn/easy-rsa/pki/issued/client1.crt
  • /etc/openvpn/easy-rsa/pki/private/client1.key

由于客户端证书和密钥仅在客户端计算机上是必需的,因此应将其从服务器中删除。

五、配置服务端参数

将示例配置文件解压至目录

1
2
ubuntu@ubuntu:/etc/openvpn$ sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/
ubuntu@ubuntu:/etc/openvpn$ sudo gzip -d /etc/openvpn/server.conf.gz

配置服务端参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
ubuntu@ubuntu:/etc/openvpn/server$ sudo vi server.conf
# listen on? (optional)
;local a.b.c.d
port 1194
proto udp
#定义IP端口
dev tun
#定义模式
ca ca.crt
cert myserver.crt
key myserver.key
dh dh2048.pem
#定义证书
server 10.8.0.0 255.255.255.0
#定义服务器与客户机隧道之间的ip段
ifconfig-pool-persist /var/log/openvpn/ipp.txt
#定义与客户端虚拟ip的对应关系,冷启动可为客户分配与之前相同的ip
push "route 172.17.2.0 255.255.255.0"
#推送给客户机的路由条目
;push "redirect-gateway def1 bypass-dhcp"
#推送给客户机默认路由,令其全部流量均通过VPN

;duplicate-cn
#如果不同客户会使用同样的证书登录,则需取消注释此行
keepalive 10 120
#10秒ping一次,共计120秒超时即强制断开
tls-auth ta.key 0
#通过takey创建"HMAC firewall"以帮助阻止DoS攻击和UDP端口泛洪

cipher AES-256-CBC
#选择加密方式
persist-key
persist-tun
#persist选项将尝试避免在重新启动时访问某些资源,这些资源由于特权降级而可能不再可访问。

status /var/log/openvpn/openvpn-status.log
verb 1
#日志输出等级
explicit-exit-notify 1
#通知客户端服务器重新启动后,它可以自动重新连接。

六、启动OpenVPN服务

注意:openvpn使用模板化的systemd jobs,如:openvpn@.

如果配置文件名为“server.conf”那么开启所需的命令应该像这样:

1
ubuntu@ubuntu:/etc/openvpn$ systemctl start openvpn@server

如果上面创建的私钥使用了密码,那么还需要导入密码

1
ubuntu@ubuntu:~$ sudo systemd-tty-ask-password-agent

检查OpenVPN是否创建了Tun0接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ubuntu@ubuntu:~$/etc/openvpn# ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:59:f2:34 brd ff:ff:ff:ff:ff:ff
inet 172.17.2.25/24 brd 172.17.2.255 scope global dynamic ens160
valid_lft 67959sec preferred_lft 67959sec
3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel 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

七、配置内核转发和防火墙参数

开启内核转发

1
2
3
ubuntu@ubuntu:~$ sudo vi /etc/ufw/sysctl.conf 
#将以下行的注释取消
net/ipv4/ip_forward=1

开启ufw接收转发的包

1
2
3
ubuntu@ubuntu:~$ sudo vi /etc/default/ufw
#修改以下行的参数
DEFAULT_FORWARD_POLICY="ACCEPT"

添加openvpn的ufw app条目

1
2
3
4
5
ubuntu@ubuntu:~$ sudo vi /etc/ufw/applications.d/openvpn 
[OpenVPN]
title=OPENVPN
description=OPENVPN ports.
ports=1194/udp

这里通过添加源nat来实现路由转发。

在理解逻辑上可以看作VPN拨号的10.8.0.0/24网段是内网,而172.17.2.0/24为外网;而且给客户端push了172.17.2.0的外网路由。因此只开启源net即可实现网段互通。

1
2
3
4
5
6
7
ubuntu@ubuntu:~$ sudo vi /etc/ufw/before.rules
#在文件底部添加以下内容
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.8.0.0/24 -o ens160 -j MASQUERADE
#此处需要根据自身机器外网网卡名称修改
COMMIT

启动ufw

1
2
3
4
ubuntu@ubuntu:~$ sudo ufw reload
ubuntu@ubuntu:~$ sudo ufw allow OpenSSH
ubuntu@ubuntu:~$ sudo ufw allow OpenVPN
ubuntu@ubuntu:~$ sudo ufw enable

八、配置客户机参数

客户机参数可以参考/usr/share/doc/openvpn/examples/sample-config-files/client.conf示例文件

也可使用https://github.com/graysky2/ovpngen配置生成器生成ovpn.file

记得将客户机连接的ip换成映射后的ip和端口