OpenVPN on OpenBSD

2013-04-03添加topology subnet和ccd配置。
2013-02-14取消whichsslconf依赖。
2012-04-12初稿。
{: .info}

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

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

安装

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

创建PKI

  • 调整vars
# vim /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
# . ./vars
# ./clean-all
# ./build-ca
# ./build-dh
# ./build-key-server openbsd-2.linuxabc.net.cn
# ./build-key admin.linuxabc.net.cn
  • 分发证书

  • 服务器

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

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

配置

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

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

基于证书认证方式

  • 服务器配置
# 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
  • 启动脚本
# cat /etc/hostname.tun0
up
!/usr/local/sbin/openvpn --daemon --config /etc/openvpn/server.conf

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

  • 服务端配置
# 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用户文件
# 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用户
# 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时自动创建的。
  • 启动脚本
/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[http://www.wormhole.hu/~ice/openvpn_bsdauth/openvpn_bsdauth.8.html]

For OpenVPN versions 2.1 and up, the ‘script-security‘ directive must be set to (at least) ‘3’ in order for openvpn_bsdauth to receive the password from OpenVPN.

  • 客户端配置
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

进程管理

  • 启动
# sh /etc/netstart tun0
  • 停止
# kill -9 `cat /var/run/openvpn.pid`

pf设置

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

$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>

排错

  • 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创建了。因此会出错。