使用 OpenVPN 安全访问业务网络

Posted on 2020-09-01 in how-to

本配置方法用于正常使用OPENVPN的同时,启用CA与证书令牌, 如有需要还可附加启用RADIUS用户与口令认证。

本配置在 debian 11 下测试通过,默认环境为全新安装,仅安装 SSH 和 基础工具软件, 创建了一个普通用户 recozo,该用户开启 sudo 功能,并且配置好了内外网卡地址。

参见:

零、初始化

进入 root 用户,使用以下命令初始化系统

# apt install sudo
# adduser recozo sudo
# timedatectl set-timezone Asia/Shanghai

一、安装OpenVPN

使用以下命令安装 OpenVPN

$ sudo apt install openvpn

二、创建服务器证书和加密文件等

安装完OPENVPN后,默认自动安装了 easyrsa,可简化证书的日常管理操作。

以下使用普通用户 recozo 进行操作,假定 CA 工作目录为 ~/bizCA (该目录名可以根据需要自行设定,也可以在以后的操作中修改目录名,甚至可以删除该目录,前提是你要作废或重置 CA )

  1. 初始化 easy-rsa

    $ make-cadir ~/bizCA && cd ~/bizCA
    $ vi vars
    

    对以下参数进行配置,以设置新证书的默认值

    set_var EASYRSA_REQ_COUNTRY     "US"
    set_var EASYRSA_REQ_PROVINCE    "California"
    set_var EASYRSA_REQ_CITY        "San Francisco"
    set_var EASYRSA_REQ_ORG         "Copyleft Certificate Co"
    set_var EASYRSA_REQ_EMAIL       "me@example.net"
    set_var EASYRSA_REQ_OU          "My Organizational Unit"
    

    初始化 ca 环境

    $ ./easyrsa init-pki
    
  2. 生成CA证书

    $ ./easyrsa build-ca nopass
    

    以上命令会生成 ca.crt 和 ca.key 两个文件,分别代表该 CA 的公钥与私钥(私钥必须严格保密), 根据实际可设置 Common Name(如 Company-Name CA)或使用默认值

    将以上生成的 ca 证书复制到 OpenVPN 目录下

    $ sudo cp pki/ca.crt /etc/openvpn/
    
  3. 生成服务器证书

    $ ./easyrsa gen-req VPNSVR nopass
    $ ./easyrsa sign-req server VPNSVR
    

    或者

    $ ./easyrsa build-server-full VPNSVR nopass
    

    将以上生成的服务器证书复制到 OpenVPN 目录下

    $ sudo cp pki/private/VPNSVR.key /etc/openvpn/
    $ sudo cp pki/issued/VPNSVR.crt /etc/openvpn/
    
  4. 生成用于密钥交换的dh

    $ ./easyrsa gen-dh
    $ sudo cp pki/dh.pem /etc/openvpn/dh2048.pem
    
  5. 生成的HMAC签名

    $ sudo openvpn --genkey secret ta.key
    $ sudo chown recozo:recozo ta.key
    $ sudo cp ta.key /etc/openvpn/
    

三、配置 OpenVPN 服务端

  1. 配置服务端配置文件

    $ sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/
    $ sudo vi /etc/openvpn/server.conf
    

    更新 server.conf 文件内容

    ;proto tcp
    proto udp
    
    ca ca.crt
    cert VPNSVR.crt
    key VPNSVR.key
    
    dh dh2048.pem
    
    topology subnet
    
    push "redirect-gateway def1 bypass-dhcp"        # 将客户端所有流量均从VPN转发,需要在防火墙设置NAT转换
    push "dhcp-option DNS 208.67.222.222"           # 视情况,DNS也可以不设置
    push "dhcp-option DNS 208.67.220.220"           # 视情况,DNS也可以不设置
    
    tls-auth ta.key 0                               # This file is secret
    
    cipher AES-256-CBC
    auth SHA256
    
    user nobody                                     # Windows 下无须设置
    group nogroup                                   # Windows 下无须设置
    
    log-append  /var/log/openvpn/openvpn.log        # 启用日志功能
    
    # sndbuf 0                                      # 网上搜索解决OPENVPN速度过慢的解决方案
    # rcvbuf 0                                      # 不过好像没有什么用啊
    sndbuf 393216
    rcvbuf 393216
    
    push "sndbuf 393216"
    push "rcvbuf 393216"
    
  2. 启用 IP 转发(需要完成以下配置防火墙步骤,以启用NAT转发)

    $ sudo vi /etc/sysctl.conf
    

    修改 sysctl.conf 内容

    net.ipv4.ip_forward=1
    

    激活转发

    $ sudo sysctl -p
    
  3. 启用服务端

    $ sudo systemctl start openvpn@server
    $ sudo systemctl enable openvpn@server
    

四、配置防火墙

如果客户端要访问除OPENVPN所在服务器外的其它网络地址,配置 NAT 转换

$ sudo apt install iptables
$ sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

以下为防火墙强化操作,请根据需要使用,适用于不安全环境下使用。 使用 iptables-persistent 持久化保存防火墙规则,根据需要,仅启用IPV4,关闭IPV6。 以下默认使用双网口,eth0为外网口,eth1为内(业务)网口,如果为单网口,请自行脑补。

参考链接: https://www.linode.com/docs/networking/vpn/set-up-a-hardened-openvpn-server/

  1. 安装 iptables-persistent

    $ sudo apt install iptables-persistent
    
  2. 编辑IPV4规则

    $ sudo vi /etc/iptables/rules.v4
    

    将该文件的内容替换为以下内容

    *filter
    
    # Allow all loopback (lo) traffic and reject anything
    # to localhost that does not originate from lo.
    -A INPUT -i lo -j ACCEPT
    -A INPUT ! -i lo -s 127.0.0.0/8 -j REJECT
    -A OUTPUT -o lo -j ACCEPT
    
    # Allow ping and ICMP error returns.
    -A INPUT -p icmp -m state --state NEW --icmp-type 8 -j ACCEPT
    -A INPUT -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT
    -A OUTPUT -p icmp -j ACCEPT
    
    # Allow SSH.
    -A INPUT -i eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 22 -j ACCEPT
    -A OUTPUT -o eth0 -p tcp -m state --state ESTABLISHED --sport 22 -j ACCEPT
    
    # 允许管理电脑互通访问
    -A INPUT -i eth0 -s 10.62.192.252/30 -j ACCEPT
    -A OUTPUT -o eth0 -d 10.62.192.252/30 -j ACCEPT
    
    # 只允许业务电脑访问,Allow UDP traffic on port 1194.
    -A INPUT -i eth0 -p udp -s 10.62.200.0/21 -m state --state NEW,ESTABLISHED --dport 1194 -j ACCEPT
    -A OUTPUT -o eth0 -p udp -d 10.62.200.0/21 -m state --state ESTABLISHED --sport 1194 -j ACCEPT
    
    # Allow DNS resolution and limited HTTP/S on eth0.
    # Necessary for updating the server and timekeeping.
    -A INPUT -i eth0 -p udp -m state --state ESTABLISHED --sport 53 -j ACCEPT
    -A OUTPUT -o eth0 -p udp -m state --state NEW,ESTABLISHED --dport 53 -j ACCEPT
    -A INPUT -i eth0 -p tcp -m state --state ESTABLISHED --sport 53 -j ACCEPT
    -A OUTPUT -o eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 53 -j ACCEPT
    
    -A INPUT -i eth0 -p tcp -m state --state ESTABLISHED --sport 80 -j ACCEPT
    -A OUTPUT -o eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 80 -j ACCEPT
    -A INPUT -i eth0 -p tcp -m state --state ESTABLISHED --sport 443 -j ACCEPT
    -A OUTPUT -o eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 443 -j ACCEPT
    
    # Allow traffic on the TUN interface so OpenVPN can communicate.
    -A INPUT -i tun0 -j ACCEPT
    -A FORWARD -i tun0 -j ACCEPT
    -A OUTPUT -o tun0 -j ACCEPT
    
    # Allow forwarding traffic only from the VPN.
    -A FORWARD -i tun0 -o eth1 -s 10.8.0.0/24 -j ACCEPT
    -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    # Log any packets which don't fit the rules above.
    # (optional but useful)
    -A INPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 4
    -A FORWARD -m limit --limit 3/min -j LOG --log-prefix "iptables_FORWARD_denied: " --log-level 4
    -A OUTPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_OUTPUT_denied: " --log-level 4
    
    # then reject them.
    -A INPUT -j REJECT
    -A FORWARD -j REJECT
    -A OUTPUT -j REJECT
    
    COMMIT
    
  3. 编辑IPV6规则(由于我们不需要IPV6,全部禁用)

    $ sudo vi /etc/iptables/rules.v6
    

    将该文件的内容替换为以下内容

    *filter
    
    -A INPUT -j REJECT
    -A FORWARD -j REJECT
    -A OUTPUT -j REJECT
    
    COMMIT
    
  4. 启用防火墙规则

    $ sudo iptables-restore < /etc/iptables/rules.v4
    $ sudo ip6tables-restore < /etc/iptables/rules.v6
    $ sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth1 -j MASQUERADE
    
  5. 保存规则

    $ sudo dpkg-reconfigure iptables-persistent
    
  6. 禁用IPV6功能

    $ sudo vi /etc/sysctl.d/99-sysctl.conf
    

    添加或修改以下内容

    net.ipv6.conf.all.disable_ipv6 = 1
    net.ipv6.conf.default.disable_ipv6 = 1
    net.ipv6.conf.lo.disable_ipv6 = 1
    net.ipv6.conf.eth0.disable_ipv6 = 1
    

    激活以上配置

    $ sudo sysctl -p
    

    注释掉IPV6的localhost解析

    $ sudo vi /etc/hosts
    
    #::1     localhost ip6-localhost ip6-loopback
    
  7. 查看防火墙规则与日志

    $ sudo iptables -S                                      # 查看规则
    $ sudo tail -f /var/log/messages                        # 查看日志
    

五、配置业务路由示例(双网卡)

$ sudo vi /etc/network/interfaces

参考以下内容更新 interfaces 文件

# The primary network interface
allow-hotplug eth0
iface eth0 inet static
        address 10.62.9.10/24
        # gateway 10.62.9.114
        # post-up ip route add default via 10.62.9.254 dev eth0
        # luxi vip hosts
        post-up ip route add 10.62.1.0/24 via 10.62.9.254 dev eth0
        post-up ip route add 10.62.192.252/30 via 10.62.9.254 dev eth0
        # luxi business private networks
        post-up ip route add 10.62.200.0/21 via 10.62.9.254 dev eth0
        # dns-* options are implemented by the resolvconf package, if installed
        dns-nameservers 10.62.9.114

# The vlan716 network interface
allow-hotplug eth1
iface eth1 inet static
        address 172.10.85.253/25
        post-up ip route add default via 172.10.85.254 dev eth1

六、下发 OpenVPN 路由

可以根据需要在 /etc/openvpn/server.conf 中配置以下命令来指定客户端的路由设置

push "route 10.62.9.100 255.255.255.255 net_gateway"

以上配置用于确保客户端能够正常访问指定的(安全认证)服务器。

参见以下示例

# redirect all default traffic via the VPN
push "redirect-gateway def1"
# redirect the Intranet network 192.168.1/24 via the VPN
push "route 192.168.1.0 255.255.255.0"
# redirect another network to NOT go via the VPN
push "route 10.10.0.0 255.255.255.0 net_gateway"
# redirect a host using a domainname to NOT go via the VPN
push "route www.google.ca 255.255.255.255 net_gateway"

七、准备客户端配置管理文件

为方便客户端的配置管理,创建一个专用目录和用于自动生成客户端配置的文件

$ mkdir -p ~/client-configs/files

不使用令牌认证的常规配置

$ cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf
$ vi ~/client-configs/base.conf

使用以下内容更新 base.conf 内容

proto udp                               # 与 server.conf 保持一致
remote 10.62.9.24 1194                  # 修改为本OPENVPN服务器的IP地址与端口号
user nobody                             # 仅适用于LINUX 客户端
group nogroup                           # 仅适用于LINUX 客户端
#ca ca.crt                              # 注释掉,包含在OVPN文件中
#cert client.crt                        # 注释掉,包含在OVPN文件中
#key client.key                         # 注释掉,包含在OVPN文件中
#tls-auth ta.key 1                      # 注释掉,包含在OVPN文件中
key-direction 1
cipher AES-256-CBC                      # 与 server.conf 保持一致
auth SHA256                             # 与 server.conf 保持一致
auth-nocache                            # 避免出现安全警告

# script-security 2                     # 仅适用于LINUX 客户端,自行决定是否添加
# up /etc/openvpn/update-resolv-conf    # 仅适用于LINUX 客户端,自行决定是否添加
# down /etc/openvpn/update-resolv-conf  # 仅适用于LINUX 客户端,自行决定是否添加

生成 OVPN 的脚本

$ vi ~/client-configs/make_config.sh

使用以下内容生成 make_config.sh 内容

#!/bin/bash

# First argument: Client identifier

CA_DIR=~/bizCA/
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf

cat ${BASE_CONFIG} \
        <(echo -e '<ca>') \
        ${CA_DIR}pki/ca.crt \
        <(echo -e '</ca>\n<cert>') \
        ${CA_DIR}pki/issued/${1}.crt \
        <(echo -e '</cert>\n<key>') \
        ${CA_DIR}pki/private/${1}.key \
        <(echo -e '</key>\n<tls-auth>') \
        ${CA_DIR}/ta.key \
        <(echo -e '</tls-auth>') \
        > ${OUTPUT_DIR}/${1}.ovpn

将脚本修改为可执行文件

$ chmod 700 ~/client-configs/make_config.sh

使用飞天令牌的安全认证

启用epass1000ND的令牌认证,需要在客户端上预先安装epass1000ND的中间件 (使用EPASS1000ND(支持win10) v2.5 2015发布的), 然后在客户端配置文件中增加pkcs11-providers和pkcs11-id, 令牌制作方法见生成客户端证书以及配置文件

$ cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/tokenbase.conf
$ vi ~/client-configs/tokenbase.conf

使用以下内容更新 tokenbase.conf 内容

proto udp                               # 与 server.conf 保持一致
remote 10.62.9.24 1194                  # 修改为本OPENVPN服务器的IP地址与端口号
user nobody                             # 仅适用于LINUX 客户端
group nogroup                           # 仅适用于LINUX 客户端
#ca ca.crt                              # 注释掉,包含在OVPN文件中
#cert client.crt                        # 注释掉,包含在OVPN文件中
#key client.key                         # 注释掉,包含在OVPN文件中
#tls-auth ta.key 1                      # 注释掉,包含在OVPN文件中
key-direction 1
cipher AES-256-CBC                      # 与 server.conf 保持一致
auth SHA256                             # 与 server.conf 保持一致
auth-nocache                            # 避免出现安全警告
# script-security 2                     # 仅适用于LINUX 客户端,自行决定是否添加
# up /etc/openvpn/update-resolv-conf    # 仅适用于LINUX 客户端,自行决定是否添加
# down /etc/openvpn/update-resolv-conf  # 仅适用于LINUX 客户端,自行决定是否添加

pkcs11-providers 'c:\windows\system32\ngp11v211.dll'
pkcs11-id 'TODO'                        # 需要生成令牌后获取实际 ID 后替换 TODO

生成 OVPN 的脚本

$ vi ~/client-configs/tokenmake_config.sh

使用以下内容生成 tokenmake_config.sh 内容

#!/bin/bash

# First argument: Client identifier

CA_DIR=/home/recozo/bizCA
OUTPUT_DIR=/home/recozo/client-configs/files
BASE_CONFIG=/home/recozo/client-configs/tokenbase.conf

cat ${BASE_CONFIG} \
        <(echo -e '<ca>') \
        ${CA_DIR}/pki/ca.crt \
        <(echo -e '</ca>\n<tls-auth>') \
        ${CA_DIR}/ta.key \
        <(echo -e '</tls-auth>') \
        > ${OUTPUT_DIR}/${1}.ovpn

将脚本修改为可执行文件

$ chmod 700 ~/client-configs/tokenmake_config.sh

八、生成客户端证书以及配置文件

生成客户端证书

$ ./easyrsa gen-req VPNCLI0520-001 nopass
$ ./easyrsa sign-req client VPNCLI0520-001

或者

$ ./easyrsa build-client-full VPNCLI-001 nopass

不使用令牌认证的常规配置

执行脚本生成 OVPN 文件

$ ~/client-configs/make_config.sh VPNCLI-001

以上命令会在 ~/client-configs/files 目录下生成 VPNCLI-001.ovpn 文件, 将该配置文件复制给客户端即可(具体使用请参考客户端的程序说明)

使用飞天令牌的安全认证

启用epass1000ND的令牌认证,需要在客户端上预先安装 PUTTY 和 epass1000ND 的中间件 (使用EPASS1000ND(支持win10) v2.5 2015发布的), 然后修改 ovpn 文件中的 pkcs11-id。

在服务器上生成 ovpn 与 证书文件

$ ~/client-configs/tokenmake_config.sh VPNCLI0520-001
$ ./easyrsa export-p12 VPNCLI0520-001 noca

以上命令会在 pki/private 目录中生成 pkcs#12 证书文件,可用于导入至 epass1000ND (附:$ ./easyrsa 可以查看该命令所支持的全部功能)

将证书文件导入令牌的注意事项:

  • 目前只在windows环境下成功完成了操作( windows 7 以及 windows 10 )
  • 使用的令牌管理软件(目录)为 EPASS1000ND(支持win10)\win2.5\pki\V2.5-20150919\PKIcdrom\CDROM_CN\PKI
  • 令牌(USB KEY)第一次使用时,要进行初始化,插入 USB KEY 后,执行 EPASS1000ND(支持win10)\win2.5\pki\V2.5-20150919\PKIcdrom\CDROM_CN\PKI\Utilities\PKIINIT\PKIInit_M32.exe
  • 令牌的管理与用户密码统一设置规则定义: 管理密码为路由器密码,用户密码为vlan号+id (如:VPNCLI0716-001 的用户密码为 0716 + 001 = 0717)
  • 使用 EPASS1000ND(支持win10)\win2.5\pki\V2.5-20150919\PKIcdrom\CDROM_CN\PKI\Utilities\ePassNgMgr.exe 导入前面所生成的证书

以下命令在安装了 OpenVPN 的 Windows 环境下运行,首先借助 pscp 复制刚才在服务器上生成的 ovpn 与 证书文件

C:\Users\recozo>pscp recozo@10.62.9.24:client-configs/files/VPNCLI0520-001.ovpn ./
C:\Users\recozo>pscp recozo@10.62.9.24:bizCA/pki/private/VPNCLI0520-001.p12 ./

将p12导入令牌后,立即获取 Serialized id (注意:openvpn2.4版本下显示的 Serialized id 不被支持,必须使用 openvpn 2.3版本获取 Serialized id, 你可以将 2.3版的文件复制到 windows 上,运行以下命令前定位到 2.3 版本的目录下)

.\openvpn --show-pkcs11-ids "c:\windows\system32\ngp11v211.dll"

将获取的 Serialized id 替换 ovpn 文件中的 pkcs11-id (即 TODO), 将该配置文件和令牌给客户即可。

九、为 OpenVPN 服务器安装 RadiusPlugin

  1. 解决依赖问题

    # apt-get install libgcrypt20-dev build-essential
    
  2. 下载插件

    # wget http://www.nongnu.org/radiusplugin/radiusplugin_v2.1a_beta1.tar.gz
    
  3. 解压缩

    # tar xf radiusplugin_v2.1a_beta1.tar.gz
    # cd radiusplugin_v2.1a_beta1
    # make
    
  4. 把编译好的模块拷贝适合的位置

    # mkdir /etc/openvpn/radius
    # cp radiusplugin.so /etc/openvpn/radius
    # cp radiusplugin.cnf /etc/openvpn/radius
    
  5. 配置 radiusplugin.cnf,配置前请在FreeRadius中增加nas记录

    (insert into nas (nasname, shortname, secret, description) values ("Your Server IP", "NAS001", "password", "单位名称 VLAN ID 的 OPENVPN"); )
    
    # vi /etc/openvpn/radius/radiusplugin.cnf
    

    修改 radiusplugin.cnf 内容

    NAS-IP-Address=Your Server IP           #根据本机实际修改
    server
    {
            # The UDP port for radius accounting.
            acctport=1813
            # The UDP port for radius authentication.
            authport=1812
            # The name or ip address of the radius server.
            name=Your Radius Server IP              #根据FreeRadius服务器实际修改
            # How many times should the plugin send the if there is no response?
            retry=1
            # How long should the plugin wait for a response?
            wait=1
            # The shared secret.
            sharedsecret=password   # 与 FreeRadius 中的 nas 记录一致
    }
    
  6. 启用RADIUS

    修改 server.conf

    # vi /etc/openvpn/server.conf
    

    在 server.conf 中增加以下内容

    plugin /etc/openvpn/radius/radiusplugin.so /etc/openvpn/radius/radiusplugin.cnf
    

    修改 base.conf 或 tokenbase.conf

    # vi /etc/openvpn/client/base.conf
    

    在文件中加入下面这行内容

    auth-user-pass