(下文选用最新的Ubuntu 14.04 LTS和OCServ 0.9.2作为标准环境)
编译OCserv
到官方站点找最新的OpenConnect Server版本。
curl -O ftp://ftp.infradead.org/pub/ocserv/ocserv-0.9.2.tar.xz
tar xvf ocserv-0.9.2.tar.xz
cd ocserv-0.9.2
看下README文件提及的编译依赖。理论上只有libgnutls-dev和libreadline-dev是必须的,但我们还是把可选的功能都带上。
(顺便一提,如果你在Ubuntu 14.04或更早版本上,libgnutls-dev的版本还是2.x,需要用libgnutls28-dev获取3.x的GnuTLS才能支持OCserv。)
sudo apt-get install build-essential pkg-config libgnutls28-dev libreadline-dev libseccomp-dev libpam0g-dev libwrap0-dev libnl-nf-3-dev
编译并安装。
./configure
(在我测试的环境里,最终报告只有systemd和dbus的结果为no,如果你发现其他项目显示no,不必担心,你的环境可能安装了可选的包导致出现不同结果。目前只有libgnutls28-dev是必须的模块。)
make
sudo make install
配置OCserv
我们希望做到的,是无需用户名与密码的客户端证书验证登陆。但在此之前,让我们先测通更简单的密码登录模式。首先让我们把CA证书与服务器证书生成好,具体步骤官方文档也有——
mkdir certificates
cd certificates
CA模板,创建ca.tmpl (可用nano创建。或cat创建,见官方文档,注意_EOF_指代输入结束),按需填写,这里的cn和organization可以随便填。
cn = "Your CA name"
organization = "Your fancy name"
serial = 1
expiration_days = 9999
ca
signing_key
cert_signing_key
crl_signing_key
CA密钥
certtool --generate-privkey --outfile ca-key.pem
CA证书
certtool --generate-self-signed --load-privkey ca-key.pem --template ca.tmpl --outfile ca-cert.pem
同理,我们用CA签名,生成服务器证书。先创建server.tmpl模板。这里的cn项必须对应你最终提供服务的hostname或IP,否则AnyConnect客户端将无法正确导入证书。
cn = "Your hostname or IP"
organization = "Your fancy name"
expiration_days = 9999
signing_key
encryption_key
tls_www_server
Server密钥
certtool --generate-privkey --outfile server-key.pem
Server证书
certtool --generate-certificate --load-privkey server-key.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template server.tmpl --outfile server-cert.pem
将CA,Server证书与密钥复制到以下文件夹
sudo cp ca-cert.pem /etc/ssl/certs/my-ca-cert.pem
sudo cp server-cert.pem /etc/ssl/certs/my-server-cert.pem
sudo cp server-key.pem /etc/ssl/private/my-server-key.pem
剩下的就是OCServ配置文件了。同样的,参考官方文档是最佳选项,但为了方便起见,这是你需要注意的一些设置。回到ocserv-0.9.2的文件夹下,将配置文件复制到OCserv默认读取的位置。
sudo mkdir /etc/ocserv
sudo cp doc/sample.config /etc/ocserv/ocserv.conf
确保以下配置正确
# 登陆方式,目前先用密码登录
auth = "plain[/etc/ocserv/ocpasswd]"
# 允许同时连接的客户端数量
max-clients = 6
# 限制同一客户端的并行登陆数量
max-same-clients = 2
# 服务监听的IP(服务器IP,可不设置)
listen-host = 1.2.3.4
# 服务监听的TCP/UDP端口
tcp-port = 9000
udp-port = 9001
# 自动优化VPN的网络性能
try-mtu-discovery = true
# 服务器证书与密钥
server-cert = /etc/ssl/certs/my-server-cert.pem
server-key = /etc/ssl/private/my-server-key.pem
# 客户端连上vpn后使用的dns
dns = 8.8.8.8
# 注释掉所有的route,让服务器成为gateway
#route = 192.168.1.0/255.255.255.0
# 启用cisco客户端兼容性支持
cisco-client-compat = true
创建一个登陆用的用户名与密码。
sudo ocpasswd -c /etc/ocserv/ocpasswd username
这样OCserv就基本配置好了。但如果你和我一样强化过服务器安全,还得为服务器上开些端口才行。以Linode的安全配置为例,我们需要加入和修改以下内容。
sudo nano /etc/iptables.firewall.rules
打开OCserv对应的TCP/UDP端口
-A INPUT -p tcp -m state --state NEW --dport 9000 -j ACCEPT
-A INPUT -p udp -m state --state NEW --dport 9001 -j ACCEPT
注释这行,允许转发
# -A FORWARD -j DROP
启用NAT,以下添加于COMMIT后,不然会报错:Bad argument `*nat
*nat
-A POSTROUTING -j MASQUERADE
COMMIT
完成之后导入新配置并检查配置正确。
sudo iptables-restore < /etc/iptables.firewall.rules
sudo iptables -L
sudo iptables -t nat -L
如果你之前没有配置服务器启动时自动导入这个设置
sudo nano /etc/network/if-pre-up.d/firewall
输入以下内容
#!/bin/sh
/sbin/iptables-restore < /etc/iptables.firewall.rules
最后我们需要打开IPv4的流量转发。
sudo nano /etc/sysctl.conf
启用此项
net.ipv4.ip_forward=1
并刷新配置
sudo sysctl -p /etc/sysctl.conf
测试OCserv
在服务器端启动OpenConnect Server。
sudo ocserv -f -d 1
如果服务没错误退出,是时候来测测客户端了。假设你使用iOS,下载Cisco AnyConnect。
在Connections下加入新的VPN配置,在服务器地址栏目上填入对应的IP/Hostname和TCP端口(我们的例子就是1.2.3.4:9000)
然后到设置标签页下暂时禁用“阻止不信任的服务器”选项。首次连接,AnyConnect会提示你这是不信任证书,如果你之前的服务器证书模板的cn没写错的话(我们的例子是1.2.3.4),你可以接受并导入该证书(可在诊断标签页的证书菜单里的服务器证书列表看到)。以后即便启用“阻止不信任的服务器”选项,也不会报错了(和SSH首次登陆类似)。
确定VPN连接正常并可以科学上网后,我们可以接着提高网络生活质量。
自动化OCserv
假如现有的配置有哪里让人不大满意,大概是这两点——
- OCserv的服务最好会自动跑,进程挂了也自动恢复。
- AnyConnect每次都要输入密码很麻烦,最好用客户端证书验证。
为OCserv写个简单的upstart脚本。
cd /etc/init.d
sudo ln -s /lib/init/upstart-job ocserv
cd /etc/init
sudo nano ocserv.conf
放入以下内容
#!upstart
description "OpenConnect Server"
start on runlevel [2345]
stop on runlevel [06]
respawn
respawn limit 20 5
script
exec start-stop-daemon --start --pidfile /var/run/ocserv.pid
--exec /usr/local/sbin/ocserv -- -f >> /dev/null 2>&1
end script
这样就可以用以下方式启动/暂停服务
sudo service ocserv start
sudo service ocserv stop
为AnyConnect建个客户端证书
和服务器端证书的步骤基本相同。回到之前的certificates文件夹。
创建user.tmpl
cn = "some random name"
unit = "some random unit"
expiration_days = 365
signing_key
tls_www_client
User密钥
certtool --generate-privkey --outfile user-key.pem
User证书
certtool --generate-certificate --load-privkey user-key.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template user.tmpl --outfile user-cert.pem
然后要将证书和密钥转为PKCS12的格式。按说certtool也能做到,但不知为何,当前的AnyConnect iOS版并不接受certtool生成的p12文件,于是我们只能用openssl替代——
openssl pkcs12 -export -inkey user-key.pem -in user-cert.pem -certfile ca-cert.pem -out user.p12
然后我们要通过URL将user.p12文件导入AnyConnect,具体位置在诊断标签页的证书栏目下。如果你的服务器已经有Nginx/Apache服务,只要传到一个可以访问的URL路径下即可。如果没有,请参照Nginx官网或Linode的Nginx入门教程。
导入成功之后,将对应的VPN设置的高级设置部分的证书栏目,改为导入的这张证书。
最后我们要调整下OCserv的配置——
nano /etc/ocserv/ocserv.conf
修改以下内容
# 改为证书登陆,注释掉原来的登陆模式
auth = "certificate"
# 证书认证不支持这个选项,注释掉这行
#listen-clear-file = /var/run/ocserv-conn.socket
# 启用证书验证
ca-cert = /etc/ssl/certs/my-ca-cert.pem
重启OCserv服务,确认VPN无需密码就可以正常登陆。
参考阅读:
- What changed between TLS and DTLS
- What’s the difference between VPN over TCP vs UDP?
- What is the difference between the SSL-Tunnel and DTLS-Tunnel