OpenVPN是近年来最火的VPN软件,它部署容易,使用简单,跟IPsec相比,它所缺少的只是积累和口碑,不过没关系,已经有越来越多的公司开始在生产环境中用OpenVPN来取代IPsec。

假如真要在生产环境中部署IPsec,建议使用OpenBSD自带的IPsec,它拥有原生的内核级支持,部署和使用也非常简单,而且经过OpenBSD开发人员的精心调教,自然要比Linux要优越得多。

安装

$ sudo pkg_add -r openvpn
$ sudo mkdir -p /etc/openvpn/keys
$ sudo chmod 700 /etc/openvpn/keys
$ sudo cp -rf /usr/local/share/example/openvpn/easy-rsa/2.0/ /etc/openvpn/easy-rsa

创建PKI

  • 调整vars

    /etc/openvpn/easy-rsa/vars
    export EASY_RSA="`pwd`"
    
    export OPENSSL="openssl"
    export PKCS11TOOL="pkcs11-tool"
    export GREP="grep"
    
    export KEY_CONFIG="$EASY_RSA/openssl-1.0.0.cnf"
    export KEY_DIR="$EASY_RSA/keys"
    
    export KEY_COUNTRY="CN"
    export KEY_PROVINCE="HaiNan"
    export KEY_CITY="Haikou"
    export KEY_ORG="linuxabc.net.cn"
    export KEY_EMAIL="admin@linuxabc.net.cn"

    在OpenBSD的openvpn ports中,vars默认的KEY_CONFIG为$EASY_RSA/whichopensslcnf $EASY_RSA,需要改成"$EASY_RSA/openssl-1.0.0.cnf"。

  • 创建证书

    $ cd /etc/openvpn/easy-rsa
    $ sudo . ./vars
    $ sudo ./clean-all
    $ sudo ./build-ca
    $ sudo ./build-dh
    $ sudo ./build-key-server openbsd-2.linuxabc.net.cn
    $ sudo ./build-key admin.linuxabc.net.cn
  • 分发证书

    • 服务器

      $ sudo cp openbsd-2.linuxabc.net.cn.crt openbsd-2.linuxabc.net.cn.key /etc/openvpn/keys
      $ sudo cp ca.crt dh1024.pem /etc/openvpn/keys
    • 客户端

      假如客户端是windows操作系统,推荐使用WinSCP这个软件来分发客户端证书

配置

由于log日志对于排错非常重要,因此需要特别对待

$ sudo mkdir /var/log/openvpn
$ sudo touch /var/log/openvpn/openvpn.log
$ sudo touch /var/log/openvpn/openvpn-status.log
$ sudo chown -R _openvpn:_openvpn /var/log/openvpn

基于证书认证方式

  • 服务器配置

    $ sudo cat /etc/openvpn/server-cert.conf
    proto udp
    port 1194
    dev tun0
    ;切记,tun后面还有0,要与后面的/etc/hostname.tun0相吻合。
    ca /etc/openvpn/keys/ca.crt
    cert /etc/openvpn/keys/openbsd-1.linuxabc.net.cn.crt
    key /etc/openvpn/keys/openbsd-1.linuxabc.net.cn.key
    dh /etc/openvpn/keys/dh1024.pem
    ;上面的路径建议用全路径,否则openvpn启动的时候可能会提示无法打开dh1024.pem
    server 10.5.1.0 255.255.255.0
    
    keepalive 10 120
    comp-lzo
    
    user _openvpn
    group _openvpn
    
    persist-key
    persist-tun
    push "route 192.168.33.0 255.255.255.0"
    push "route 192.168.55.0 255.255.255.0"
    push "route 192.168.66.0 255.255.255.0"
    push "route 192.168.88.0 255.255.255.0"
    
    route 192.168.0.0 255.255.255.0
    route 192.168.1.0 255.255.255.0
    #client-config-dir /etc/openvpn/ccd
    status /var/log/openvpn/openvpn-status.log
    log /var/log/openvpn/openvpn.log
    log-append /var/log/openvpn/openvpn.log
    
    verb 4
  • 客户端配置

    client
    dev tun
    proto udp
    remote 212.232.254.190 1194
    
    resolv-retry infinite
    nobind
    persist-key
    persist-tun
    
    ca ./keys/ca.crt
    cert ./keys/username.dslab.qmcc.crt
    key  ./keys/username.dslab.qmcc.key
    ;tls-auth ./keys/ta.key 1
    dh ./keys/dh1024.pem
    
    ;auth-user-pass
    ns-cert-type server
    
    comp-lzo
    verb 7
    mute 10
  • 启动脚本

    $ sudo cat /etc/hostname.tun0
    up
    !/usr/local/sbin/openvpn --daemon --config /etc/openvpn/server.conf

基于用户名/密码认证方式

  • 服务端配置

    $ sudo cat /etc/openvpn/server-user.conf
    proto udp
    port 1194
    dev tun0
    ;切记,tun后面还有0,要与后面的/etc/hostname.tun0相吻合。
    ca /etc/openvpn/keys/ca.crt
    cert /etc/openvpn/keys/openbsd-1.linuxabc.net.cn.crt
    key /etc/openvpn/keys/openbsd-1.linuxabc.net.cn.key
    dh /etc/openvpn/keys/dh1024.pem
    ;上面的路径建议用全路径,否则openvpn启动的时候可能会提示无法打开dh1024.pem
    server 10.11.0.0 255.255.255.0
    topology subnet
    ; OpenVPN 2.1之前不支持subnet模式,仅支持net30,每个客户端的
    ; IP地址是30子网掩码,比较浪费IP资源,OpenVPN2.1之后开始
    ; 支持subnet模式,分配给客户端的IP地址是连续的。
    
    keepalive 10 120
    comp-lzo
    
    user _openvpn
    group _openvpn
    persist-key
    persist-tun
    
    auth-user-pass-verify /usr/local/libexec/openvpn_bsdauth via-env
    client-to-client
    
    ; ccd需要跟client-cert-not-required和username-as-common-name一起使用方能生效,
    ; openvpn会将接入的用户名跟ccd的文件名进行比对,对于采用证书认证方式的用户,
    ; 用户名就是certificate的common name,此处采用OpenBSD系统帐号作为认证方式,
    ; 因此openvpn需要通过username-as-common-name这条指令将OpenBSD系统帐号转变成
    ; certificate的common name来看待。从而实现与ccd的文件名适配。
    
    client-config-dir /etc/openvpn/ccd ; 此处要求绝对路径
    client-cert-not-required
    username-as-common-name
    
    status /var/log/openvpn/openvpn-status.log
    log /var/log/openvpn/openvpn.log
    log-append /var/log/openvpn/openvpn.log
    
    verb 4
    mute 20
  • ccd用户文件

    $ sudo cat /etc/openvpn/ccd/user1
    ifconfig-push 10.11.0.2 255.255.255.0
    ; topology subnet时,IP地址格式为10.11.0.2 255.255.255.0
    ; topology net30,IP地址格式为10.11.0.2 10.11.0.1
    push "route 192.168.33.0 255.255.255.0"
    push "route 192.168.55.0 255.255.255.0"
    push "route 192.168.66.0 255.255.255.0"
    push "route 192.168.88.0 255.255.255.0"
  • 创建openvpn用户

    $ sudo echo "/usr/bin/false" >> /etc/shells
    ; openvpn用户不需要登录OpenBSD,所以不必提供shell,但必须在/etc/shells备案,否则无法通过认证。
    
    # encrypt -p -b 6
    ; 明文密码转密文字符串
    
    # user add -p '$2a$06$hYBI8r5ylrjtNRXRCCFxweyTNMnLnmTtT2ksXFNQxC.7sjNHnqaM2' -s /usr/bin/false -c "openvpn User" -d /dev/null -g _openvpnusers <vpnuser>
    ;-p 参数后面是用''包裹的密文字符串。
    ;openvpn用户不需要home目录,因此统一指定了一个/dev/null空设备。
    ;openvpn用户必须在`_openvpnusers`这个组中,否则无法通过认证。该组是安装openvpn_bsdauth时自动创建的。
  • 启动脚本

    $ sudo cat /etc/hostname.tun0
    up
    !/usr/local/sbin/openvpn --script-security 3 system --daemon --config /etc/openvpn/server.conf

关于--script-security 3,详见openvpn_bsdauth.8.html

  • 客户端配置

    client
    dev tun
    proto udp
    remote 212.238.170.34 1194
    
    resolv-retry infinite
    nobind
    persist-key
    persist-tun
    
    ca ./keys/ca.crt
    
    auth-user-pass
    ns-cert-type server
    
    comp-lzo
    verb 7
    mute 10

进程管理

  • 启动

    $ sudo sh /etc/netstart tun0
  • 停止

    $ sudo kill -9 `cat /var/run/openvpn.pid`

pf设置

openbsd的精髓在pf,所以网络服务均需要跟它打交道:

/etc/pf.conf
-----------8<--------------
$ext_if = "fxp2"
table <vpn_net> const { 10.5.1.0/24 }
table <lan_net> const { 192.168.33.0/24, 192.168.55.0/24, \
						192.168.66.0/24, 192.168.88.0/24}
pass in inet proto udp to $ext_if port 1194
pass inet proto { tcp, udp } from <vpn_net> to <lan_net>
----------->8--------------

排错

  • TLS_ERROR: BIO read tls_read_plaintext error

    出现这种错误提示时,一般是由于服务器和客户机之间的时间差距过大所致,建议使用OpenNTPd定时更新。此外,假如OpenBSD创建ca.crt等证书的时候时间就已经不对,需要将所创建的证书全部删除,更新时间后再重新创建。

  • VERIFY ERROR: depth=0, error=unsupported certificate purpose:

    该错误的原因是在创建CA证书的时候,使用了错误的脚本,譬如服务器端证书应该用./build-key-server创建,结果用./build-key创建了。因此会出错。