CentOS7.2 搭建OpenVPN 及 用户认证

第一部分: 搭建

环境:Azure OpenLogic(CentOS) 7.2 64位
OpenVPN版本:
OpenVPN 2.3.12 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [MH] [IPv6] built on Aug 23 2016

主要参考教程:https://www.phpini.com/linux/centos-7-install-openvpn-server

安装过程中出现了一些问题,记录如下:


1
2
[vast@vast easy-rsa]$ sudo ./clean-all
[sudo] password for vast:

Please source the vars script first (i.e. “source ./vars”)
Make sure you have edited it to reflect your configuration.

前一步source ./vars成功执行,为何这里就说没有?
解决方法:

  1. 切换到root用户(非必需,保证权限即可)
    [root@vast easy-rsa]# rm -rf keys #删除keys文件夹
  2. [root@vast easy-rsa]# source ./vars
    *NOTE: If you run ./clean-all, I will be doing a rm -rf on /etc/openvpn/easy-rsa/keys*
  3. [root@vast easy-rsa]# ./clean-all #成功

最后搭建好后,按照教程创建本地配置文件后,发现死活连不上。去中科大那找了份能用的配置文件对比,发现……

user-1
dev tun
proto udp
remote your_server_ip 1194
resolv-retry infinite
nobind
persist-key
persist-tun
comp-lzo
verb 3
ca /path/to/ca.crt
cert /path/to/client.crt
key /path/to/client.key

第一行的user-1应该是文件名,不能出现在.ovpn文件中。当然文件名随便取都没关系。最后3行用相对路径,直接用ca.crt、Client.crt、client.key即可。当然也可以用如下格式插入到.ovpn文件中。

1
2
3
4
5
<ca>
#文件内容复制到此处。
</ca>

连上OpenVPN后,分配到的ip是10.8.0.6,发现无法访问外网。一琢磨,估计是通过OpenVPN只能连接服务器的私有子网。仔细想想,VPN应用场景很广泛,要是在商业机构、或者比较重要的组织里,搭好后自动就把转接给做了,很危险的(客户端可以访问服务端所在网络,直接就渗透进内网了)。所以应该是要自己动手设置。

1
sudo bash -c "echo 1 >/proc/sys/net/ipv4/ip_forward"

这一步是开启核心的封包转递(IP forward) 功能。然后测试就能上外网了。
值得注意的是,这个只是临时配置,服务器重启后又失效了。
http://linux.vbird.org/linux_server/0230router.php

鸟哥建议您直接修改系统设定档的内容,那就是 /etc/sysctl.conf来达成开机启动封包转递的功能

1
2
3
4
[root@www ~]# vim /etc/sysctl.conf
#将底下这个设定值修改正确即可!(本来值为0 ,将它改为1即可)
net.ipv4.ip_forward = 1
[root@www ~]# sysctl -p <==立刻让该设定生效

第二部分:用户控制系统

简易脚本

创建一个login.sh到openvpn目录下,加入以下内容。

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
PASSFILE="/etc/openvpn/psw-file"
LOG_FILE="login-auth.log"
TIME_STAMP=`date "+%Y-%m-%d %T"`
###########################################################
if [ ! -r "${PASSFILE}" ]; then
echo "${TIME_STAMP}: Could not open password file \"${PASSFILE}\" for reading." >> ${LOG_FILE}
exit 1
fi
CORRECT_PASSWORD=$(grep -oP "(?<=^$username\s).+$" $PASSFILE)
if [ "${CORRECT_PASSWORD}" = "" ]; then
echo "${TIME_STAMP}: User does not exist: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE}
exit 1
fi
if [ "${password}" = "${CORRECT_PASSWORD}" ]; then
echo "${TIME_STAMP}: Successful authentication: username=\"${username}\"." >> ${LOG_FILE}
exit 0
fi
echo "${TIME_STAMP}: Incorrect password: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE}
exit 1
1
2
3
4
5
6
7
8
chmod +x login.sh
vim server.conf
#加入以下内容,保存
auth-user-pass-verify login.sh via-env
# 账号密码保存在psw-file,日志在login-auth.log(自动创建)。
# 添加用户,格式为 账号 密码
echo test test >> psw-file

值得注意的是,查资料会发现官方也有个login.sh ,不过不能正确读取账号密码。

使用Mysql建立用户体系

假设你已经装好了Mysql,用户名是root,密码是passwd。创建一个数据库名为ov,创建一个表为openvpn用来记录用户。表内有iduserpasssentrecvallmaxendtimeactive等字段。

类似上面。先配置server.conf,加入以下内容

1
2
3
4
5
6
7
8
9
auth-user-pass-verify /etc/openvpn/login.sh via-env
client-disconnect /etc/openvpn/disconnect.sh
client-connect /etc/openvpn/connect.sh
client-cert-not-required
status openvpn-status.txt
log openvpn.log
log-append openvpn.log
verb 3

login.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/sh
user=$usernameuser
rp=$password
mysql -hlocalhost -uroot -ppasswd -e "use ov;SELECT pass FROM openvpn WHERE user='$user';">>log.txt
mysql -hlocalhost -uroot -ppasswd -e "use ov;SELECT recv FROM openvpn WHERE user='$user';">>log.txt
mysql -hlocalhost -uroot -ppasswd -e "use ov;SELECT sent FROM openvpn WHERE user='$user';">>log.txt
mysql -hlocalhost -uroot -ppasswd -e "use ov;SELECT max FROM openvpn WHERE user='$user';">>log.txt
mysql -hlocalhost -uroot -ppasswd -e "use ov;SELECT active FROM openvpn WHERE user='$user';">>log.txt
mysql -hlocalhost -uroot -ppasswd -e "use ov;SELECT endtime FROM openvpn WHERE user='$user';">>log.txt
pass=$(sed -n 2p log.txt)
recv=$(sed -n 4p log.txt)
sent=$(sed -n 6p log.txt)
all=$(sed -n 8p log.txt)
time=$(sed -n 12p log.txt)
now=$(date -d $(date +%Y-%m-%d) +%s)
rm -rf log.txt
if [ "$rp" == "$pass" ] && [ "$active" == "1" ] && [ "$[$recv+$sent]" -lt "$all" ] && [ "$time" -ge "$now" ];
then
exit 0
else
echo $(date +%Y年%m月%d日%k时%M分) "用户登录失败" "账号:"${username} "密码:"${password}>>user_error.log
>>user_error.log
exit 1
fi

connect.sh

1
2
#!/bin/sh
echo $(date +%Y年%m月%d日%k时%M分)"有新的客户端连接 $(date +%Y-%m-%d %k:%M) "ip:"$trusted_ip "端口:"$trusted_port "用户名:"$common_name" >>user_ok.log

disconncet.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/sh
user=$common_name
#user="i"
mysql -hlocalhost -uroot -ppasswd -e "use ov;SELECT sent FROM openvpn WHERE user='$user';">addlog.txt
mysql -hlocalhost -uroot -ppasswd -e "use ov;SELECT recv FROM openvpn WHERE user='$user';">>addlog.txt
recv=$(sed -n 2p addlog.txt)
sent=$(sed -n 4p addlog.txt)
#echo $recv
#echo $sent
recv=$[$recv+$bytes_sent]
sent=$[$sent+$bytes_received]
#recv=$[$recv+123]
#sent=$[$sent+123]
#echo $bytes_sent
#echo $bytes_received
mysql -hlocalhost -uroot -ppasswd -e "use ov;UPDATE openvpn SET sent = '$sent' WHERE user='$user';"
mysql -hlocalhost -uroot -ppasswd -e "use ov;UPDATE openvpn SET recv = '$recv' WHERE user='$user';"
rm -rf addlog.txt

至于添加账号,如果需求小的话可以自己进数据库添加。需求大的话写个脚本也是很方便的。

以上