Table of Contents
1. 环境准备
1.1 系统时间设置
如果在本地部署,请更新系统时间为网络时间,打印日志的时间将会更加准确
# 检查是否安装NTP
[root@localhost ~]# yum list installed |grep ntp
# 安装NTP
[root@localhost ~]# yum -y install ntp
# 开启服务
[root@localhost ~]# systemctl start ntpd
[root@localhost ~]# systemctl enable ntpd
# 设置ntp服务器 添加:cn.ntp.org.cn
[root@localhost ~]# vi /etc/ntp.conf
server cn.ntp.org.cn
# 手动校对时间和设置中国时区
[root@localhost ~]# ntpdate cn.ntp.org.cn
[root@localhost ~]# timedatectl set-timezone Asia/Shanghai
# 关闭本地时钟
[root@localhost ~]# timedatectl set-local-rtc 0
# 启动NTP
[root@localhost ~]# timedatectl set-ntp yes
# 同步NTP,4p:ipv4的地址
[root@localhost ~]# ntpq -4p
1.2 SELinux
# 马上生效:禁用SELinux
[root@localhost ~]# setenforce 0
# 永久关闭【需要重启服务器生效】
[root@localhost ~]# sed -i ‘s/SELINUX=enforcing/SELINUX=disabled/g’ /etc/selinux/config
1.3 防火墙
# 禁用firewalld
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# systemctl disable firewalld
# 安装iptables
[root@localhost ~]# yum -y install iptables-services
# 启动iptables,并开机自启动
[root@localhost ~]# systemctl enable iptables
[root@localhost ~]# systemctl start iptables
# 清理所有防火墙规则
[root@localhost ~]# iptables -F
# 添加防火墙规则
## 将 openvpn 的网络流量转发到公网:snat 规则
[root@localhost ~]# iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -j MASQUERADE
## iptables 规则持久化保存
[root@localhost ~]# iptables-save > /etc/sysconfig/iptables
# 规则查看
[root@localhost ~]# iptables -nvL -t nat
1.4 开启系统IP转发
[root@localhost ~]# vi /etc/sysctl.conf
# 最后一行添加或修改参数
net.ipv4.ip_forward=1
# 执行生效
[root@localhost ~]# sysctl -p
2. 安装-证书
2.1 安装easy-rsa 3.0 和OpenVPN和lzop
[root@localhost ~]# yum install -y epel-release
[root@localhost ~]# yum -y install easy-rsa
[root@localhost ~]# yum -y install openvpn
# lzop用来压缩数据使用
[root@localhost ~]# yum -y install lzop
2.2 CA 根证书
# easy-rsa 脚本复制到 /etc/openvpn/
[root@localhost ~]# cp -r /usr/share/easy-rsa/ /etc/openvpn/easy-rsa
[root@localhost ~]# cd /etc/openvpn/easy-rsa/
# 根据easy-rsa的版本进入
[root@localhost 3.0.8]# cd 3.0.8/
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
# 编辑vars 文件
# 说明:vars 文件中定义的变量是用于生成证书的基本信息,没这个文件可新建,填写如下内容(变量值根据实际情况随便填写)
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
[root@localhost 3.0.8]# vi vars
export KEY_SIZE=2048
export KEY_COUNTRY="CN"
export KEY_PROVINCE="GD"
export KEY_CITY="GUANGZHOU"
export KEY_ORG="CORY"
export [email protected]
export KEY_CN=cory
export KEY_NAME=cory
export KEY_OU=cory
# 使变量生效
[root@localhost 3.0.8]# source ./vars
# 初始化 pki 相关目录
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
[root@localhost 3.0.8]# ./easyrsa init-pki
#生成 CA 根证书, 输入 Common Name,名字随便起,这里默认ca。
[root@localhost 3.0.8]# ./easyrsa build-ca nopass
# 生成证书如下
[root@localhost 3.0.8]# find ./ -name ca*
./pki/private/ca.key
./pki/ca.crt
./x509-types/ca
2.3 生成服务务器证书和密钥
# 第一个参数 server 为证书名称,可以随便起,为了下面的配置,请用sever代表
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
[root@localhost 3.0.8]# ./easyrsa build-server-full server nopass
2.4 生成 Diffie-Hellman 算法需要的密钥文件
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
[root@localhost 3.0.8]# ./easyrsa gen-dh
2.5 生成的文件检查
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
[root@localhost 3.0.8]# find ./ -name *server*
./pki/issued/server.crt
./pki/private/server.key
./pki/reqs/server.req
./x509-types/serverClient
./x509-types/server
2.6 生成 tls-auth key
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
[root@localhost 3.0.8]# openvpn --genkey --secret ta.key
[root@localhost 3.0.8]# ll |grep ta.key
-rw------- 1 root root 636 Jan 30 11:52 ta.key
2.7 生成自动吊销用户证书
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
[root@localhost 3.0.8]# ./easyrsa gen-crl
[root@localhost 3.0.8]# ll /etc/openvpn/easy-rsa/3.0.8/pki/crl.pem
-rw------- 1 root root 609 Jan 30 11:52 /etc/openvpn/easy-rsa/3.0.8/pki/crl.pem
# 注意:crl.pem证书的不能移动,否则在后期删除用户认证的时候不生效,保持该目录即可
2.8 整理证书
# 将以上整理好的证书【ca.crt,server.crt,server.key,dh.pem,ta.key】
# 全部放在/etc/openvpn/server/certs/目录下
# 目的是openvpn的配置文件指明统一路径,方便管理
[root@localhost ~]# pwd
/root
[root@localhost ~]# mkdir /etc/openvpn/server/certs
# 进入到/etc/openvpn/server/certs/
[root@localhost ~]# cd /etc/openvpn/server/certs/
# 拷贝CA
[root@localhost ~]# cp /etc/openvpn/easy-rsa/3.0.8/pki/ca.crt ./
# 拷贝根证书
[root@localhost ~]# cp /etc/openvpn/easy-rsa/3.0.8/pki/issued/server.crt ./
[root@localhost ~]# cp /etc/openvpn/easy-rsa/3.0.8/pki/private/server.key ./
# 拷贝DH算法需要的秘钥文件
[root@localhost ~]# cp /etc/openvpn/easy-rsa/3.0.8/pki/dh.pem ./
# 拷贝ta秘钥文件
[root@localhost ~]# cp /etc/openvpn/easy-rsa/3.0.8/ta.key ./
# 查看是否已经拷贝过来
[root@localhost certs]# ll
total 24
-rw------- 1 root root 1135 Jan 30 11:55 ca.crt
-rw------- 1 root root 424 Jan 30 11:55 dh.pem
-rw------- 1 root root 4505 Jan 30 11:55 server.crt
-rw------- 1 root root 1704 Jan 30 11:55 server.key
-rw------- 1 root root 636 Jan 30 11:55 ta.key
3. 配置-OpenVPN
3.1 OpenVPN配置文件
# 版本号是openvpn-2.4.10,注意版本
# 可以在:/usr/share/doc/openvpn-2.4.10/sample/sample-config-files/server.conf 复制一份 demo 到 /etc/openvpn/
[root@localhost ~]# cd /etc/openvpn/
[root@localhost openvpn]# vim server.conf
# ################################
port 1194 # 监听的端口号
proto udp # 服务端用的协议,udp,默认udp
dev tun #TUN 接口下和公司的网络区分开,完全一个虚拟的网络。 dev tap:二层,可以广播
ca /etc/openvpn/server/certs/ca.crt # CA 根证书路径
cert /etc/openvpn/server/certs/server.crt # OpenVPN 服务器证书路径
key /etc/openvpn/server/certs/server.key # OpenVPN 服务器密钥路径
dh /etc/openvpn/server/certs/dh.pem # Diffie-Hellman 算法密钥文件路径
tls-auth /etc/openvpn/server/certs/ta.key 0 # 开启TLS-auth,使用ta.key防御攻击。服务器端的第二个参数值为0【此处必须设置为0】,客户端配置文件要设置为1。
ifconfig-pool-persist ipp.txt #服务器自动给客户端分配IP后,客户端下次连接时,仍然采用上次的IP地址(第一次分配的IP保存在ipp.txt中,下一次分配其中保存的IP)。
push "route 10.0.0.0 255.0.0.0" # # 推送路由和DNS到客户端
push "route 172.21.16.0 255.255.240.0" # 推送路由到客户端,如果内网服务器地址是172.21.16.0的网段,可以增加此行【根据实际情况修改】,然后就可以ping通内网地址的所有服务器
server 10.8.0.0 255.255.255.0 # 该网段为 open VPN 虚拟网卡网段,不要和内网网段冲突即可。open VPN 默认为 10.8.0.0/24
push "dhcp-option DNS 1.1.1.1" # DNS 服务器配置,可以根据需要指定其他 ns
push "dhcp-option DNS 223.5.5.5"
# 客户端所有流量都通过 open VPN 转发,类似于代理开全局,VPN服务器本身要通过客户端原来的网关访问【取消redirect-gateway def1 bypass-dhcp选项后这项必须开启,否则无法访问OpenVPN服务器】
push "redirect-gateway def1"
duplicate-cn # 如果客户端都使用相同的证书和密钥连接VPN,一定要打开这个选项,否则每个证书只允许一个人连接VPN
keepalive 10 120 # 每10秒ping一次,连接超时时间设为120秒。
comp-lzo # 开启VPN连接压缩,如果服务器端开启,客户端也必须开启
client-to-client #设置客户端是否可以访问客户端
persist-key # 持久化选项可以尽量避免访问在重启时由于用户权限降低而无法访问的某些资源。
persist-tun
max-clients 250 # 允许最大的客户端连接数,默认100
user openvpn # open VPN 进程启动用户,openvpn 用户在安装完 openvpn 后就自动生成了
group openvpn
# 默认情况下,日志消息将写入syslog(在Windows系统中,如果以服务方式运行,日志消息将写入OpenVPN安装目录的log文件夹中)。
# 你可以使用log或者log-append来改变这种默认情况。
# "log"方式在每次启动时都会清空之前的日志文件。
# "log-append"这是在之前的日志内容后进行追加。
# 你可以使用两种方式之一(但不要同时使用)。
# log /var/log/openvpn/server.log
log-append /var/log/openvpn/server.log
# 输出一个简短的状态文件,用于显示当前的连接状态,该文件每分钟都会清空并重写一次。
status /var/log/openvpn/status.log
# 为日志文件设置适当的冗余级别(0~9)。冗余级别越高,输出的信息越详细。
#
# 0 表示静默运行,只记录致命错误。
# 4 表示合理的常规用法。
# 5 和 6 可以帮助调试连接错误。
# 9 表示极度冗余,输出非常详细的日志信息。
verb 3
# 重复信息的沉默度。
# 相同类别的信息只有前20条会输出到日志文件中。
mute 20
# 当服务器重启时通知客户端
# 可以自动重新连接。必须和udp一起启动
explicit-exit-notify 1 # 设置断线重连功能
cipher AES-256-CBC #指定数据对称加密算法
reneg-sec 0 #reneg-sec服务器端会定期检查认证情况,默认3600秒一小时,使用OTP的话尽量时间长一些,否则客户端需要重新输入用户名密码和OTP一次性密码。
auth-nocache #断线后防止内存中保存用户名和密码来提高安全性
# 吊销对应用户的 SSL 证书
crl-verify /etc/openvpn/easy-rsa/3.0.8/pki/crl.pem
# ############################
3.2 创建 open VPN 日志目录
[root@localhost ~]# mkdir -p /var/log/openvpn/
[root@localhost ~]# chown openvpn:openvpn /var/log/openvpn
[root@localhost ~]# ll -d /var/log/openvpn
drwxr-xr-x 2 openvpn openvpn 4096 Jan 30 12:07 /var/log/openvpn
3.3 启动OpenVPN服务
# 开启OpenVPN服务
[root@localhost ~]# systemctl start openvpn@server
[root@localhost ~]# systemctl enable openvpn@server
[root@localhost ~]# systemctl status openvpn@server
# 验证
[root@localhost ~]# netstat -antpu | grep openvpn
udp 0 0 0.0.0.0:1194 0.0.0.0:* 24537/openvpn
3.4 公司端口映射
由于公司只有一个公网Ip,所以只能在路由器上做端口映射映射到内网的UDP:1194
4. OpenVPN Client
4.1 创建用户-创建证书
[root@localhost ~]# cd /etc/openvpn/easy-rsa/3.0.8/
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
# 创建张三用户
[root@localhost 3.0.8]# ./easyrsa build-client-full zhangsan nopass
[root@localhost 3.0.8]# find ./ -name *zhangsan*
./pki/issued/zhangsan.crt
./pki/private/zhangsan.key
./pki/reqs/zhangsan.req
4.1.1 客户端配置配置文件.ovpn
client
dev tun
proto udp
# 根据情况修改公网ip地址
remote xxx.xxx.xxx.xxx 1194
# 无需人为重启,即可重新接入VPN
resolv-retry infinite
# 全局数据代理
redirect-gateway def1
# 本机不绑定任何端口监听incoming数据,Client无需此操作,除非一对一的VPN有必要
nobind
# 跟服务器配置一样
persist-key
persist-tun
# 指定采用服务器校验方式
remote-cert-tls server
# TLS加密传输
tls-client
# 开启VPN连接压缩,如果服务器端开启,客户端也必须开启
comp-lzo
# 调试信息级别
verb 3
# 相同类别的信息只有前20条会输出到日志文件中。
mute 20
# 证书合并到配置文件
# ca.crt 文件内容 直接复制ca.crt 文件内容到此处
# 文件路径:/etc/openvpn/server/certs/ca.crt
# client.crt 文件内容,直接复制zhangsan.crt的内容到此处
# 文件路径:/etc/openvpn/easy-rsa/3.0.8/pki/issued/zhangsan.crt
# client.key文件内存 直接复制zhangsan.key的内容到此处
# 文件路径:/etc/openvpn/easy-rsa/3.0.8/pki/private/zhangsan.key
# 证书合并到配置文件
key-direction 1
# ta.key 文件 复制ta.key的内容到此处
# 文件路径:/etc/openvpn/server/certs/ta.key
4.2 删除用户-吊销证书
[root@localhost openvpn]# cd /etc/openvpn/easy-rsa/3.0.8/
[root@localhost 3.0.8]# pwd
/etc/openvpn/easy-rsa/3.0.8
# 删除张三用户,吊销张三的证书
# 注意:必须有/etc/openvpn/easy-rsa/3.0.8/pki/issued/zhangsan.crt文件才能吊销,否者用户吊销不了
[root@localhost 3.0.8]# ./easyrsa revoke zhangsan
[root@localhost 3.0.8]# ./easyrsa gen-crl
# 重启OpenVPN 服务端使其生效
[root@localhost 3.0.8]# systemctl restart openvpn@server
# 检查是否吊销成功,R代表吊销,V代表可用
# 张三的ID为CF82B82E3E5BD53DE3E19FCF3B95D967,时间为210130094137Z【21年01月30日09点41分37秒】【此时间为UTC时间,并非中国时区】
[root@localhost ~]# cd /etc/openvpn/easy-rsa/3.0.8
[root@localhost 3.0.8]# cat pki/index.txt
V 230505092248Z 0554F4B3F53F1CC589834A4F55A3CBF1 unknown /CN=server
R 230505093748Z 210130094137Z CF82B82E3E5BD53DE3E19FCF3B95D967 unknown /CN=zhangsan
# 查看哪些证书被吊销,张三的证书ID为:CF82B82E3E5BD53DE3E19FCF3B95D967
[root@localhost ~]# cd /etc/openvpn/easy-rsa/3.0.8
[root@localhost 3.0.8]# openssl crl -in pki/crl.pem -text -noout
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: /CN=ca
Last Update: Jan 30 10:07:14 2021 GMT
Next Update: Jul 29 10:07:14 2021 GMT
CRL extensions:
X509v3 Authority Key Identifier:
keyid:80:80:7C:93:42:23:3C:00:49:57:5B:7D:DB:96:4F:69:E9:45:99:66
DirName:/CN=ca
serial:AC:66:40:8A:AC:7A:A8:75
Revoked Certificates:
Serial Number: CF82B82E3E5BD53DE3E19FCF3B95D967
Revocation Date: Jan 30 09:41:37 2021 GMT
Signature Algorithm: sha256WithRSAEncryption
89:ef:94:db:60:91:7a:ba:dc:1f:a1:a3:33:78:d2:89:21:b7:
6e:c5:77:d9:10:05:f9:e2:95:dd:37:94:7f:fe:0e:0a:23:57:
f8:ff:e1:f7:81:f2:01:50:b4:46:44:bd:f5:99:35:83:ab:db:
04:96:9e:98:28:58:3e:7d:f4:73:93:65:ae:1f:b3:e5:a2:53:
3c:35:2c:57:2b:e7:4f:f8:21:0f:06:53:12:19:72:42:69:44:
3a:16:fc:28:3d:39:46:9d:b7:a5:cb:23:cb:2a:93:48:88:b4:
9f:98:37:eb:73:5b:59:e3:1e:0e:8d:87:cc:e7:d9:ab:74:f6:
af:d8:1b:bd:37:18:7a:66:cd:06:56:f5:aa:ac:ce:5b:e1:a6:
82:6e:ad:b0:4e:17:b9:85:58:28:6f:d8:62:76:51:6c:46:ef:
19:42:e6:54:9a:d4:dd:74:30:73:f2:16:0d:f4:a8:be:84:02:
0b:fb:8c:ba:9c:fd:17:77:58:53:1a:68:89:02:be:6a:4b:eb:
26:10:e2:af:27:2a:d5:ab:ee:77:ae:07:ee:ce:15:4b:04:74:
b9:76:db:7f:5d:14:09:12:15:5a:df:9f:33:8d:c1:c7:54:61:
c3:a6:61:ab:7e:2a:68:0b:c4:bb:25:b2:21:e6:61:67:ca:63:
82:e5:e4:9a
5. 脚本创建和删除用户
5.1 创建用户
#!/bin/bash
# 如果任何语句的执行结果不是true则应该退出
set -e
# 定义openvpn ip地址
openvpn_ipadd="192.168.10.5"
# 定义openvpn的生成用户秘钥的存储目录
OVPN_USER_KEYS_DIR=/etc/openvpn/client/keys
# 定义已经配置好的ovpn文件
OVPN_USER_CONF_DIR=/etc/openvpn/client/conf
# easy_rsa的目录
EASY_RSA_DIR=/etc/openvpn/easy-rsa
# easy_rsa的版本
EASY_RSA_VERSION=3.0.8
# easy_rsa的PKI目录
PKI_DIR=$EASY_RSA_DIR/$EASY_RSA_VERSION/pki
# 如果不带参数则跳出循环
if [ ! -n "$1" ]; then
echo "无参数,不能创建用户"
exit 1
fi
# 对于传过来的所有参数【用户】进行循环
for user in "$@"
do
# 如果用户为server,则跳出本地循环,提示用户不能为server,不能创建sever用户
if [ $user = "server" ] || [ $user = "ca" ]; then
echo "用户为$user,不能创建此用户,跳出了本地循环"
continue
fi
# 如果用户已经存在,则跳出本地循环,并提示用户已存在,不能创建此用户
if [ -f "$PKI_DIR/reqs/$user.req" ]; then
echo "用户:$user,已经存在,不能创建此用户,跳出了本地循环"
continue
fi
# 进入用户EASY_RSA目录
cd $EASY_RSA_DIR/$EASY_RSA_VERSION
# 生成客户端 ssl 证书文件
echo "yes" | ./easyrsa build-client-full $user nopass > /dev/null 2>&1
# 整理证书,备份用户证书,用户被删除后可以取回
mkdir -p $OVPN_USER_KEYS_DIR/$user
# CA 根证书
cp $PKI_DIR/ca.crt $OVPN_USER_KEYS_DIR/$user/
# 客户端证书
cp $PKI_DIR/issued/$user.crt $OVPN_USER_KEYS_DIR/$user/
# 客户端证书密钥
cp $PKI_DIR/private/$user.key $OVPN_USER_KEYS_DIR/$user/
# 客户端的req
cp $PKI_DIR/reqs/$user.req $OVPN_USER_KEYS_DIR/$user/
# 将证书合成到配置文件中
mkdir -p $OVPN_USER_CONF_DIR
cat /dev/null 2>&1
./easyrsa gen-crl > /dev/null 2>&1
systemctl restart openvpn@server
echo "用户:$user,已吊销证书"
else
echo "用户:$user,不存在"
fi
# 吊销掉证书后移动或者清理客户端相关文件
mkdir -p $OVPN_USER_KEYS_DIR_BAK
if [ -d "$OVPN_USER_KEYS_DIR/$user" ]; then
rm -rf
mv $OVPN_USER_KEYS_DIR/${user} $OVPN_USER_KEYS_DIR_BAK
echo "已经移动用户文件夹到:$OVPN_USER_KEYS_DIR_BAK$user"
fi
if [ -f "$OVPN_USER_CONF_DIR/$user.ovpn" ]; then
rm -rf $OVPN_USER_CONF_DIR/$user.ovpn
echo "已经删除用户配置文件:$OVPN_USER_CONF_DIR/$user.ovpn"
fi
done
exit 0
# 将如上内容写入文件del_OpenVPN_User.sh
[root@localhost ~]# chmod +x del_OpenVPN_User.sh
# 例如删除zhangsan
[root@localhost ~]# ./del_OpenVPN_User.sh zhangsan
用户:zhangsan,已吊销证书
已经移动用户文件夹到:/etc/openvpn/client/keys_bak/zhangsan
已经删除用户配置文件:/etc/openvpn/client/conf/zhangsan.ovpn
6. 用户登录日志
6.1 脚本
[root@localhost ~]# cd /etc/openvpn/
# 创建用户登录脚本
[root@localhost openvpn]# vi UserLoginLog.sh
#!/bin/bash
# 定义时间,用于文件命令
day=`date +%Y-%m`
# 如果文件存在直接输出日志
if [ -f /var/log/openvpn/UserLogin$day.txt ];then
echo "`date '+%F %H:%M:%S'` User $common_name IP $trusted_ip is logged $1" >> /var/log/openvpn/UserLogin$day.txt
else
# 如果文件不存在,创建文件,再输出日志
touch /var/log/openvpn/UserLogin$day.txt
echo "`date '+%F %H:%M:%S'` User $common_name IP $trusted_ip is logged $1" >> /var/log/openvpn/UserLogin$day.txt
fi
# 因为openvpn运行的用户是openvpn,所有赋予组和执行权限
[root@localhost openvpn]# chown :openvpn UserLoginLog.sh
[root@localhost openvpn]# chmod +x UserLoginLog.sh
[root@localhost openvpn]# ll UserLoginLog.sh
-rwxr-xr-x 1 root openvpn 386 Jan 31 01:46 UserLoginLog.sh
6.2 修改配置文件
[root@localhost openvpn]# pwd
/etc/openvpn
# 在server.conf最后加入如下三行
[root@localhost openvpn]# vi server.conf
script-security 2
client-connect "/etc/openvpn/UserLoginLog.sh in"
client-disconnect "/etc/openvpn/UserLoginLog.sh off"
# 重启openvpn服务
[root@localhost openvpn]# systemctl restart openvpn@server
6.3 验证结果
# 日志结果
[root@localhost ~]# tail -f /var/log/openvpn/UserLogin2021-01.txt
2021-01-31 02:09:19 User zhangsan IP 113.111.116.178 is logged in
2021-01-31 02:09:55 User zhangsan IP 113.111.116.178 is logged off
7. Python ldap验证
7.1 脚本
由于openvpn-auth-lda配置文件ldap.conf中RequireGroup true以及Group的配置组下的用户才可以登录VPN。但根据这个【ISSUE】 ,当前2.0.3的openvpn-auth-ldap不支持
由此 写了个Python的脚本来做验证,流程如下:
当用户在客户端中输入账号密码点击登录之后,将账号username 和密码password 传入的环境变量中
Python脚本获取到环境变量中的账号和密码拿去openldap服务器中进行验证,并且该用户需要在某个组【例如:组VPN_Users】中
成功则返回0 【openvpn程序判断,Python只管返回即可】
失败则返回1【openvpn程序判断,Python只管返回即可】
该脚本文件名:/root/auth_ldap.py
chmod 777 /root/auth_ldap.py
根据情况进行修改组名称和组类别,查看具体组的属性即可得知
如果组类别为posixGroup 传入用户cn即可
如果组类别为groupOfNames,传入用户的dn全路径
用户登录日志文件:/var/log/openvpn/authldap.log 【根据openVPN安装的路径进行修改】
日志路径需要根据启动openvpn服务的用户授权,例如:chown openvpn:openvn /var/log/openvpn/
依赖包:pip install ldap3
yum -y install epel-release
yum -y install python-pip
pip install ldap3
#!/usr/bin/env python
# encoding: utf-8
import ldap3
import os
import sys
import time
import logging
from ldap3 import Connection, ServerPool
from ldap3 import (
HASHED_SALTED_SHA, MODIFY_REPLACE
)
from ldap3.utils.hashed import hashed
class LDAP(object):
def __init__(self, Server_Pool, Server_Port, ADMIN_DN, ADMIN_PASSWORD, SEARCH_BASE):
self.LDAP_Server_Pool = ServerPool(Server_Pool)
self.LDAP_Server_Port = Server_Port
self.ADMIN_DN = ADMIN_DN
self.ADMIN_PASSWORD = ADMIN_PASSWORD
self.SEARCH_BASE = SEARCH_BASE
self.conn = Connection(self.LDAP_Server_Pool, user=self.ADMIN_DN, password=self.ADMIN_PASSWORD, auto_bind=True)
def get_users(self, *args):
# 查询一个或多个用户
# *args :test01,test02
if not bool(args):
raise Exception('至少需要输入一个或多个用户')
mode = "(cn={0})"
users = ""
for user in set(args):
users += mode.format(user)
search_filter = '(&(objectclass=inetOrgPerson)(|{0}))'.format(users)
self.conn.search(self.SEARCH_BASE, search_filter=search_filter, attributes=["*"])
res = eval(self.conn.response_to_json())
return res
def get_user_in_ou(self, user, ou):
ldap_result = self.get_users(user)
username_dn = ldap_result["entries"][0]["dn"]
username_ou = username_dn.split(sep=',',maxsplit=1)[1]
if username_ou == ou:
return True
else:
return False
def get_users_has_groups(self, user_dn, group_type):
# 获取某个用户对应的所有组
# user_dn: cn=test,ou=Users,dc=example,dc=org根据组类别进行传入
# groupOfNames posixGroup
ldap_result = self.get_users(user_dn)
username_dn = ldap_result["entries"][0]["dn"]
search_filter = '(&(objectclass={0})(uniqueMember={1}))'.format(group_type, username_dn)
self.conn.search(self.SEARCH_BASE, search_filter=search_filter, attributes=["*"])
res = eval(self.conn.response_to_json())
entries = res["entries"]
groups = set()
for attributes in entries:
groups.add(attributes["attributes"]["cn"][0])
return groups
def auth(self, cn, password):
# cn :test01
ldap_result = self.get_users(cn)
if ldap_result["entries"]:
user_dn = ldap_result["entries"][0]["dn"]
# 认证用户账号密码是否正确
try:
Connection(self.LDAP_Server_Pool, user=user_dn, password=password, auto_bind=True)
return True, ldap_result["entries"]
except ldap3.core.exceptions.LDAPBindError as e:
print(e)
return False
else:
return False
if __name__ == "__main__":
# 配置 ldap ,根据情况修改
LDAP_SERVER_POOL = ["192.168.10.5"]
LDAP_SERVER_PORT = 389
ADMIN_DN = "cn=admin,dc=example,dc=org"
ADMIN_PASSWORD = "admin"
SEARCH_BASE = "dc=example,dc=org"
# 用户名和密码,不需要修改,从环境变量中自动获取
username=os.getenv('username')
password=os.getenv('password')
# 要求的群组,目前实例的组类型,如下根据情况修改
RequireGroup = "IT"
GroupType = "posixGroup"
# 判断用户是否在Resigned OU下,根据情况进行修改
Resigned = "ou=resigned,dc=dreamkey,dc=io"
# 日志保存路径设置
logging.basicConfig(format='%(asctime)s - %(levelname)s: %(message)s',level=logging.DEBUG,filename="/var/log/openvpn/authldap.log",filemode="a")
# 认证
ldap = LDAP(LDAP_SERVER_POOL, LDAP_SERVER_PORT, ADMIN_DN, ADMIN_PASSWORD, SEARCH_BASE)
## 获取用户所有的组
username_in_groups = ldap.get_users_has_groups(username, GroupType)
## 如果用户在 Resigned OU下,则拒绝
if ldap.get_user_in_ou(username, Resigned):
logging.info("{0} 登录失败: OU In {1}".format(username,Resigned ))
sys.exit(1)
## 账号密码成功,并且要求的群组在用户所有的组内,则验证成功,返回0,否则失败返回1
if ldap.auth(username,password) and RequireGroup in username_in_groups:
logging.info("{0} 登录成功".format(username))
sys.exit(0)
else:
logging.info("{0} 登录失败:账号密码错误或无授权".format(username))
sys.exit(1)
7.2 openvpn 服务配置
# 文件:/etc/openvpn/server.conf 最下面添加即可
script-security 3
auth-user-pass-verify /root/auth_ldap.py via-env
username-as-common-name
client-cert-not-required
7.3 客户端配置
ns-cert-type server
auth-user-pass
# cert client.crt 注释掉
# key client.key 注释掉
发表回复