引言

在当前的数字时代,保护您的网络安全比以往任何时候都更加重要。
OpenVPN是一种流行的虚拟私人网络(VPN)解决方案,它可以帮助保护您的互联网连接,确保数据安全和隐私,当然,也可以用作打通异地网络。
本文将指导您如何从头开始部署OpenVPN


什么是OpenVPN

OpenVPN是一个开源的VPN软件,支持创建安全的点对点或站点对站点连接。
它使用了最先进的加密技术,可在各种操作系统上运行,包括WindowsmacOSLinux以及移动平台。


OpenVPN部署的先决条件

在开始部署之前,您需要准备以下事项:

  • 一台可作为VPN服务器的计算机,具有固定的公网IP地址。
  • 一定的网络知识,包括对IP地址、DNS和路由的基本了解。
  • 服务器的管理员访问权限。

需求规划

公司需要把内部网络与云上网络(腾讯云)打通,实现网络互通,经研究选择OpenVPN作为实现方法。

拓扑图如下:

60b6c4e1d985e92d7626ddffc00e405.png

解析一下:

  1. 内网部署VPN客户端,云上有公网IP的服务器部署VPN服务端,双方互通。
  2. 内网配置核心交换机做路由转发,拦截目的地为云上网络的数据,转发到VPN客户端,通过iptables鉴权判断是否允许转发到VPN服务端,如不允许则丢弃数据包,允许则转发。
  3. 目的地非云上网络的数据则正常转发,从防火墙出去互联网。
  4. 目的地为云上网络的数据抵达VPN服务端后,由VPN服务端内部网卡做转发,实现访问云上网络内部资源。

机器规划:
此处说明一下
云上内网网段为 10.5.0.0/16
VPN内网网段为 10.9.0.0/24

系统 主机名 IP地址 服务 作用
Centos7.9 openvpn-2023-1-60 10.200.1.60 OpenVPN Client VPN客户端
Centos7.9 OpenVPN-20231227 1.144.144.144 OpenVPN Server VPN服务端

部署OpenVPN

服务器初始化(服务端/客户端均需要)

# 修改一些安装源
yum install -y epel-release

sed -e 's|^mirrorlist=|#mirrorlist=|g' \
         -e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos|g' \
         -i.bak \
         /etc/yum.repos.d/CentOS-*.repo

sed -e 's!^metalink=!#metalink=!g' \
    -e 's!^#baseurl=!baseurl=!g' \
    -e 's!http://download\.fedoraproject\.org/pub/epel!https://mirrors.tuna.tsinghua.edu.cn/epel!g' \
    -e 's!http://download\.example/pub/epel!https://mirrors.tuna.tsinghua.edu.cn/epel!g' \
    -i /etc/yum.repos.d/epel*.repo

# 安装基础包
yum install -y chrony conntrack ipvsadm ipset jq iptables curl sysstat libseccomp wget socat git gcc-c++ make yum-utils testice-mapper-persistent-data lvm2 bash-completion nfs-utils lrzsz tree

# 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld
systemctl stop iptables && systemctl disable iptables

# 关闭 Selinux
setenforce 0 && sed -i 's/SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config

# 时间同步
(crontab -l;echo '*/30 * * * * /usr/sbin/ntpdate ntp1.aliyun.com && /usr/sbin/hwclock -w') | crontab

# 内核优化
echo "* - nofile 65535" >> /etc/security/limits.conf
echo "* - nproc 65536" >> /etc/security/limits.conf
sed -i 's#4096#65536#g' /etc/security/limits.d/20-nproc.conf

cat >> /etc/security/limits.d/nofile.conf <<EOF
* soft nofile 65536
* hard nofile 65536
EOF

cat >> /etc/sysctl.conf <<EOF
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 20480
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.core.somaxconn = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_tw_buckets = 10240
net.ipv4.ip_forward = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.neigh.default.gc_thresh1 = 1024
net.ipv4.neigh.default.gc_thresh1 = 2048
net.ipv4.neigh.default.gc_thresh1 = 4096
vm.swappiness = 0
vm.overcommit_memory = 1
vm.panic_on_oom = 0
fs.inotify.max_user_instances = 8192
fs.inotify.max_user_watches = 1048576
fs.file-max = 52706963
fs.nr_open = 52706963
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 10
EOF

sysctl -p >/dev/null 2>&1

# 升级系统内核
# 载入公钥、安装 elrepo
rpm -import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

# 修改源链接
sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/elrepo.repo
sed -i 's|http://elrepo.org/linux|https://mirrors4.tuna.tsinghua.edu.cn/elrepo|g' /etc/yum.repos.d/elrepo.repo
yum makecache fast

# 更新系统
yum update -y

# 载入 elrepo-kernel 元数据
yum --disablerepo=\* --enablerepo=elrepo-kernel repolist

# 查看可用内核
yum --disablerepo=\* --enablerepo=elrepo-kernel list kernel*

# 安装指定内核
yum remove -y kernel-tools-libs.x86_64 kernel-tools.x86_64
yum -y --enablerepo=elrepo-kernel install kernel-lt.x86_64 kernel-lt-tools.x86_64

# 重启一下
init 6

# 查看可用内核
awk -F\' '$1=="menuentry " {print $2}' /etc/grub2.cfg

# 指定内核启动(从0开始)
grub2-set-default 0

# 创建内核配置文件
grub2-mkconfig -o /boot/grub2/grub.cfg

# 再重启一下
init 6

部署服务端

# 安装openvpn和easy-rsa
yum install -y openvpn easy-rsa
mkdir -p /etc/openvpn/easy-rsa
cp -r /usr/share/easy-rsa/3.0.8/* /etc/openvpn/easy-rsa/
mkdir -p /etc/openvpn/easy-rsa/keys
cp -r /usr/share/doc/easy-rsa-3.0.8/vars.example /etc/openvpn/easy-rsa/vars

# 编写配置文件
cd /etc/openvpn/easy-rsa/ && vim /etc/openvpn/easy-rsa/vars
# 检查是否直接执行vars文件。如果是,显示错误信息并退出。
# 在Easy-RSA 3.x中,不推荐直接source vars文件。
if [ -z "$EASYRSA_CALLER" ]; then
    echo "You appear to be sourcing an Easy-RSA 'vars' file." >&2
    echo "This is no longer necessary and is disallowed. See the section called" >&2
    echo "'How to use this file' near the top comments for more details." >&2
    return 1
fi
# 设置Easy-RSA工作目录为当前目录。
set_var EASYRSA "`pwd`"
# 指定使用的OpenSSL命令。
set_var EASYRSA_OPENSSL "openssl"
# 指定pkcs11-tool命令,通常用于与硬件安全模块(HSM)交互。
set_var EASYRSA_PKCS11_TOOL "pkcs11-tool"
# 定义使用的grep命令。
set_var EASYRSA_GREP "grep"
# 设置存放私钥基础设施(PKI)的目录为当前目录下的keys文件夹。
set_var EASYRSA_PKI "`pwd`/keys"
# 设置RSA密钥的大小为2048位。
set_var EASYRSA_KEY_SIZE 2048
# 设置CA证书的有效期为36500天(约100年)。
set_var EASYRSA_CA_EXPIRE 36500
# 设置普通证书的有效期为36500天(约100年)。
set_var EASYRSA_CERT_EXPIRE 36500
# 设置证书请求(CSR)时使用的国家为中国。
set_var EASYRSA_REQ_COUNTRY "CN"
# 设置证书请求(CSR)时使用的省份为广东。
set_var EASYRSA_REQ_PROVINCE "GuangDong"
# 设置证书请求(CSR)时使用的城市为深圳。
set_var EASYRSA_REQ_CITY "ShenZhen"
# 设置证书请求(CSR)时使用的组织名。
set_var EASYRSA_REQ_ORG "XXXXX"
# 设置证书请求(CSR)时使用的电子邮箱地址。
set_var EASYRSA_REQ_EMAIL "runfa.li@qq.com"
# 设置证书请求(CSR)时使用的组织单位为运维。
set_var EASYRSA_REQ_OU "YunWei"
# 设置证书请求(CSR)时使用的通用名称为EasyRSA。
set_var EASYRSA_REQ_CN "EasyRSA"

# 创建server证书类型的配置文件
cat >> /etc/openvpn/easy-rsa/x509-types/server <<EOF
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = serverAuth
keyUsage = digitalSignature,keyEncipherment
EOF

# 创建client证书类型的配置文件
cat >> /etc/openvpn/easy-rsa/x509-types/client <<EOF
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = clientAuth
keyUsage = digitalSignature
EOF

# 初始化
./easyrsa init-pki

# 生成ca证书文件
./easyrsa build-ca nopass

# 生成server端证书和私钥文件
./easyrsa gen-req server nopass

# 给server端证书签名
./easyrsa sign-req server server

# 生成client端证书和私钥文件
./easyrsa gen-req client nopass

# 给client端证书签名
./easyrsa sign-req client client

# 为安全的TLS通信生成Diffie-Hellman参数
./easyrsa gen-dh

# 生成openvpn服务端配置文件
cat >> /etc/openvpn/server.conf <<EOF
# 设定OpenVPN监听的本地地址,0.0.0.0 表示监听所有IP地址
local 0.0.0.0
# 设置OpenVPN服务器监听的端口
port 11211
# 设置使用的协议,这里是 UDP
proto udp
# 设置虚拟网络接口类型,这里使用 tun,适用于路由/点对点配置
dev tun
# CA(证书颁发机构)证书的位置
ca /etc/openvpn/easy-rsa/keys/ca.crt
# 服务器证书的位置
cert /etc/openvpn/easy-rsa/keys/issued/server.crt
# 服务器私钥的位置
key /etc/openvpn/easy-rsa/keys/private/server.key
# Diffie-Hellman 参数文件的位置
dh /etc/openvpn/easy-rsa/keys/dh.pem
# 配置服务器的VPN子网,客户端将从这个子网中获得IP地址
server 10.9.0.0 255.255.255.0
# 向客户端推送路由,表示客户端访问10.5.0.0子网时应通过VPN
push "route 10.5.0.0 255.255.0.0"
# 持久化客户端IP池,即使服务重启也保持IP地址分配的一致性
ifconfig-pool-persist ipp.txt
# 允许客户端之间相互通信
client-to-client
# 设置心跳检测间隔和超时时间
keepalive 10 120
# 开启压缩,可以提高传输效率
comp-lzo
# 最大客户端数量限制(100)
max-clients 100
# 持久化密钥,即在重启后不需要重新读取
persist-key
# 持久化虚拟网络接口,即在重启后不需要重新创建
persist-tun
# 日志文件,记录连接状态
status openvpn-status.log
# 日志文件的位置,记录详细的日志信息
log /var/log/openvpn.log
# 日志详细程度
verb 3
EOF

# 启动服务端
systemctl start openvpn@server && systemctl enable openvpn@server

# 记录客户端证书
cat /etc/openvpn/easy-rsa/keys/ca.crt
......

cat /etc/openvpn/easy-rsa/keys/issued/client.crt
......

cat /etc/openvpn/easy-rsa/keys/private/client.key 
......

# 生成客户端配置文件
cat >> /etc/openvpn/client.conf <<EOF
# 客户端模式配置
client
# 使用的虚拟网络接口类型,这里是 tun
dev tun
# 设置使用的协议,这里是 UDP
proto udp
# 指定服务器的地址和端口
remote 1.144.144.144 11211
# 如果无法连接到服务器,则无限次重试
resolv-retry infinite
# 不绑定到特定的本地端口
nobind
# 持久化密钥,即在重启后不需要重新读取
persist-key
# 持久化虚拟网络接口,即在重启后不需要重新创建
persist-tun
# 嵌入CA证书,开始和结束标记之间是CA证书的内容
<ca>
-----BEGIN CERTIFICATE-----
[CA证书内容]
-----END CERTIFICATE-----
</ca>
# 嵌入客户端证书,开始和结束标记之间是客户端证书的内容
<cert>
Certificate:
[客户端证书内容]
-----END CERTIFICATE-----
</cert>
# 嵌入客户端私钥,开始和结束标记之间是私钥的内容
<key>
-----BEGIN PRIVATE KEY-----
[客户端私钥内容]
-----END PRIVATE KEY-----
</key>
# 开启压缩,可以提高传输效率
comp-lzo
# 日志详细程度
verb 3
EOF

# 配置服务端iptables
yum install -y iptables-services
systemctl start iptables && systemctl enable iptables

# 清空所有已有的规则,这将删除所有自定义规则,在每个链(INPUT, FORWARD, OUTPUT)中。
iptables -F

# 将默认策略设置为接受所有传入流量。
# 这意味着所有进入服务器的流量都将被允许,除非有特定规则拒绝它。
iptables -P INPUT ACCEPT

# 将默认策略设置为接受所有传出流量。
# 这意味着所有从服务器发出的流量都将被允许。
iptables -P OUTPUT ACCEPT

# 将默认策略设置为接受所有转发流量。
# 这对于路由器和网关非常重要,它允许流量通过服务器路由到其它网络。
iptables -P FORWARD ACCEPT

# 在NAT表的POSTROUTING链上添加一条规则,对所有源自10.9.0.0/24的出站流量进行MASQUERADE操作。
# 这意味着当这些数据包离开服务器时,它们的源IP地址将被更改为服务器的IP地址。
iptables -t nat -A POSTROUTING -s 10.9.0.0/24 -j MASQUERADE

# 保存当前的iptables规则设置。
# 这通常是通过将规则写入一个文件来实现,这样在服务器重启时规则可以被重新加载。
service iptables save

部署客户端

# 客户端安装openvpn
yum -y install openvpn

# 把服务端生成的client.conf放到/etc/openvpn目录下
# 启动客户端
systemctl start openvpn@client && systemctl enable openvpn@client

# 测试是否连通
# 可以见到客户端已经和服务端联通,此处的10.5.0.9是服务端的内网IP地址
[root@openvpn-2023-1-60 openvpn]# ping 10.5.0.9
PING 10.5.0.9 (10.5.0.9) 56(84) bytes of data.
64 bytes from 10.5.0.9: icmp_seq=1 ttl=64 time=8.27 ms
64 bytes from 10.5.0.9: icmp_seq=2 ttl=64 time=8.15 ms
64 bytes from 10.5.0.9: icmp_seq=3 ttl=64 time=8.37 ms
64 bytes from 10.5.0.9: icmp_seq=4 ttl=64 time=8.34 ms
64 bytes from 10.5.0.9: icmp_seq=5 ttl=64 time=8.59 ms
64 bytes from 10.5.0.9: icmp_seq=6 ttl=64 time=7.98 ms
64 bytes from 10.5.0.9: icmp_seq=7 ttl=64 time=8.29 ms
64 bytes from 10.5.0.9: icmp_seq=8 ttl=64 time=8.39 ms
64 bytes from 10.5.0.9: icmp_seq=9 ttl=64 time=8.39 ms
64 bytes from 10.5.0.9: icmp_seq=10 ttl=64 time=8.33 ms
^C
--- 10.5.0.9 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 9013ms
rtt min/avg/max/mdev = 7.987/8.314/8.599/0.187 ms

此时还没有实现我们的需求,因为只是把服务端和客户端打通了,内网网络还是没法访问云上网络,别着急,我们接下来继续操作!


路由转发

核心交换机配置

此处以华为三层交换机为例,如下图一般配置,即可把访问 10.5.0.0/16 的云上网段数据做一个拦截操作。

image.png

image.png

image.png

客户端做转发

配置iptables

# 客户端安装iptables-services并启动
yum -y install iptables-services
systemctl start iptables && systemctl enable iptables

# 配置iptables
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
iptables -D FORWARD -j REJECT --reject-with icmp-host-prohibited
iptables -A FORWARD -s 10.220.210.0/24 -d 10.5.0.0/16 -j ACCEPT
iptables -A FORWARD -d 10.5.0.0/16 ! -p icmp -j DROP
iptables -I FORWARD -s 10.210.2.45/32 -d 10.5.0.0/16 -m comment --comment "我的电脑" -j ACCEPT

# 保存规则
service iptables save

解释一下

iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

  • NAT表的POSTROUTING链上添加了一个规则,对于经过tun0OpenVPN的通常接口)的出站流量,使用MASQUERADE进行源地址转换。

iptables -D FORWARD -j REJECT --reject-with icmp-host-prohibited

  • FORWARD链中删除了一条拒绝所有转发流量的规则,这是为了不阻碍需要的特定流量。

iptables -A FORWARD -s 10.220.210.0/24 -d 10.5.0.0/16 -j ACCEPT

  • 允许从10.220.210.0/2410.5.0.0/16的流量转发。

iptables -A FORWARD -d 10.5.0.0/16 ! -p icmp -j DROP

  • 丢弃目的地为10.5.0.0/16,但不是ICMP协议的流量。

iptables -I FORWARD -s 10.210.2.45/32 -d 10.5.0.0/16 -m comment --comment "我的电脑" -j ACCEPT

  • 插入(-I)一条新规则到FORWARD链的最前面,允许从IP地址10.210.2.4510.5.0.0/16的流量转发,并附上了一个注释。

测试一下

image.png

image.png


总结

至此,实现了内部网络通过OpenVPN和云上网络打通的需求了。
当然,目前只是内部网络能访问云上网络,并没有做云上网络访问内部网络的操作,这个我这暂时没需求,就不琢磨了。
同时,我这还添加了FORWARD规则用作一个简单的权限控制,仅供参考。


文章作者: Runfa Li
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Linux 小白鼠
Linux 网络 运维 服务器 vpn Centos7 shell Centos7 vpn 防火墙 网络 Linux openvpn
觉得文章不错,打赏一点吧,1分也是爱~
打赏
微信 微信
支付宝 支付宝