使用 ocserv 搭建企业级 OpenConnect VPN 网关并使用 Let's Encrypt 证书

AnyConnect 和 OpenConnect

Wikipedia 上描述 OpenConnect 如下:

OpenConnect is an open-source software application for connecting to virtual private networks (VPN), which implement secure point-to-point connections.

It was originally written as an open-source replacement for Cisco’s proprietary AnyConnect SSL VPN client,[2] which is supported by several Cisco routers. As of 2013, the OpenConnect project also offers an AnyConnect-compatible server,[3] and thus offers a full client-server VPN solution.

可以简要地看出,OpenConnect 原本是由于 AnyConnect 有只能运行在 Cisco 设备上限制而开发出来的一个多系统支持的开源 VPN 实现方式,属于 SSL VPN,需要一个有效的 SSL 证书.

本文实行简单粗暴的原则,记录了一个 Ubuntu 服务器最小化搭建 ocserv(OpenConnect 服务端) 服务的过程,所以:不使用证书登录验证(使用用户名+密码组合),SSL使用 Let’s Encrypt(而非网上许多文章所介绍的自签发).

Why OpenConnect

可能有些小伙伴看到本文长度会问了,为什么要搞这么复杂?直接 ss-server 或者 OpenVPN 一键脚本安装不好么?

原因有三:

  • 我们需要的是安全内网访问,不是快速地绕过防火墙…而且后期需要加入证书认证
  • OpenVPN 协议特征过于明显,虽然 AnyConnect 协议特征也十分明显,但是由于目前只有一些大厂在用,一般而言直接拨位与海外的 VPN 网关不容易受到干扰或受到的干扰较小
  • 对于例如 iOS/BlackBerry BBOS 系统而言,一般自带 AnyConnect 连接工具

本例中:

  • 一台全新的 Ubuntu 18.04 LTS(主要是考虑到 80 端口未被占用,给后文中获取 SSL 证书的方法提供可能)
  • 域名为:vpn.example.com,并且已经做好了解析到服务器 IP
  • 服务器IP为:1.2.3.4

2018-09-12更新:如果 80 端口被占用了可以考虑使用 DNS Challenge 的方法获取 Let’s Encrypt 证书,相关步骤可以参考 《使用 Google Cloud Platform 的 Storage 托管静态站点并通过 Google CDN 加速》

安装 ocserv & 准备系统

网上许多方法都是通过手动编译源代码包的方式安装,然而现在至少对于 Debian 系的系统来说已经有了编译好的软件包了,详情见 Distribution Status,对于 Debian 系服务器来说(比如本例的 Ubuntu)直接一条指令即可(非常感谢维护这个包的:Aron Xu,Liang Guo和Mike Miller):

1
$ sudo apt install ocserv -y

之后我们需要打开系统的转发功能,在 /etc/sysctl.conf 中加入如下行:

1
net.ipv4.ip_forward=1

通过

1
$ sysctl -p

保存.

打开 NAT 功能:

1
# iptables -t nat -A POSTROUTING -j MASQUERADE

配置 Let’s Encrypt 证书

ocserv 需要 SSL 证书,网上许多教程中使用的是自签发证书,方法复杂且容易被 MITM 攻击,好在现在有 Let’s Encrypt 可以免费为自己域名添加证书,本例中使用 certbot 来获取一个 Let’s Encrypt 证书.

下载certbot,方法很多,在本例中为:

1
2
3
4
5
$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install certbot

其他系统请参考 Certbot 官方网站.

安装好certbot后使用:

1
$ certbot certonly

会看到:

1
2
3
4
5
6
7
8
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

由于我们仅仅是想要一个证书,这里选择 1,让 certbot 来搞定证书获取的过程,之后输入自己的域名,比如本例中的 vpn.example.com ,稍等片刻应该可以看到类似如下的输出(记住证书存放的地址,后面会用到):

1
2
3
4
5
6
7
8
9
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/vpn.example.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/vpn.example.com/privkey.pem
Your cert will expire on 2018-11-11. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"

配置 ocserv

默认安装好后在/etc/ocserv/下有一个很长的配置文件ocserv.conf,着重注意以下配置字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 登录方式,使用用户名密码登录,密码文件稍后生成
auth = "plain[/etc/ocserv/ocpasswd]"

# 允许同时连接的客户端数量
max-clients = 4

# 限制同一客户端的并行登陆数量
max-same-clients = 2

# 服务监听的TCP/UDP端口(默认为443)
tcp-port = 443
udp-port = 443

# 自动优化 MTU,尝试改善网络性能
try-mtu-discovery = true

# 服务器证书与密钥,就是上一步中生成的证书和私钥的位置
server-cert = /etc/letsencrypt/live/vpn.example.com/fullchain.pem
server-key = /etc/letsencrypt/live/vpn.example.com/privkey.pem

# 服务器域名
default-domain = vpn.example.com

# 客户端连上 vpn 后使用的 DNS,这里使用 Cloudflare 的 1.1.1.1
dns = 1.1.1.1

# 注释掉所有的 route 和 no-route,让服务器成为gateway
#route = 192.168.1.0/255.255.255.0
#no-route = 192.168.5.0/255.255.255.0

# 启用 Cisco 客户端兼容性支持
cisco-client-compat = true

由于使用用户名密码登录,我们需要生成一个密码文件,指令如下:

1
$ ocpasswd -c /etc/ocserv/ocpasswd <用户名>

此时会要求你输入两边密码,如果需要再添加用户只需重复上述指令即可.

配置好后启动 VPN:

1
$ ocserv -c /etc/ocserv.conf

确认已经开启:

1
2
3
4
5
root@vpn:/etc/ocserv# netstat -tulpn | grep 443
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 1987/ocserv
tcp6 0 0 :::443 :::* LISTEN 1987/ocserv
udp 0 0 0.0.0.0:443 0.0.0.0:* 1987/ocserv
udp6 0 0 :::443 :::* 1987/ocserv

Connecting Through VPN

配置好 VPN 后让自己的所有服务器全部拨上 VPN:

1
# openconnect https://vpn.example.com/

对于个人用户访问,这里以黑莓 Passport 为例(请无视那个现在并不存在企业名称),截图如下:


拨通后可以看到自己的内网 IP :

然后,开始在 VPN 的保护下畅游自己的大内网吧~

Off-Topic

如果直接用浏览器去访问 VPN 网关(比如本例中:https://vpn.example.com)的话,返回的是如下 HTML 内容:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<config-auth client="vpn" type="auth-request">
<version who="sg">0.1(1)</version>
<auth id="main">
<message>Please enter your username.</message>
<form method="post" action="/auth">
<input type="text" name="username" label="Username:" />
</form></auth>
</config-auth>

此外如果开启了 ocserv 之后在 sudo 的时候卡住并提示:”sudo: unable to resolve host vpn: Resource temporarily unavailable” 的话,着重关注一下自己的/etc/hosts文件中是否包含一行:

1
127.0.0.1	localhost

参考连接

  1. 使用ocserv搭建 Cisco Anyconnect 服务器
  2. Setup OpenConnect VPN Server for Cisco AnyConnect on Ubuntu 14.04 x64

我的博客使用了Disqus评论框,如果你看不到评论框,那么多半Disqus服务在你所在的地区被墙,请使用代理访问。