Featured image of post 高可用openvpn全局单向A访问B区的网络

高可用openvpn全局单向A访问B区的网络

公司目前在A区,要访问B的资源和网站,这个将如何访问?如果采用专线成本太高,经过运维调研和测试,采用Openvpn能极大有效完成这个需求,并且安全,成本底,可。。。。。。。

openvpn介绍

OpenVPN是一个全特性的SSL VPN,支持弹性的客户端认证方法,基于证书、智能卡,和/或用户名及密码凭证等,并且通过应用于VPN虚拟接口的防火墙规则,可以使用特定用户或组的访问控制策略。

VPN 全称为虚拟私人网络(Virtual Private Network),常用于连接中、大型企业或团体间私人网络的通讯方法,利用隧道协议(Tunneling Protocol)来达到发送端认证、消息保密与准确性等功能。

比如多地办公的公司,可以使用 VPN 将不同地区连接在同一内网下;或者在家办公的时候也可以通过 VPN 接入公司内网中。

VPN 以 CS 架构运行,工作流程如下:

img

VPN工作流程

在外网的用户可以使用 vpn client 连接组织搭建的 vpn server 以建立通信隧道,随后便建立了虚拟的私人网络,处于外网的 worker 和内网中的 server 可以相互通信。

那么我们可以简单理解 VPN,由 VPN client 捕获用户发出的报文,封装报文后通过物理网络通信链路将报文发给 VPN serverVPN server 接收到报文后进行解包,再将其转发给实际的目标,反之同理; VPN 在逻辑层面构建了虚拟网络。

openvpn原理

OpenVpn的技术核心是虚拟网卡,其次是SSL协议实现,由于SSL协议在其它的词条中介绍的比较清楚了,这里重点对虚拟网卡及其在OpenVpn的中的工作机理进行介绍:

虚拟网卡是使用网络底层编程技术实现的一个驱动软件,安装后在主机上多出现一个网卡,可以像其它网卡一样进行配置。服务程序可以在应用层打开虚拟网卡,如果应用软件(如IE)向虚拟网卡发送数据,则服务程序可以读取到该数据,如果服务程序写合适的数据到虚拟网卡,应用软件也可以接收得到。虚拟网卡在很多的操作系统下都有相应的实现,这也是OpenVpn能够跨平台一个很重要的理由。

在OpenVpn中,如果用户访问一个远程的虚拟地址(属于虚拟网卡配用的地址系列,区别于真实地址),则操作系统会通过路由机制将数据包(TUN模式)或数据帧(TAP模式)发送到虚拟网卡上,服务程序接收该数据并进行相应的处理后,通过SOCKET从外网上发送出去,远程服务程序通过SOCKET从外网上接收数据,并进行相应的处理后,发送给虚拟网卡,则应用软件可以接收到,完成了一个单向传输的过程,反之亦然。

OpenVPN应用场景

Peer-to-Peer VPN(点对点连接),将Internet两台机器(公网地址)使用VPN连接起来,比如上海服务器和北京服务器之间的数据需要相互调用,但是数据又比较敏感,直接通过http公共网络传输,容易被窃取,如果拉一条专线成本又太高。那么我们可以通过VPN使用现有网络,将两台主机逻辑上捆绑在一个虚拟网络中,这样既保证了数据传输安全,同时又节省了成本。

1.用户通过Internet连接vpn服务通过加密技术进行数据传输;

2.加密实现方式是客户端公钥加密,服务端私钥解密;

3.客户端连接vpn后,vpn会给客户端推送一条内网路由以此实现内部主机通信

私有网段划分

搭建VPN通常是为了将位于不同地理位置的私有网段连接起来。要注意,VPN所连接的两端的私网网段不能冲突。

IANA (The Internet Assigned Numbers Authority)定义了下面三个IP地址块用于私有网络:

10.0.0.0 10.255.255.255 (10/8前缀)
172.16.0.0 172.31.255.255 (172.16/12前缀)
192.168.0.0 192.168.255.255 (192.168/16前缀)

Openvpn部署

环境介绍

主机 ip 网段
openvpn-server(vpn-192.168.83.44 ) 192.168.83.10(物理ip)/192.168.255.1(虚拟ip) 192.168.0.0/16
openvpn-client01–(主节点) 10.134.18.10(物理ip)/192.168.255.10(虚拟ip) 10.0.0.0/8
openvpn-client02–(备节点) 10.128.19.10(物理ip)/192.168.255.6 10.0.0.0/8
server虚拟ip 192.168.255.1/24 192.168.255.0/16

安装系统:CentOS Linux release 7.5.1804 (Core)

启用EPEL的yum源,安装OpenVPN:

1
2
3
[root@gw ~]# yum install epel-release
[root@gw ~]# yum install openvpn 
OpenVPN程序应该在客户端和服务端机器都安装,它是同一个程序包提供客户端或服务端的功能,取决于你的配置

服务端

img

生成所有证书&密钥原理

搭建OpenVPN,需要设置你自己的CA(Certificate Authority)并且为OpenVPN服务器和多个客户端分别生成证书和密钥。

构建一个OpenVPN 2.x配置的第一个步骤是建立一个PKI(public key infrastructure)。该PKI包含:

  • 服务器和每一个客户端都要有一个单独的证书(也叫做公钥)和私钥。

  • 一个master CA (Certificate Authority)证书和密钥,用于为每一个服务器和客户端证书签名。

OpenVPN支持基于证书的双向认证,这意味着,在建立相互信任之前,客户端必须认证服务器证书,服务端也必须认证客户端证书。服务器和客户端在认证彼此时,会首先验证对方呈现的证书是否由master CA签名,然后测试证书报头中的信息,比如证书common name或证书类型(客户端或服务器)。

注意:服务器和客户端时钟需要基本同步,否则证书可能不会正常工作。

生成CA的证书&密钥

生成一个master CA证书和密钥,一个服务器证书和密钥,和为3个不同的客户端生成证书和密钥。

对于PKI管理,我们会使用easy-rsa 2,这是与OpenVPN 2.2.x和之前的版本绑定的一个脚本集合。如果你使用的是OpenVPN 2.3.x,你需要单独从easy-rsa-old项目页面下载easy-rsa 2。而在*NIX平台上,你应该使用easy-rsa 3,参考它的文档以了解详细信息。

 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
41
42
43
44
45
46
47
48
[root@gw ~]# yum install easy-rsa
将整个easy-rsa的目录拷贝到另一个目录下,比如/etc/openvpn,这样未来升级OpenVPN包时不会覆盖你的修改。
[root@gw ~]# cp -ar /usr/share/easy-rsa /etc/openvpn
生成变量配置文件:
[root@gw ~]# cp /usr/share/doc/easy-rsa-3.0.3/vars.example /etc/openvpn/easy-rsa/3.0.3/vars

可以在vars中设置证书有效期
[root@gw ~]# vim vars
#配置一下相关的信息
export KEY_COUNTRY="CN"
export KEY_PROVINCE="ShangHai"
export KEY_CITY="ShangHai"
export KEY_ORG="YCZB"
export KEY_EMAIL="heian@heian.com"
set_var EASYRSA_CA_EXPIRE       3650                                      // CA证书的默认有效期
set_var EASYRSA_CERT_EXPIRE     3650                                      // CA签发的证书的默认有效期
set_var EASYRSA_CRL_DAYS        3650       // 貌似如果CRL文件在该时间内都未修改过的话,所有客户端都将无法连接


进入easy-rsa的目录,初始化环境:
cd /etc/openvpn/easy-rsa/3.0.3/
source ./vars
 ./easyrsa init-pki   #初始化一个新的PKI,其实就是移除并重新创建pki目录结构


创建CA证书和密钥对:
 ./easyrsa build-ca nopass
 # build-ca命令创建CA证书和密钥对。nopass选项表示不对CA密钥进行加密。nopass 配置无密码。
 #生产环境建议设置密码。在生成证书、密钥的时候,会要求输入该CA密钥的密码。
 现在,已经生成了CA的证书文件pki/ca.crt和私钥文件pki/private/ca.key。

Generating a 2048 bit RSA private key
.................................+++
...............+++
writing new private key to '/etc/openvpn/easy-rsa/3.0.3/pki/private/ca.key.lhgETNINjO'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:Guowei_CA       #输入用于辨识的一个名称 

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/etc/openvpn/easy-rsa/3.0.3/pki/ca.crt

现在,已经生成了CA的证书文件pki/ca.crt和私钥文件pki/private/ca.key。

生成服务端的证书&密钥

生成OpenVPN服务端的证书和密钥对:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
./easyrsa build-server-full server nopass

# build-server-full命令生成服务端的证书和密钥对。
# server参数是生成证书时用的Common Name,建议就使用server。nopass选项表示不对密钥进行加密。

Generating a 2048 bit RSA private key
..+++
................+++
writing new private key to '/etc/openvpn/easy-rsa/3.0.3/pki/private/server.key.gYkfUBDAFl'
-----
Using configuration from ./openssl-1.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'server'
Certificate is to be certified until Aug 12 01:22:27 2028 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated

现在,已经生成了服务端的证书文件pki/issued/server.crt和私钥文件pki/private/server.key。并且,生成的服务端证书已经是经过先前的CA密钥签名的了。

生成客户端的证书&密钥

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
./easyrsa build-client-full clientname nopass

# build-client-full命令生成客户端的证书和密钥对。
# client1参数是生成证书时用的Common Name。nopass选项表示不对密钥进行加密。

Generating a 2048 bit RSA private key
......................................+++
............................................................................+++
writing new private key to '/etc/openvpn/easy-rsa/3.0.3/pki/private/client1.key.wQ7i2qbP93'
-----
Using configuration from ./openssl-1.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'client1'
Certificate is to be certified until Aug 12 02:08:02 2028 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated

现在,已经生成了服务端的证书文件pki/issued/client1.crt和私钥文件pki/private/client1.key。并且,生成的客户端证书已经是经过先前的CA密钥签名的了。

类似的,我们还可以为client2、client3等分别生成证书和密钥对。总是为每一个客户端使用一个唯一的Common Name。

生成Diffie Hellman参数

我们需要为OpenVPN服务端生成Diffie Hellman参数:

1
2
3
4
5
./easyrsa gen-dh     
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
......................................................................+.......+...........................+......................................+................................................+....+..............................................................................................................................................................................
DH parameters of size 2048 created at /etc/openvpn/easy-rsa/3.0.3/pki/dh.pem

现在,已经生成了Diffie Hellman参数文件pki/dh.pem。

生成tls-auth key

生成tls-auth key,为了防止DDOS和TLS攻击,这个属于可选安全配置

1
openvpn --genkey --secret ta.key

服务端和创建配置文件

OpenVPN软件包自带了一些示例配置文件,因为我们是使用rpm包安装的,可以在/usr/share/doc/openvpn-2.4.6/sample/sample-config-files/目录下找到:

image-20220701153303964

服务器和客户端的示例配置文件分别是server.conf和client.conf

证书目录优化

1
2
3
4
5
6
# mkdir /etc/openvpn/server/certs && cd /etc/openvpn/server/certs
# cp /etc/openvpn/easy-rsa/pki/dh.pem ./
# cp /etc/openvpn/easy-rsa/pki/ca.crt ./
# cp /etc/openvpn/easy-rsa/pki/issued/server.crt ./
# cp /etc/openvpn/easy-rsa/pki/private/server.key ./
# cp /etc/openvpn/easy-rsa/ta.key ./

Server服务器配置文件

OpenVPN软件包自带的服务器示例配置文件很适合用来生成真正使用的服务器配置文件。它会创建一个VPN,使用一个虚拟的TUN网络接口(用于路由),会在UDP端口1194(OpenVPN的官方端口号)监听客户端连接,并分发10.8.0.0/24子网中的虚拟地址给连接进来的客户端。

在你使用该配置文件之前,你应该修改该配置文件中的ca、cert、key和dh选项,让它们指向各自的文件(我们先前生成的)。

 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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#启动的端口
port 1194
#使用的tcp协议
proto tcp
## "dev tun"将会创建一个路由IP隧道
dev tun
# 生成的ca证书
ca /etc/openvpn/server/certs/ca.crt
#服务端的证书
cert /etc/openvpn/server/certs/server.crt
#服务端的密钥
key /etc/openvpn/server/certs/server.key
#Diffie-Hellman密钥交换 文件
dh /etc/openvpn/server/certs/dh.pem
#openvpn server的虚拟ip网段
server 192.168.255.0 255.255.255.0
#route控制了从内核到OpenVPN服务器(通过TUN接口)的路由
### 具体下一跳是哪里,由 client-config 里的 iroute 指定
route 10.0.0.0 255.0.0.0
# 在此文件中维护客户端与虚拟IP地址之间的关联记录
# 如果OpenVPN重启,重新连接的客户端可以被分配到先前分配的虚拟IP地址
ifconfig-pool-persist /etc/openvpn/server/ipp.txt
#下面是定义服务器读取特殊客户端配置文件的目录为ccd;
client-config-dir /etc/openvpn/ccd
#允许客户端子网互通
client-to-client
# keepalive指令将导致类似于ping命令的消息被来回发送,以便于服务器端和客户端知道对方何时被关闭
# 每10秒钟ping一次,如果120秒内都没有收到对方的回复,则表示远程连接已经关闭
keepalive 10 120
# 服务器和每个客户端都需要拥有该密钥的一个拷贝
# 第二个参数在服务器端应该为'0',在客户端应该为'1'
tls-auth /etc/openvpn/server/certs/ta.key 0
# 选择一个密码加密算法,该配置项也必须复制到每个客户端配置文件中
cipher AES-256-CBC
# 持久化选项可以尽量避免访问那些在重启之后由于用户权限降低而无法访问的某些资源
persist-key
persist-tun
#日志文件
status /var/log/openvpn-status.log
# 为日志文件设置适当的冗余级别(0~9)
# 冗余级别越高,输出的信息越详细
#
# 0 表示静默运行,只记录致命错误
# 4 表示合理的常规用法
# 5和6 可以帮助调试连接错误
# 9 表示极度冗余,输出非常详细的日志信息
verb 3
# 通知客户端,当服务器重新启动时,可以自动重新连接
# 只能是UDP协议使用,TCP使用的话不能启动服务
# 测试需要push到客户端才有效果
#explicit-exit-notify 1

explicit-exit-notify 1
script-security 2
client-connect /etc/openvpn/script/connect.sh
client-disconnect /etc/openvpn/script/disconnect.sh

connect.sh

1
2
3
4
5
6
7
8
9
#!/bin/bash
Time=`date +%F`
if [ -f /etc/openvpn/log/openvpn_$Time.log ];then
  touch /etc/openvpn/log/openvpn_$Time.log
  echo "`date '+%F %H:%M:%S'` User $common_name trust_ip $trusted_ip is login,Remote_ip is $ifconfig_pool_remote_ip, Mask is $route_netmask_1" >> /etc/openvpn/log/openvpn_$Time.log
else
  touch /etc/openvpn/log/openvpn_$Time.log
  echo "`date '+%F %H:%M:%S'` User $common_name trust_ip $trusted_ip is login,Remote_ip is $ifconfig_pool_remote_ip, Mask is $route_netmask_1" >> /etc/openvpn/log/openvpn_$Time.log
fi

disconnect.sh

1
2
3
4
5
6
7
8
9
#!/bin/bash
Time=`date +%F`
if [ -f /etc/openvpn/log/openvpn_$Time.log ];then
  touch /etc/openvpn/log/openvpn_$Time.log
  echo "`date '+%F %H:%M:%S'` User $common_name trust_ip $trusted_ip is logout,Remote_ip is $ifconfig_pool_remote_ip, Mask is $route_netmask_1" >> /etc/openvpn/log/openvpn_$Time.log
  else
  touch /etc/openvpn/log/openvpn_$Time.log
  echo "`date '+%F %H:%M:%S'` User $common_name trust_ip $trusted_ip is logout,Remote_ip is $ifconfig_pool_remote_ip, Mask is $route_netmask_1" >> /etc/openvpn/log/openvpn_$Time.log
fi

开启forward转发

1
2
3
4
systemctl stop firewalld
systemctl mask firewalld
setenforce 0				# 临时关闭
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config	
1
2
3

echo net.ipv4.ip_forward = 1 >>/etc/sysctl.conf
sysctl -p

配置iptables规则

1
2
3
systemctl enable iptables
systemctl start iptables
iptables -F   # 清理所有防火墙规则

将 openvpn 的网络流量转发到公网:snat 规则

1
2
3
4
# 如下网段记得与server.conf 当中定义的网段保持一致
iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth0 -j MASQUERADE
iptables -L -t nat
iptables-save > /etc/sysconfig/iptables   # iptables 规则持久化保存
1
2
3
4
5
把iptables规则备份到/etc/sysconfig/iptables文件中
iptables-save > /etc/sysconfig/iptables

恢复刚才备份的规则
iptables-restore < /etc/sysconfig/iptables

我测试环境的iptables配置

 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


[dev][root@foxconn-vpn-192.168.83.44 backup_openvpn]# cat /etc/sysconfig/iptables
# Generated by iptables-save v1.4.21 on Thu May  6 14:02:02 2021
*nat
:PREROUTING ACCEPT [4743102:251117700]
:INPUT ACCEPT [2104299:126313633]
:OUTPUT ACCEPT [54995:3991628]
:POSTROUTING ACCEPT [25003:2044398]
:l - [0:0]
#表示走 10.0.0.0/8数据的源IP都转换tun0这个接口的IP然后转发出去。
-A POSTROUTING -d 10.0.0.0/8 -o tun0 -j MASQUERADE
#表示走 192.168.0.0/16数据的源IP都转换eth0这个接口的IP然后转发出去。
-A POSTROUTING -d 192.168.0.0/16 -o eth0 -j MASQUERADE
COMMIT
# Completed on Thu May  6 14:02:02 2021
# Generated by iptables-save v1.4.21 on Thu May  6 14:02:02 2021
*filter
:INPUT ACCEPT [431:383193]
:FORWARD ACCEPT [512:393937]
:OUTPUT ACCEPT [374:70793]
-A FORWARD -d 10.128.199.248/32 -j DROP
-A FORWARD -d 10.128.199.254/32 -j DROP
COMMIT
# Completed on Thu May  6 14:02:02 2021
# Generated by iptables-save v1.4.21 on Thu May  6 14:02:02 2021
*mangle
:PREROUTING ACCEPT [64983188:19955544594]
:INPUT ACCEPT [32316135:9267024863]
:FORWARD ACCEPT [30855150:10615986243]
:OUTPUT ACCEPT [31879646:5718904613]
:POSTROUTING ACCEPT [62734647:16334877032]
COMMIT
# Completed on Thu May  6 14:02:02 2021

特殊客户端配置ccd

1
2
3
4
5
6
7
8
9
[dev][root@foxconn-vpn-192.168.83.44 ccd]# pwd
/etc/openvpn/ccd
[dev][root@foxconn-vpn-192.168.83.44 ccd]# ls
lh.dmz
[dev][root@foxconn-vpn-192.168.83.44 ccd]# cat lh.dmz 
iroute 10.0.0.0 255.0.0.0
#10.0.0.0/8子网网段应该被路由到lh.dmz 
#iroute控制了从OpenVPN服务器到远程客户端的路由
#和前面server.conf 配置相互 route 10.0.0.0 255.0.0.0 配合

是否允许client2子网(10.0.0.0/8)和其它客户端之间的网络流量。如果是,添加下面的语句到服务器配置文件中:(目前的环境暂时没有用到)

1
2
3
client-to-client
push "route 10.0.0.0 255.0.0.0"
#这会让OpenVPN服务器通告client2的子网到其它客户端。

服务端脚本配置

钉钉发送接口脚本

 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
41
42
43
44
45
46
#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests
import json
import sys
import os
import time
import hmac
import hashlib
import base64
import urllib

def signature():
  timestamp = long(round(time.time() * 1000))
  secret = 'xxxxxxxxxx'
  secret_enc = bytes(secret).encode('utf-8')
  string_to_sign = '{0}\n{1}'.format(timestamp, secret)
  string_to_sign_enc = bytes(string_to_sign).encode('utf-8')
  hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
  sign = urllib.quote_plus(base64.b64encode(hmac_code))
  return timestamp,sign
 
def Dingtalk_Push(title, message, msgtype=None):
  (timestamp,sign) = signature()
  headers = {'Content-Type': 'application/json;charset=utf-8'}
  token = "xxxxxxxxxxxxxxxxxxxxxxxxxx"
  api_url = "https://oapi.dingtalk.com/robot/send?access_token=%s&timestamp=%s&sign=%s" % (token,timestamp,sign)

  json_data = {
    "msgtype": "markdown",
    "markdown": {
      "title": title,
      "text": message.replace('\r','\n').replace('\\n','\n')
    },
    "at": {
      "isAtAll": True
    }  
  }
  with open("/tmp/dd_notice.log", "w") as f:
    f.write(json.dumps(json_data))
  requests.post(api_url,json.dumps(json_data),headers=headers).text

if __name__ == '__main__':
  title = sys.argv[1]
  message = sys.argv[2]
  Dingtalk_Push(title, message)

线路检查-主备切换脚本

 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
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/bin/bash
#Check To Fox Network Script

PingCheck(){
  ip=$1
  status_code=0
  for i in {1..3}
  do
    /usr/sbin/fping -c 10 -t 1 $ip >/dev/null 2>&1
    if [ $? != 0 ];then
      status_code=$(expr $status_code + 1) 
    fi
    sleep 1
  done
  echo $status_code
}

CheckLine(){
  if [ -f /etc/openvpn/ccd/lh.fox ];then
    echo "lh.fox"
  elif [ -f /etc/openvpn/ccd/lh.dmz ];then
    echo "lh.dmz"
  fi
}

ChangeLine(){
  S_Line=$1
  D_Line=$2
  mv /etc/openvpn/ccd/$S_Line /etc/openvpn/ccd/$D_Line 
  kill $(ps -ef |grep "/sbin/openvpn --daemo[n]"|awk '{print $2}')
  sleep 3
  /sbin/openvpn --daemon --config /etc/openvpn/server.conf --log-append /var/log/openvpn.log 
}

#Start Check
M_IP="192.168.255.10"
B_IP="192.168.255.6"
M_S=$(PingCheck $M_IP)
Line=$(CheckLine)
if [ "$M_S" = "3" ] && [ "$Line" = "lh.dmz" ];then
  B_S=$(PingCheck $B_IP)
  if [ "$B_S" = "3" ];then
    msg="$(date +"%Y/%m/%d %H:%M:%S")\\\n壹城To厂区:主线路与备用线路均异常"
  else 
    msg="$(date +"%Y/%m/%d %H:%M:%S")\\\n壹城To厂区:主线路异常,切换备用线路"
  fi
  ChangeLine lh.dmz lh.fox  
  /usr/bin/python /etc/openvpn/script/dd-notice.py "壹城To厂区网络告警" "$msg" 
elif [ "$M_S" = "0" ] && [ "$Line" = "lh.fox" ];then
  msg="$(date +"%Y/%m/%d %H:%M:%S")\\\n壹城To厂区:主线路恢复,切回主线路"
  ChangeLine lh.fox lh.dmz 
  /usr/bin/python /etc/openvpn/script/dd-notice.py "壹城To厂区网络告警" "$msg"
fi 

定时任务

1
*/5 * * * * /bin/bash -x /etc/openvpn/script/check-network.sh > /tmp/debug.log 2>&1

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
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/bin/bash

USER=$2
PASS=$(echo "${USER}@xxxx.com $(date)"|md5sum |cut -b 1-12)
CA_PASS="xxxxx.88"
OVDIR="/etc/openvpn"
SER_ERSA="${OVDIR}/easy-rsa/3.0.6"
CLI_ERSA="${OVDIR}/easy-rsa/3.0.6"
KEYS_DIR="${OVDIR}/client"
DB_FILE="${SER_ERSA}/pki/index.txt"

if [ ! -f /bin/expect ];then
  echo "expect is not installed, start the installation..."
  yum -y install expect
  if [ $? != 0 ];then
     echo "Installation failed, please install manually"
     exit 1
  fi
fi



function GenerateAkey(){
  rlist=$(find /etc/openvpn/ -name "${USER}*")
  if [ -n "$rlist" ];then
    echo "用户: ${USER} 已存在"
    exit 1
  fi
  cd ${CLI_ERSA}/
/bin/expect <<EOF
  spawn ./easyrsa gen-req $USER
  expect "Enter PEM pass phrase:"
  send "${PASS}\r"
  expect "Verifying - Enter PEM pass phrase"
  send "${PASS}\r"
  expect "Common Name"
  send "\r"
  expect eof
EOF
}

function GenerateAconf(){
cat > ${KEYS_DIR}/${USER}/${USER}.ovpn <<EOF
client
dev tun
proto udp
remote xxx.xxx.xxx.xxx 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert ${USER}.crt
key ${USER}.key
remote-cert-tls server
tls-auth ta.key 1
cipher AES-256-CBC
verb 3
EOF
}

function ImportAkey(){
  cd ${SER_ERSA}/
  ./easyrsa import-req ${CLI_ERSA}/pki/reqs/${USER}.req ${USER}
/bin/expect <<EOF
  spawn ./easyrsa sign client $USER
  expect "Confirm request details:"
  send "yes\r"
  expect "Enter pass phrase for"
  send "${CA_PASS}\r"
  expect eof
EOF
}

function CreateUser(){
  GenerateAkey
  ImportAkey
  mkdir ${KEYS_DIR}/${USER}
  cp ${SER_ERSA}/pki/issued/${USER}.crt ${KEYS_DIR}/${USER}/
  cp ${CLI_ERSA}/pki/private/${USER}.key ${KEYS_DIR}/${USER}/
  cp ${OVDIR}/{ca.crt,ta.key} ${KEYS_DIR}/${USER}/
  cd ${KEYS_DIR}/
  GenerateAconf
  zip -r ${USER}.zip ${USER}/
  if [ -d ${USER} ];then
    rm -rf ${USER}
  fi
  echo -e "\033[32mPlease Download ${KEYS_DIR}/${USER}.zip\033[0m"
  if [ -f ${SER_ERSA}/pki/issued/${USER}.crt ];then
    #/bin/python2.7 /etc/openvpn/script/mail.py reg ${USER} ${PASS} ${KEYS_DIR}/${USER}.zip
    echo -e "\033[32mSenMail To ${USER}@fujfu.com\033[0m"
  else
    echo -e "\033[31mUser creation failed\033[0m"
  fi
}

function RemoveUser(){
  rlist=$(find /etc/openvpn/ -name "${USER}*")
  if [ ! -n "$rlist" ];then
    echo "用户: ${USER} 不存在"
    exit 1
  fi
  echo -e "\033[31m${rlist}\033[0m"
  read -p "上述文件将被移除,请确认(yes/no): " yn
  if [ "$yn" = "yes" ];then
    for f in $rlist;do
      rm -rf $f
      if [ $? = 0 ];then
        echo -e "\033[31m$f\033[0m       \033[32m[del]\033[0m"
      else
        echo -e "\033[31m$f\033[0m       \033[31m[fail]\033[0m"
      fi
      sleep 0.5
    done
    sed -i "/=${USER}$/d" ${DB_FILE}
    if [ $? = 0 ];then
      cd ${SER_ERSA}/
/bin/expect <<EOF
  spawn ./easyrsa update-db
  expect "Enter pass phrase for"
  send "${CA_PASS}\r"
  expect eof
EOF
      echo -e "\033[31m${DB_FILE}\033[0m       \033[32m[update]\033[0m"
    else
      echo -e "\033[31m${DB_FILE}\033[0m       \033[32m[fail]\033[0m"
    fi   
  else
    exit 0
  fi
}

function RevokeUser(){
  rlist=$(find /etc/openvpn/ -name "${USER}*")
  if [ ! -n "$rlist" ];then
    echo "用户: ${USER} 不存在"
    exit 1
  fi
  cd ${SER_ERSA}/
/bin/expect <<EOF
  spawn ./easyrsa revoke ${USER}
  expect "Continue with revocation"
  send "yes\r"
  expect "Enter pass phrase for"
  send "${CA_PASS}\r"
  expect eof
EOF
}

function Gencrl(){
  cd ${SER_ERSA}/
/bin/expect <<EOF
  spawn ./easyrsa gen-crl
  expect "Enter pass phrase for"
  send "${CA_PASS}\r"
  expect eof
EOF
}

case "$1" in
    start)
        /usr/sbin/openvpn --daemon --config /etc/openvpn/server.conf --log-append /var/log/openvpn.log
    ;;
    restart)
        /usr/bin/pkill --signal SIGHUP --exact openvpn
    ;;
    add)
        if [ -n "$2" ];then
          CreateUser
        else
          echo $"Usage: $0 add username"
        fi
    ;;
    remove)
        if [ -n "$2" ];then
          RevokeUser
          Gencrl
          RemoveUser
        else
          echo $"Usage: $0 remove username"
        fi
    ;;
    *)
        echo $"Usage: $0 {start|restart|add|remove} username"
        exit 1
esac

openvpn管理脚本(第二版)

为了简化客户端配置文件的管理,OpenVPN 提供了一种便捷的内联文件方式,允许用户将根证书(ca.crt)、客户端证书(client.crt)以及客户端私钥(client.key)等必要文件直接嵌入到配置文件中。通过这种方式,用户无需分别管理多个文件,从而提高了配置的便捷性和安全性。 具体来说,用户可以在OpenVPN的配置文件(通常是.ovpn文件)中,通过特定的指令将这些证书和密钥文件的内容直接包含进来。这样,当配置文件被加载时,OpenVPN会自动读取并应用这些内联的证书和密钥信息,无需用户手动指定证书和密钥文件的路径。 这种方法不仅使得文件管理更为集中和高效,而且也减少了配置错误的可能性,因为所有的信息都在一个地方,用户只需维护一个配置文件即可。这对于用户来说是一个很大的便利,特别是对于那些需要频繁部署和更新VPN配置的场景。

  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
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/bin/bash

#获取传入的第二个参数
USER=$2
PASS=$(echo "${USER} $(date)" | md5sum | cut -b 1-12)
CA_PASS="xxxx.88"
OVDIR="/etc/openvpn"
SER_ERSA="${OVDIR}/easy-rsa/3.0.6"
CLI_ERSA="${OVDIR}/easy-rsa/3.0.6"
KEYS_DIR="${OVDIR}/client"
DB_FILE="${SER_ERSA}/pki/index.txt"

#判断是否安装expect
if [ ! -f /bin/expect ]; then
    echo "expect is not installed, start the installation..."
    yum -y install expect
    if [ $? != 0 ]; then
        echo "Installation failed, please install manually"
        exit 1
    fi
fi

function GenerateAkey() {
    #判断用户是否存在
    rlist=$(find /etc/openvpn/ -name "${USER}*")
    if [ -n "$rlist" ]; then
        echo "用户: ${USER} 已存在"
        exit 1
    fi
    cd ${CLI_ERSA}/ || exit
    # 生成客户单的证书
    /bin/expect <<EOF
  spawn ./easyrsa gen-req $USER
  expect "Enter PEM pass phrase:"
  send "${PASS}\r"
  expect "Verifying - Enter PEM pass phrase"
  send "${PASS}\r"
  expect "Common Name"
  send "\r"
  expect eof
EOF
}
#生成单个配置文件
new_client() {
    # Generates the custom client.ovpn
    {
        cat /etc/openvpn/server/client-common.txt
        echo "<ca>"
        cat /etc/openvpn/easy-rsa/3.0.6/pki/ca.crt
        echo "</ca>"
        echo "<cert>"
        sed -ne '/BEGIN CERTIFICATE/,$ p' /etc/openvpn/easy-rsa/3.0.6/pki/issued/"$USER".crt
        echo "</cert>"
        echo "<key>"
        cat /etc/openvpn/easy-rsa/3.0.6/pki/private/"$USER".key
        echo "</key>"
        echo "key-direction 1"
        echo "<tls-auth>"
        sed -ne '/BEGIN OpenVPN Static key/,$ p' /etc/openvpn/server/ta.key
        echo "</tls-auth>"
    } >~/"$USER".ovpn
}


function ImportAkey() {
    cd ${SER_ERSA}/ || exit
    #导入client签约证书
    ./easyrsa import-req ${CLI_ERSA}/pki/reqs/${USER}.req ${USER}
    #给client端证书做签名
    /bin/expect <<EOF
  spawn ./easyrsa sign client $USER
  expect "Confirm request details:"
  send "yes\r"
  expect "Enter pass phrase for"
  send "${CA_PASS}\r"
  expect eof
EOF
}
#创建证书目录,进行归纳 压缩,发送邮件
function CreateUser() {
    GenerateAkey
    ImportAkey
    echo "
client
dev tun
proto tcp
remote xxx.xxx.xxx.xxx 11191
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
block-outside-dns
verb 3" >/etc/openvpn/server/client-common.txt
    new_client

    echo -e "\033[32mPlease Download ${KEYS_DIR}/${USER}-yc.zip\033[0m"
    echo -e ""
    #判断client 生成文件存在
    if [ -f ${SER_ERSA}/pki/issued/${USER}.crt ]; then
        #通过Python发送邮件 ,包含证书和使用方法
       # /bin/python2.7 /etc/openvpn/script/mail.py ${USER} ${PASS} ${KEYS_DIR}/${USER}-yc.zip
       # /bin/python2.7 /etc/openvpn/script/mail.py ${USER} ${PASS} ~/"$USER".ovpn
        echo -e "\033[32mSenMail To ${USER}@fujfu.com\033[0m"
        echo -e "\033[32mPrivate Key Password: \033[0m\033[31m${PASS}\033[0m"
    else
        echo -e "\033[31mUser creation failed\033[0m"
    fi
}
#移除账号文件
function RemoveUser() {
    #判断用户是否存在
    rlist=$(find /etc/openvpn/ -name "${USER}*")
    if [ ! -n "$rlist" ]; then
        echo "用户: ${USER} 不存在"
        exit 1
    fi
    echo -e "\033[31m${rlist}\033[0m"
    read -p "上述文件将被移除,请确认(yes/no): " yn
    if [ "$yn" = "yes" ]; then
        for f in $rlist; do
            rm -rf $f
            if [ $? = 0 ]; then
                echo -e "\033[31m$f\033[0m       \033[32m[del]\033[0m"
            else
                echo -e "\033[31m$f\033[0m       \033[31m[fail]\033[0m"
            fi
        done
        #删除openvpn的证书中的用户
        sed -i "/=${USER}$/d" ${DB_FILE}
        if [ $? = 0 ]; then
            cd ${SER_ERSA}/
            # update-db 命令来更新证书数据库
            /bin/expect <<EOF
  spawn ./easyrsa update-db
  expect "Enter pass phrase for"
  send "${CA_PASS}\r"
  expect eof
EOF
            echo -e "\033[31m${DB_FILE}\033[0m       \033[32m[update]\033[0m"
        else
            echo -e "\033[31m${DB_FILE}\033[0m       \033[32m[fail]\033[0m"
        fi
    else
        exit 0
    fi
}
#删除账号
function RevokeUser() {
    rlist=$(find /etc/openvpn/ -name "${USER}*")
    if [ ! -n "$rlist" ]; then
        echo "用户: ${USER} 不存在"
        exit 1
    fi
    cd ${SER_ERSA}/
    #gen-crl会生成一份吊销证书的名单,放在pki/crl.pem文件里
    /bin/expect <<EOF
  spawn ./easyrsa revoke ${USER}
  expect "Continue with revocation"
  send "yes\r"
  expect "Enter pass phrase for"
  send "${CA_PASS}\r"
  expect eof
EOF
}

# 撤销证书并创建CRL
# 这是CA特定的任务。
# 要永久撤消已颁发的证书,请提供导入期间使用的短名称:
# ./easyrsa revoke EntityName
# 要创建包含所有已撤销的证书的更新CRL,请执行以下操作:
# ./easyrsa gen-crl

function Gencrl() {
    cd ${SER_ERSA}/
    /bin/expect <<EOF
  spawn ./easyrsa gen-crl
  expect "Enter pass phrase for"
  send "${CA_PASS}\r"
  expect eof
EOF
}

case "$1" in
start)
    /usr/sbin/openvpn --daemon --config /etc/openvpn/server.conf --log-append /var/log/openvpn.log
    ;;
restart)
    /usr/bin/pkill --signal SIGHUP --exact openvpn
    ;;
add)
    if [ -n "$2" ]; then
        CreateUser
    else
        echo $"Usage: $0 add username"
    fi
    ;;
remove)
    if [ -n "$2" ]; then
        RevokeUser
        Gencrl
        RemoveUser
    else
        echo $"Usage: $0 remove username"
    fi
    ;;
*)
    echo $"Usage: $0 {start|restart|add|remove} username"
    exit 1
    ;;
esac

上面生成下方格式配置文件

 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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
client
dev tun
proto udp
sndbuf 0
rcvbuf 0
remote openvpnserver 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
comp-lzo
verb 3
cipher AES-256-CBC
script-security 3
key-direction 1
auth-nocache
auth-user-pass

# ca ca.crt
<ca>
-----BEGIN CERTIFICATE-----
......
......
......
-----END CERTIFICATE-----
</ca>

# cert client.crt
<cert>
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            89:53:31:72:cf:04:52:82:fb:e9:53:fe:82:fc:13:25
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=192.168.1.10
        Validity
            Not Before: Nov 14 03:32:32 2023 GMT
            Not After : Feb 16 03:32:32 2026 GMT
        Subject: CN=client
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ......
                    ......
                    ......
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Subject Key Identifier: 
                6E:0A:D2:EF:CE:55:4F:56:C7:57:D1:77:37:0D:AD:28:EF:A2:C8:41
            X509v3 Authority Key Identifier: 
                keyid:1A:CE:DD:A8:65:0E:3D:32:E0:74:17:15:5D:F7:6E:3B:7D:C1:59:05
                DirName:/CN=192.168.1.10
                serial:D8:A8:9B:71:84:77:C8:9B

            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Key Usage: 
                Digital Signature
            Netscape Comment: 
                Easy-RSA (3.0.8) Generated Certificate
            Netscape Cert Type: 
                SSL Client
    Signature Algorithm: sha256WithRSAEncryption
                    ......
                    ......
                    ......
-----BEGIN CERTIFICATE-----
......
......
......
-----END CERTIFICATE-----
</cert>

# key client.key
<key>
-----BEGIN PRIVATE KEY-----
......
......
......
-----END PRIVATE KEY-----
</key>

# tls-crypt ta.key 1
<tls-crypt>
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
......
......
......
-----END OpenVPN Static key V1-----
</tls-crypt>

开通账号自动发送邮件

  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
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import datetime
import smtplib,os,datetime,sys
from email.header import Header
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.application import MIMEApplication
import email.MIMEMultipart



def GenHtml(UserName,UserPass):
  Data = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 
  html = """
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
table {  
     border-collapse: collapse;  
     font-family: Futura, Arial, sans-serif;  
}  
caption {  
     font-size: larger;  
     margin: 1em auto;  
} 
th,td {  
     padding: .65em;  
}  
th {  
     background: #555 nonerepeat scroll 0 0;  
   border: 1px solid #777;  
   color: #fff;  
}  
td {  
     border: 1px solid#000000;  
} 
</style>
</head>
<body>
<div id="container">
<div id="content">
<table style="tablestyle" border="1">
<tr>
  <td bgcolor="#66B3FF" style="color: #F3F3FA" align="center"><b>开通时间</b></td>
  <td align="center">%s</td>
</tr>
<tr>
  <td bgcolor="#66B3FF" style="color: #F3F3FA" align="center"><b>账号</b></td>
  <td align="center"><font color="red"><b>%s</b></font></td>
</tr>
<tr>
  <td bgcolor="#66B3FF" style="color: #F3F3FA" align="center"><b>密码</b></td>
  <td align="center"><font color="red"><b>%s</b></font></td>
</tr>
<tr>
  <td bgcolor="#66B3FF" style="color: #F3F3FA" align="center"><b>有效期</b></td>
  <td align="center"><font color="red"><b>7天</b></font></td>
</tr>
<tr>
  <td bgcolor="#66B3FF" style="color: #F3F3FA" align="center"><b>证书及配置文件</b></td>
  <td align="center"><font color="red"><b>见附件</b></font></td>
</tr>
</table>
</div>
</div>
</br>
<h2>使用说明:</h2>
<ul><li><b>Windows</b></li></ul>
<p>下载 openvpn 的安装程序 <a href="https://aliyuncs.com/software/OpenVPN-2.5.3-I601-amd64.msi" title="OpenVPN-2.5.3-I601-amd64.msi">OpenVPN-2.5.3-I601-amd64.msi</a>
安装完成,将证书拷贝至 OpenVPN\config 下即可,openvpn 的软件请使用管理员权限打开。</p>
<ul><li><b>MacOS</b></li></ul>
<p>下载 Tunnelblick 等,支持openvpn 的客户端双击 *.ovpn 即可导入。</p>
<p>下载 Tunnelblick 安装程序 <a href="https://aliyuncs.com/software/Tunnelblick_3.8.5a_build_5671.dmg" title="Tunnelblick_3.8.5a_build_5671.dmg">Tunnelblick_3.8.5a_build_5671.dmg</a>
<ul><li><b>温馨提示</b></li></ul>
<p>请妥善保管好你的账号、密码以及密钥文件,如发生信息丢失,请及时联系管理员。</p>
</div>
</body>
</html>
""" % (Data, UserName, UserPass)
  return html





def VpnMailTo(html, mailSubject, mailto, key_file):
    mailuser = "yunwei@qq.com"
    mailpass = "xxxxxxx"

    server = smtplib.SMTP_SSL('smtp.qq.com', 465)
    server.login(mailuser, mailpass)
    
    main_msg = email.MIMEMultipart.MIMEMultipart()
    text_msg = email.MIMEText.MIMEText(html, _subtype='html', _charset='utf-8')
    main_msg.attach(text_msg)

    contype = 'application/octet-stream'
    maintype, subtype = contype.split('/', 1)
    files = ["/etc/openvpn/script/docs/办公室内网OpenVPN使用手册.docx", key_file]
    #for f in files:
    #  data = open(f, 'rb')
    #  file_msg = email.MIMEBase.MIMEBase(maintype, subtype)
    #  file_msg.set_payload(data.read())
    #  data.close()
    #  email.Encoders.encode_base64(f)

    #  basename = os.path.basename(f)
    #  file_msg.add_header('Content-Disposition','attachment', filename = f)
    #  main_msg.attach(f)
    for fs in files:
      with open(fs,'rb') as f:
          basename = os.path.basename(fs)
          part = MIMEApplication(f.read())
          part.add_header('Content-Disposition', 'attachment', filename = basename)
          main_msg.attach(part)

    main_msg['From'] = 'VPNService <yunwei@qq.com>'
    main_msg['Subject'] = Header(mailSubject, 'utf8').encode()
    main_msg['To'] = ",".join(mailto)
    main_msg['Date'] = email.Utils.formatdate()
    server.sendmail('yunwei@qq.com', mailto, main_msg.as_string())

def VpnReg(User, Pass, KeysFile):
  mailSubject = User + " 你好,办公网络环境的VPN账号已开通成功!"
  html = GenHtml(User,Pass)
  MailTo = []
  MailTo.append(User+"@qq.com")
  VpnMailTo(html, mailSubject, MailTo, KeysFile) 


if __name__ == '__main__':
  User = sys.argv[1]
  Pass = sys.argv[2]
  KeysFile = sys.argv[3]
  VpnReg(User,Pass,KeysFile)

openvpn管理

1
2
3
4
[dev][root@foxconn-vpn-192.168.1.1 script]# pwd
/etc/openvpn/script
[dev][root@foxconn-vpn-192.168.1.1 script]# ./vpncli -h
Usage: ./vpncli {start|restart|add|remove} username

openvpn-client客户端

OpenVPN 客户端配置 - 主节点

客户端标识 物理 IP / 虚拟 IP 目标网络范围
主节点(openvpn-client01) 10.134.18.10 / 192.168.255.10 10.0.0.0/8
 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
#客户段
client
#使用的tcp协议
dev tun
## "dev tun"将会创建一个路由IP隧道
proto tcp
#vpn server的地址
remote xxx.xxx.xxx.xxx 1194
# 启用该指令,与服务器连接中断后将自动重新连接,
# 这在网络不稳定的情况下(例如:笔记本电脑无线网络)非常有用
resolv-retry infinite
# 大多数客户端不需要绑定本机特定的端口号
nobind
# 持久化选项可以尽量避免访问在重启时由于用户权限降低而无法访问的某些资源
persist-key
persist-tun
#ca证书
ca ca.crt
#客户端证书
cert lh.dmz.crt
#客户端秘钥
key lh.dmz.key
# 通过检查证书具有正确的密钥使用设置来验证服务器证书
# 这是防止此处讨论的潜在攻击的重要预防措施:
#  http://openvpn.net/howto.html#mitm
# 要使用此功能,EasyRSA生成服务器证书的时候进行相关设置
remote-cert-tls server
# 如果在服务器上使用tls-auth密钥,那么每个客户端也必须拥有密钥
tls-auth ta.key 1
## 选择一个加密算法,服务器使用的算法选项,也必须在这里指定它
# 注意,v2.4客户端/服务器将自动以TLS模式协商AES-256-GCM。
cipher AES-256-CBC
#信息日志
verb 3

启动客户端

1
openvpn --daemon --cd /etc/openvpn/lh.dmz/ --config lh.dmz.ovpn --log-append /var/log/openvpn_dmz.log --askpass /etc/openvpn/lh.dmz/lh.dmz.pass

OpenVPN 客户端配置 - 备节点(通过代理)

客户端标识 物理 IP / 虚拟 IP 目标网络范围
备节点(openvpn-client02) 10.128.19.10 / 192.168.255.6 10.0.0.0/8
 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
client
dev tun
proto tcp
remote xxx.xxx.xxx.xxx 1194
resolv-retry infinite
route 192.168.0.0 255.255.0.0
route xxx.xxx.xxx.xxx 255.255.255.255 #公网路由
nobind
persist-key
persist-tun
ca ca.crt
cert lh.fox.crt
key lh.fox.key
remote-cert-tls server
tls-auth ta.key 1
cipher AES-256-CBC
verb 3
#http-proxy 10.xxx.xxx.xxx 3128
#http-proxy 10.xxx.xxx.xxx 3128
# 如果通过HTTP代理方式来连接到实际的VPN服务器
# 在此处指定代理服务器的主机名(或IP)和端口号
# 如果代理服务器需要身份认证,请参考官方手册
http-proxy 10.xxx.xxx.xxx 3128
# 连接失败时自动重试
http-proxy-retry

启动客户端

1
openvpn --daemon --cd /etc/openvpn/lh.fox --config lh.fox.ovpn --log-append /var/log/openvpn.log --askpass /etc/openvpn/lh.fox/lh.fox.pass  #这个vpn在连接时,会使用到密码

交换机配置

交换机添加路由

10.0.0.0/8 这个网段是 异地 的网段

访问 10.0.0.0/8的 数据,下一跳 192.168.83.44 (openvpn-server)

image-20220701174558080

参考文档:https://www.gaoyufu.cn/archives/openvpn

未来的你,会感谢今天仍在努力奋斗的你