OpenVPN是一个用于创建虚拟专用网络加密通道的软件包,允许创建的VPN使用公开密钥、数字证书、或者用户名/密码来进行身份验证。OpenVPN能在Solaris、Linux、OpenBSD、FreeBSD、NetBSD、Mac OS X与Windows 2000/XP/Vista/7以及Android和iOS上运行,并包含了许多安全性的功能。
配置OpenVPN 2.0的第一步是建立一个PKI(public key infrastructure 公钥基础设施)。PKI包括:
- 服务端和每个客户端都有一个证书(也称做公钥)和私钥
- 一个认证机构(CA)的证书和私钥,用来为每一个服务端和客户端颁发证书(sign each of the server and client certificates)。
OpenVPN 支持基于证书的双向认证,也就是说客户端需认证服务端,服务端也要认证客户端,
服务端和客户端验证对方的第一步是验证对方提供的证书是由认证机构(CA)颁发的。然后测试第一步认证通过的证书的头部信息,如:证书的common name,证书的类型(客户端还是服务端)。
从VPN的观点来看,这一安全模式满足一系列要求:
- 服务端仅仅需要它自己的证书/私钥对 -- 它不需要知道客户端的证书。
- 服务端仅仅接受拥有CA颁发的证书的客户端。因为服务端检查证书是否由CA颁发时并不需要访问 CA的私钥,这样就可以将CA的私钥(整个PKI中最重要的私钥)放在另一台机子上。
- 如果一个私钥(is compromised),通过将它的证书加入CRL(证书吊销列表)可以禁止这一私钥。 CRL允许有选择地拒绝compromised 证书而不需要重建整个PKI。
- 基于嵌入的证书域比如Vommon Name,服务端能够加强客户端待定(client-specific)访问权限 (access fights)。
生成认证机构(master Certificate Authority(CA))证书 & 私钥
在这一节我们生成一个认证机构(master CA)证书/私钥,一个服务端证书/私钥,两个客户端的证书/私钥。
我们使用OpenVPN捆绑的一组脚本。
在Linux下打开一个Sehll,进入OpenVPN下的easy-rsa目录。如果OpenVPN是从RPM包安装的,easy-rsa目录通常在/usr/share/doc/packages/openvpn或/usr/share/doc/openvpn-2.0目录下(最好在改动之前将这一目录拷到别的地方,比如/etc/openvpn,以免以后OpenVPN的升级覆盖所做的改动)。
在Windows下,打开一个命令行窗口进入\Program Files\OpenVPN\easy-rsa目录,运行下面的批处理文件将配置文件拷到正确的位置(这一命令会覆盖先前存在的vars.bat和openssl.cnf文件)。
init-config
编辑vars文件(在Windows下是vars.bat)设置KEY_COUNTRY、KEY_PROVINCE、 KEY_CITY, KEY_ORG和KEY_EMAIL参数,这些参数不能有一个是空白。
下一步,初始化PKI,Linux下:
. ./vars
./clean-all
./build-ca
Windows下:
vars
clean-all
build-ca
最后命令(build-ca)通过调用交互地openssl命令生成认证机构(CA)的证书和私钥。
ai:easy-rsa # ./build-ca
Generating a 1024 bit RSA private key
............++++++
...........++++++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [KG]:
State or Province Name (full name) [NA]:
Locality Name (eg, city) [BISHKEK]:
Organization Name (eg, company) [OpenVPN-TEST]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:OpenVPN-CA
Email Address [me@myhost.mydomain]:
上面的序列中,大多数询问参数的默认值是在vars或vars.bat文件中设定的值。唯一一个需要明确输入的参数是Common Name,上面的例子中输入的是"OpenVPN-CA"。
为服务端生成证书&私钥
为服务端生成证书和私钥。Linux/BSD/Unix:
./build-key-server server
Windows:
build-key-server server
和前面的一步类似,大多数参数可以保持默认值。当询问Common Name时,输入"server" 。另外两个回答"y"的问题,"Sign the certificate? [y/n]"和"1 out of 1 certificate requests certified, commit? [y/n]"。
Two other queries require positive responses, "Sign the certificate? [y/n]" and "1 out of 1 certificate requests certified, commit? [y/n]".
为3个客户端生成证书&私钥
生成客户端证书和前一步类似。Linux/BSD/Unix:
./build-key client1
./build-key client2
./build-key client3
Windows:
build-key client1
build-key client2
build-key client3
如果你想使用口令保护你的客户端私钥,则使用build-key-pass脚本而不是build-key。
为每个客户端输入适合的Common Name,也就是"client1", "client2", "client3"。总是为每个客户端指定一个独一无二的名字。
生成 Diffie Hellman 参数
必须为OpenVPN服务端生成 Diffie Hellman 参数。Linux/BSD/Unix:
./build-dh
Windows:
build-dh
输出:
ai:easy-rsa # ./build-dh
Generating DH parameters, 1024 bit long safe prime, generator 2
This is going to take a long time
.................+...........................................
...................+.............+.................+.........
......................................
密钥文件
在keys目录下生成的私钥和证书。下面是这些文件的解释:
文件名 | 需要者 Needed By | 说明 Purpose | 秘密 Secret |
ca.crt | 服务端和所有客户端 server + all clients | 根证书 Root CA certificate | 否 NO |
ca.key | 签发私钥的机器 key signing machine only | 根私钥 Root CA key | 是 YES |
dh{n}.pem | 服务器 server only | Diffie Hellman parameters | 否 NO |
server.crt | 服务器 server only | 服务器证书 Server Certificate | 否 NO |
server.key | 服务器 server only | 服务器私钥 Server Key | 是 YES |
client1.crt | client1 only | Clinet1的证书 Client1 Certificate | 否 NO |
client1.key | client1 only | Clinet1的私钥 Client1 Key | 是 YES |
client2.crt | client2 only | Client2的证书 Client2 Certificate | 否 NO |
client2.key | client2 only | Client2的私钥 Client2 Key | 是 YES |
client3.crt | client3 only | Client3的证书 Client3 Certificate | 否 NO |
client3.key | client3 only | Client3的私钥 Client3 Key | 是 YES |
生成密钥的最后一步是将密钥文件拷到需要它们的机器上。
为服务端和客户端创建配置文件
得到例子配置文件 Getting the sample config files
最好用OpenVPN的例子配置文件作为你自己配置文件的起点。 这些文件在以下目录
- OpenVPN源代码包的sample-config-files目录
- 如果从RPM安装,/usr/share/doc/packages/openvpn 或 /usr/share/doc/openvpn-2.0目录下的 sample-config-files目录
- Windows,Start Menu -> All Programs -> OpenVPN -> OpenVPN Sample Configuration Files
在Linux, BSD, or unix操作系统中,样例配置文件是server.conf和client.conf。 在Windows下是server.ovpn and client.ovpn。
编写服务端配置文件
样例配置文件使用虚拟TUN网络接口(路由模式for routing)创建一个VPN,它在 UDP端口1194(OpenVPN的官方端口)上监听客户端连接请求,并且从10.8.0.0/24 子网为连接的客户端分配虚拟地址。
使用样例配置文件之前,首先要编辑ca、cert、key 和dh 参数,使之指向你在上一节PKI中生成的文件。
这时服务端配置文件就可以使用了,也可以进一步修改它:
- 如果你使用以太网桥,则必须使用 server-bridge和dev tap而不是 server和dev tun。
- 如果想让OpenVPN服务端监听一个TCP端口而不是UDP端口, 使用proto tcp而不是proto udp
- 如果你想使用不同于10.8.0.0/24的一个虚拟IP地址范围,则修改 server项。记住这一虚拟IP地址范围必须是在你的网络上没有使用的。
- 如果想让连接的客户端可以通过VPN互相访问,将client-to-client的注释去掉。 默认情况下客户端只能访问服务端。
- 如果你使用的是Linux、BSD或Unix,则可以将user nobody和group nobody 的注释去掉以增强安全性。
如果想在同一台机器上运行多个OpenVPN,每个VPN使用一个不同的配置文件, 是可以做到的:
- 每个VPN实例使用一个不同的port号(UDP和TCP使用不同的端口空间,所以 可以让一个VPN监听UDP-1194,另一个监听TCP-1194)。
- 如果在Windows下运行,则每一个OpenVPN配置都需要有一个自己的TAP-Win32虚拟网卡。可以使用Start Menu -> All Programs -> OpenVPN -> Add a new TAP-Win32 virtual ethernet adapter来增加TAP-Win32虚拟网卡。
- 如果你运行了多个OpenVPN,记住编辑指定输出文件的指令,避免一个VPN覆盖另一个VPN 的输出文件。这些指令包括log、log-append、 status和ifconfig-pool-persist。
编写客户端配置文件
客户端配置文件的例子(client.conf Linux/BSD/Unix或client.ovpn Windows) 和服务端配置文件的例子相对应。
-
象服务端配置文件一样,首先编辑ca、cert和key 参数使之指向你在上一节PKI生成的文件。每一个客户端有自己的cert/key对。只有ca文件在服务端和所有客户端之间是通用的。
-
下一步,编辑remote指令使之指向服务端的主机名/IP地址和端口号。 (如果OpenVPN服务端运行在firewall/NAT-gateway之后的一台单网卡机子上,则使用网关的公用IP地址,和你在网关上配置的向OpenVPN服务端转发的端口)。
-
最后,确保客户端配置文件和服务端配置文件中指令的的一致性。主要检查的是 dev(tun/tap)和proto(udp/tcp)。还有comp-lzo和 fragment(如果使用了)则在客户端和服务端的配置文件中都必须提供。
启动并测试VPN的初始连接
启动服务端
首先,确保OpenVPN服务端能从internet访问。这意味着:
- 防火墙打开UDP端口1194(或者你配置的任意TCP/UDP端口)。
- 设置一个端口转发规则,将UDP端口1194从防火墙/网关转发到运行OpenVPN服务端的机子。
下一步,确保TUN/TAP虚拟网卡没有被屏蔽。
为了减少错误,最好从命令行启动OpenVPN服务端(或者在Windows下,右击.ovpn文件), 不要将其作为后台或服务运行。
一个服务端的启动过程:
Sun Feb 6 20:46:38 2005 OpenVPN 2.0_rc12 i686-suse-linux [SSL] [LZO] [EPOLL] built on Feb 5 2005
Sun Feb 6 20:46:38 2005 Diffie-Hellman initialized with 1024 bit key
Sun Feb 6 20:46:38 2005 TLS-Auth MTU parms [ L:1542 D:138 EF:38 EB:0 ET:0 EL:0 ]
Sun Feb 6 20:46:38 2005 TUN/TAP device tun1 opened
Sun Feb 6 20:46:38 2005 /sbin/ifconfig tun1 10.8.0.1 pointopoint 10.8.0.2 mtu 1500
Sun Feb 6 20:46:38 2005 /sbin/route add -net 10.8.0.0 netmask 255.255.255.0 gw 10.8.0.2
Sun Feb 6 20:46:38 2005 Data Channel MTU parms [ L:1542 D:1450 EF:42 EB:23 ET:0 EL:0 AF:3/1 ]
Sun Feb 6 20:46:38 2005 UDPv4 link local (bound): [undef]:1194
Sun Feb 6 20:46:38 2005 UDPv4 link remote: [undef]
Sun Feb 6 20:46:38 2005 MULTI: multi_init called, r=256 v=256
Sun Feb 6 20:46:38 2005 IFCONFIG POOL: base=10.8.0.4 size=62
Sun Feb 6 20:46:38 2005 IFCONFIG POOL LIST
Sun Feb 6 20:46:38 2005 Initialization Sequence Completed
启动客户端
和服务端一样,最好从命令行(或在Windows下右击client.ovpn文件)启动OpenVPN。
Windows下客户端的启动和上面的服务端启动类似,并且最后以 Initialization Sequence Completed 消息结束。
现在,从客户端通过VPN发送ping包,如果你使用路由模式(服务端配置文件里是dev tun),输入下面命令:
如果使用桥接模式(服务端配置文件是dev tap),尝试ping服务端所在子网的某台机子的IP地址。
如果ping成功,祝贺你!你已经有了一个能正常工作的VPN。
常见问题
如果ping失败,或者OpenVPN客户端初始化失败,请检查下列现象和解决办法:
-
错误信息: TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity). 这个错误表示客户端不能和服务端建立网络连接。
解决方法:
- 保证客户端使用允许其访问到OpenVPN服务端的主机名/IP地址和端口号。
- 如果OpenVPN服务端是受保护的LAN内的单网卡机子,确保在服务端网关防火墙上使用了正确的端口转发规则。假如你的OpenVPN的IP地址是防火墙内的192.168.4.4,在UDP端口1194上监听客户端连接。服务于192.168.4.x子网上的NAT网关应该有一条端口转发规则: forward UDP port 1194 from my public IP address to 192.168.4.4。
- 打开服务端的防火墙允许到UDP端口1194(或者别的你在服务端配置文件中指定的TCP/UDP端口)的连接。
-
错误信息: Initialization Sequence Completed with errors -- 这一错误可能出现在windows 下,(a)DHCP客户端服务没有运行,(b)在XP SP2上使用了第三方的个人防火墙。
解决办法: 启动DHCP客户端服务,确保使用的个人防火墙和XP SP2能正常工作。
-
得到了Initialization Sequence Completed消息,但是ping失败了 -- 这通常是服务端或客户端上的防火墙过滤了TUN/TAP网络接口从而阻止了VPN网络的流量。
解决办法: 禁止客户端的防火墙(如果有的话)过滤TUN/TAP网络接口。例如在Windows下,你可以到Windows Security Center -> Windows Firewall -> Advanced取消对应于TAP-Win32网卡的选择(禁止客户端防火墙过滤TUN/TAP网卡从安全角度来看通常是合理的,因为你本来已经告诉防火墙不要阻止授权的VPN流量)。同样确保服务端TUN/TAP接口没有被防火墙过滤,
-
当使用proto udp时,连接在启动时停止,服务端的日志文件中有如下一行:
TLS: Initial packet from x.x.x.x:x, sid=xxxxxxxx xxxxxxxx
但是在客户端的日志中却并没有等价的一行。
解决办法: 你有客户端到服务端的单向连接。服务端到客户端的连接被防火墙(通常是在客户端一侧)阻止了。防火墙可能是(a)客户端上运行个人软件防火墙,或者(b)是对客户端的NAT路由网关。修改防火墙设置允许服务端返回的UDP包到达客户端。