Ubuntu 下 OpenVPN 配置

2017/3/26 posted in  linux

安装OpenVPN

一下命令安装openvpn

sudo apt-get -y install openvpn libssl-dev openssl

安装完成后查看相应版本:

openvpn --version

查看版本的目的是后面下载相应的openvpn客户端文件的时候,最好下载相应的版本,否则可能会报错。

安装证书工具

sudo apt-get -y install easy-rsa

制作证书

sudo mkdir /etc/openvpn/easy-rsa/
#把/usr/share/easy-rsa/目录下的所有文件全部复制到/etc/openvpn/easy-rsa/下
sudo cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
sudo vi /etc/openvpn/easy-rsa/vars

# These are the default values for fields
# which will be placed in the certificate.
# Don't leave any of these fields blank.
export KEY_COUNTRY="CN"
export KEY_PROVINCE="HB"
export KEY_CITY="wuhan"
export KEY_ORG="hansap"
export KEY_EMAIL="pengjunjie@hansap.com"
export KEY_OU="hansap"

# X509 Subject Field
export KEY_NAME="hansapextra"


实际上这里KEY_NAME是OpenVPN的名字,

然后使用source vars命令使其生效,如下:

source vars
#运行source vars的时候会有提示,需要使用clean all来清洗,执行clean-all命令会删除,当前目录下的keys文件夹。
./clean-all

制作CA证书

在easy-rsa目录下

./build-ca

输出的全部回车即可。这时在keys目录下面 /etc/openvpn/easy-rsa/keys/可以查看到 ca.crtca.key

把该CA证书的ca.crt文件复制到openvpn的启动目录_etc_openvpn下,如下:

cp keys/ca.crt /etc/openvpn/

ll /etc/openvpn/

制作Server端证书

在easy-rsa目录下面执行

./build-key-server hansapextra

中间有个密码,可以保持为空

这个时候/etc/openvpn/easy-rsa/keys会生成Server端证书 hansapextra.crt,hansapextra.csr,hansapextra.key

创建交换文件

在easy-rsa目录下执行

./build-dh

在目录/etc/openvpn/easy-rsa/keys会生成 dh2048.pem

把vpnilanni.crt、vpnilanni.key、dh2048.pem复制到_etc_openvpn/目录下,如下:

cp keys/hansapextra.crt keys/hansapextra.key keys/dh2048.pem /etc/openvpn/

制作客户端证书

在目录easy-rsa下

./build-key extraclient

一直确认,后面输入密码可以为空

在目录/etc/openvpn/easy-rsa/keys会生成extraclient.crt,extraclient.csr,extraclient.key

配置Server端

Server端的配置文件默认可以从openvpn的样例中拷贝

cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/

cd /etc/openvpn/
#拷贝过来后解压
gzip -d server.conf.gz
root@vpnserver:/etc/openvpn# grep -vE "^#|^;|^$" server.conf
port 1194
proto tcp
dev tun
ca ca.crt
cert hansapextra.crt
key hansapextra.key  # This file should be kept secret
dh dh2048.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 192.168.11.0 255.255.255.0"
push "route 172.16.0.0 255.255.0.0"
keepalive 10 120
comp-lzo
persist-key
persist-tun
status openvpn-status.log
verb 3

做一点解释

  1. proto tcp 代表使用tcp的连接,tcp稳定一些。
  2. dev 使用tun模式。这样更使用与使用路由模式,而tap适合于使用将ip出去。
  3. server 10.8.0.0 255.255.255.0 这里可以随便配置一个子网,注意这里只能填写子网,这个子网是客户端分配的网段。
  4. push "route 192.168.11.0 255.255.255.0" 这里会推送两个路由,后面会讲这个路由怎么用

完成后可以启动

/etc/init.d/openvpn start

netstat -tunlp |grep 1194

#使用status也可以查看状态
/etc/init.d/openvpn start

配置Client 端

windows上配置

将client的ctr 和 key 文件,以及ca.crt文件拷贝到客户端,配置client.conf到客户端。

cp extraclient.crt extraclient.key ca.crt /home/firephoenix/        

cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /home/firephoenix/

配置修改

williamtekiMacBook-Pro:Downloads valentine$ grep -vE "^#|^;|^$" client.conf
client
dev tun
proto tcp
remote 61.183.247.97 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert extraclient.crt
key extraclient.key
ns-cert-type server
comp-lzo
verb 3

安装openvpn for windows客户端,我们可以从这个地址下载,如下:http://build.openvpn.net/downloads/releases/

建议和前面查询的版本相同的版本,如2.3.2版本。

ca.crt,client.conf,extraclient.crt,extraclient.key 四个文件放到一个文件夹中,然后再讲这个文件夹拷贝到c:\Program Files\OpenVPN\config\文件夹下面。

启动OpenVPN的客户端之后就可以看到connect。

配置网络

固定:修改_etc_sysctl.conf,取消这一行的注释:
net.ipv4.ip_forward= 1
然后使之立即生效
sysctl -p

EEEDB226-42C6-4B7D-8BAD-7A3C10EE819F

证书的管理

证书有效期管理

默认的OpenVPN配置,客户端证书有效期是10年。如何自定义客户端证书的时间呢?其实比较简单,编辑vars文件,找到export KEY_EXPIRE=3650这一行,把默认的3650,改为你想设置的天数即可。编辑后保存,运行一次vars,设置好环境变量,再用build-key生成客户端证书,即可。这样一来,客户端证书的有效期,就是你所设置的有效期了。

客户端证书的吊销

和PPTP VPN不一样,PPTP VPN直接删除客户端帐号,就可以了。在OpenVPN中,是通过revoke操作,吊销客户端证书,来实现禁止客户端连接OpenVPN的。
具体的方法如下:

#进入OpenVPN配置文件所在目录
#执行vars,初始化环境
. vars
#使用revoke-full命令,吊销客户端证书
./revoke-full clientName
#clientName是被吊销的客户端证书名称

命令执行后,我们能在keys目录中找到一个文件,名叫:crl.pem ,这个文件中包含了吊销证书的名单。然后,在服务端配置文件中,加入如下一行:

crl-verify crl.pem

最后一步,重启OpenVPN服务,即可

配置管理日志

默认情况下,openvpn server的配置会将日志写入_var_log/syslog 中,这种配置比较难管理,在openvpn中也添加了配置日志的部分。

# By default, log messages will go to the syslog (or
# on Windows, if running as a service, they will go to
# the "\Program Files\OpenVPN\log" directory).
# Use log or log-append to override this default.
# "log" will truncate the log file on OpenVPN startup,
# while "log-append" will append to it.  Use one
# or the other (but not both).
;log         openvpn.log
log-append  openvpn.log

这样在_etc_openvpn/openvpn.log 下面就可以看到相应的登陆日志了。

配置mysql集成OpenVPN用户验证

安装数据库

root@vpnserver:~# apt-get install mysql-server libpam-mysql sasl2-bin

配置数据库

root@vpnserver:~# mysql -uroot -p

#建库
CREATE DATABASE `openvpn` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci

mysql> use openvpn

mysql> GRANT ALL ON openvpn.* TO 'openvpn'@'localhost' IDENTIFIED BY '********';

mysql> CREATE TABLE IF NOT EXISTS `user` (
    -> `username` char(32) COLLATE utf8_unicode_ci NOT NULL,
    -> `password` char(128) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `active` int(10) NOT NULL DEFAULT '1',
    -> `creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    -> `name` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
    -> `email` char(128) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `note` text COLLATE utf8_unicode_ci,
    -> `quota_cycle` int(10) NOT NULL DEFAULT '30',
    -> `quota_bytes` bigint(20) NOT NULL DEFAULT '10737418240',
    -> `enabled` int(10) NOT NULL DEFAULT '1',
    -> PRIMARY KEY (`username`),
    -> KEY `idx_active` (`active`),
    -> KEY `idx_enabled` (`enabled`)
    -> ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE TABLE IF NOT EXISTS `log` (
    -> `username` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
    -> `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    -> `end_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
    -> `trusted_ip` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `trusted_port` int(10) DEFAULT NULL,
    -> `protocol` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `remote_ip` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `remote_netmask` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `bytes_received` bigint(20) DEFAULT '0',
    -> `bytes_sent` bigint(20) DEFAULT '0',
    -> `status` int(10) NOT NULL DEFAULT '1',
    -> KEY `idx_username` (`username`),
    -> KEY `idx_start_time` (`start_time`),
    -> KEY `idx_end_time` (`end_time`)
    -> ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

mysql> exit

修改openvpn配置

nano /etc/pam.d/openvpn

auth sufficient pam_mysql.so user=openvpn passwd=******** host=localhost db=openvpn table=user usercolumn=username passwdcolumn=password where=active=1 sqllog=0 crypt=1

account required pam_mysql.so user=openvpn passwd=******** host=localhost db=openvpn table=user usercolumn=username passwdcolumn=password where=active=1 sqllog=0 crypt=1

其中数据库、用户名、密码按照自己的实际情况设置。

crypt 表示密码在数据库中加密存储的方式,含义如下:
0 (or “plain”):不加密,明文存储。不推荐使用。
1 (or “Y”):使用crypt(3)函数,相当于MySQL 中的ENCRYPT()函数。
2 (or “mysql”):使用MySQL 的PASSWORD()函数。PAM 可能与MySQL 的函数不同,不推荐使用。
3 (or “md5″):使用MD5。
4 (or “sha1″):使用SHA1。

编辑/etc/default/saslauthd

nano /etc/default/saslauthd

START=no改成START=yes

重新启动saslauthd。

/etc/init.d/saslauthd restart

先测试一下配置是否正确,先添加在mysql里面添加一个test用户,密码也是test。

mysql -uopenvpn -p
mysql>

USE openvpn;
INSERT INTO user(username, password) VALUES('test', ENCRYPT('test'));
exit

退出以后,运行

testsaslauthd -u test -p test -s openvpn
如果提示

0: OK "Success."

说明验证通过,如果验证没通过的话,检查一下_var_log/auth.log,看看是什么原因导致的错误。

配置pam验证模块

复制Openvpn的pam验证模块到Openvpn目录:

cp /usr/lib/openvpn/openvpn-plugin-auth-pam.so /etc/openvpn/

重新编辑server.conf

#增加这个配置

# user/password auth from mysql
plugin /etc/openvpn/openvpn-plugin-auth-pam.so openvpn
username-as-common-name
;client-to-client


# record in database,这两行主要做用户登陆记录和流量管控,我们这里不做流量管控,可以修改一下。
script-security 2
client-connect ./connect.sh
client-disconnect ./disconnect.sh

在disconnect里面在端口之后会记录相应的VPN流量。

流量记录

新建一个/etc/openvpn/connect.sh文件。

nano /etc/openvpn/connect.sh

输入以下内容:

#!/bin/bash

DB='openvpn'
DBADMIN='openvpn'
DBPASSWD='password'

mysql -u$DBADMIN -p$DBPASSWD -e "INSERT INTO log(username,start_time,trusted_ip,trusted_port,protocol,remote_ip,remote_netmask,status) VALUES('$common_name',now(),'$trusted_ip',$trusted_port,'$proto_1','$ifconfig_pool_remote_ip','$route_netmask_1',1)" $DB

新建/etc/openvpn/disconnect.sh文件。

nano /etc/openvpn/disconnect.sh

输入以下内容:

#!/bin/bash

DB='openvpn'
DBADMIN='openvpn'
DBPASSWD='password'

mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE log SET end_time=now(),bytes_received=$bytes_received,bytes_sent=$bytes_sent,status=0 WHERE trusted_ip='$trusted_ip' AND trusted_port=$trusted_port AND remote_ip='$ifconfig_pool_remote_ip' AND username='$common_name' AND status=1" $DB

mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=0 WHERE user.username IN (SELECT username FROM (SELECT log.username AS username, quota_bytes FROM user, log WHERE log.username='$common_name' AND log.username=user.username AND log.status=0 AND TO_DAYS(NOW())-TO_DAYS(start_time)< =quota_cycle GROUP BY log.username HAVING SUM(bytes_received)+SUM(bytes_sent)>=quota_bytes) AS u);" $DB

上面的数据库用户名密码替换成你设置的数据库用户名密码。

赋予文件可执行的权限。

chmod +x /etc/openvpn/connect.sh
chmod +x /etc/openvpn/disconnect.sh

其主要作用是:在用户连接时,在数据库log 表中新建一条记录,记录用户的IP 地址、端口号、连接时间等信息。在用户断开连接时,更新刚才添加的记录,记下用户的断开连接时间、发送数据量、接收数据量等。然后,对用户的流量进行判断,若超过配额,则将用户锁定(active=0)。

user 表中的quota_cycle 是用户的流量计算周期,quota_bytes 是用户每个周期内最多允许的流量。connect.sh 和disconnect.sh 脚本文件中调用了OpenVPN 的环境变量。OpenVPN 在执行脚本时,自动各种设置了环境变量,供脚本使用。

使用cron 每天对用户进行检查
以上操作在用户超过流量时自动将用户锁定。每天还应该执行一次检查,把已经恢复流量的用户解锁。可以通过cron实现此功能。

建立文件/etc/cron.daily/openvpn

nano /etc/cron.daily/openvpn

内容如下:

#!/bin/bash
DB='openvpn'
DBADMIN='openvpn'
DBPASSWD='password'
mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=1" $DB
mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=0 WHERE user.username IN (SELECT username FROM (SELECT log.username AS username, quota_bytes FROM user, log WHERE log.username=user.username AND log.status=0 AND TO_DAYS(NOW())-TO_DAYS(start_time)< =quota_cycle GROUP BY log.username HAVING SUM(bytes_received)+SUM(bytes_sent)>=quota_bytes) AS u);" $DB
mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=0 WHERE enabled=0" $DB

同样把上面的数据库用户名密码替换成你设置的数据库用户名密码。

其思路是:先默认将所有用户解锁,然后将超过流量的用户锁定。同时,管理员可以通过user 表中的enabled 字段手工禁用用户。

赋予文件可执行权限:

chmod +x /etc/cron.daily/openvpn

修改saslauthd 的缓存时间。

saslauthd 默认有一段较长的缓存时间,在用户通过认证后的一段时间里,可以再次通过认证而不需要重新查询数据库。这样不利于实现对超流量用户的立即锁定。saslauthd 启动时有一个-t 参数,可以设置其超时时间。

修改/etc/default/saslauthd文件

nano /etc/default/saslauthd

saslauthd 启动时有一个-t 参数,可以设置其超时时间,最后一行的OPTIONS,添加-t 60。

OPTIONS="-c -m /var/run/saslauthd -t 60"

客户端的安装

Windows用户直接下载Windows Installer即可,安装按默认安装就可以了。

接下来在服务器上拷贝三个证书文件下来,分别是ca.crt,client1.key,client1.crt,放到C:\Program Files\OpenVPN\config\目录下,新建一个myvpn.ovpn文件,用记事本打开

client
dev tun
proto udp
remote 服务器ip 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client1.crt
key client1.key
#这里需要一定要增加,否则无法访问
auth-user-pass

push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"

ns-cert-type server
redirect-gateway
keepalive 20 60
comp-lzo
verb 3
mute 20
route-method exe
route-delay 2

非流量监控管理

在disconnect.sh 中去掉相应字段即可

#!/bin/bash

DB='openvpn'
DBADMIN='openvpn'
DBPASSWD='password'

mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE log SET end_time=now(),bytes_received=$bytes_received,bytes_sent=$bytes_sent,status=0 WHERE trusted_ip='$trusted_ip' AND trusted_port=$trusted_port AND remote_ip='$ifconfig_pool_remote_ip' AND username='$common_name' AND status=1" $DB

#mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=0 WHERE user.username IN (SELECT username FROM (SELECT log.username AS username, quota_bytes FROM user, log WHERE log.username='$common_name' AND log.username=user.username AND log.status=0 AND TO_DAYS(NOW())-TO_DAYS(start_time)< =quota_cycle GROUP BY log.username HAVING SUM(bytes_received)+SUM(bytes_sent)>=quota_bytes) AS u);" $DB

将最下面的定期清理相应的超过流量的客户

tips: 这里面应该有个小bug,可以留到后面进行修改,在用户disconnect的时候,仅搜索了4个字段,用户的ip、端口、远程ip、用户名。但是可能出现跨天的情况,而update找到的是第一个,可能日志状态后续会混乱。这里后面还是应该加上相应的时间,至少需要保持更新用户几天之内的。

证书管理

用上面的方法,通过mysql连接的时候,依然需要客户端证书,才能进行登录。

所以针对安全考虑,可以分发不同的证书给不同的组织,然后针对某些组织,再分配相应的账号密码进行安全验证。

证书有效期

默认的OpenVPN配置,客户端证书有效期是10年。如何自定义客户端证书的时间呢?其实比较简单,编辑vars文件,找到export KEY_EXPIRE=3650这一行,把默认的3650,改为你想设置的天数即可。编辑后保存,运行一次vars,设置好环境变量,再用build-key生成客户端证书,即可。这样一来,客户端证书的有效期,就是你所设置的有效期了。

给客户的一些证书可以修改为30天过期,过期之后可以删除再重新生成新的证书

吊销证书

和PPTP VPN不一样,PPTP VPN直接删除客户端帐号,就可以了。在OpenVPN中,是通过revoke操作,吊销客户端证书,来实现禁止客户端连接OpenVPN的。
具体的方法如下:

#进入OpenVPN配置文件所在目录
#执行vars,初始化环境
. vars
#使用revoke-full命令,吊销客户端证书
./revoke-full clientName
#clientName是被吊销的客户端证书名称

命令执行后,我们能在keys目录中找到一个文件,名叫:crl.pem ,这个文件中包含了吊销证书的名单。然后,在服务端配置文件中,加入如下一行:

crl-verify /etc/openvpn/easy-rsa/keys/crl.pem

注意这里路径要对,要么是相对路径,否则openvpn server会起不起来

最后一步,重启OpenVPN服务,即可。

制作客户端说明文档

[[OpenVPN 客户端说明文档]]

制作一个给外部的客户端和用户名密码

生成客户端证书

cd /etc/openvpn/easy-rsa/
./build-key extraclient

将 client文件拷贝出

将 client替换到文件中,修改相关内容