第3章 虛拟專用網絡
虛拟專用網絡(Virtual Private Network,VPN)架設在公共共享的網際網路基礎設施上,在非受信任的網絡上建立私有的和安全的連接配接,把分布在不同地域的資訊基礎設施、辦公場所、使用者或者商業夥伴互聯起來。
虛拟專用網絡使用加密技術為通信提供安全保護,以對抗對通信内容的竊聽和主動的攻擊。虛拟專用網絡在今天被廣泛地使用到遠端互聯中。在虛拟專用網絡技術出現之前,不同辦公場所互聯組建專用私有網絡時,企業往往需要投入較大的成本用于租賃專用線路。虛拟專用網絡的出發點是建立虛拟的專用鍊路,在網際網路上進行傳輸并使用加密技術進行通信安全防護。
虛拟專用網絡的使用場景如下。
- 安全互聯:把多個分布在不同地域的伺服器或者網絡安全地連接配接起來。
- 指定網絡流量路由:把多個點之間的網絡流量通過虛拟專用網絡的隧道進行連接配接後,可以使用動态路由等優化内部網絡通信。
- 匿名通路:通過虛拟專用網絡通道,可以隐藏用戶端的來源IP位址,在某些場景下可以起到保護使用者的作用。
本章将首先概要描述目前使用比較多的各種虛拟專用網絡建構技術、方案和原理,然後重點講解使用OpenVPN建構企業級虛拟專用網絡的最佳方案,深入研究其中的核心配置參數,最後對OpenVPN的排錯思路和方法進行指導。
3.1 常見虛拟專用網絡建構技術
目前我們在實踐中,經常遇到的虛拟專用網絡建構技術,大緻上分以下3類:
- 點到點的隧道協定(Point-to-Point Tunneling Protocol,PPTP)虛拟專用網絡
- 網際網路協定安全(Internet Protocol Security,IPSec)虛拟專用網絡
- 安全接口層/安全傳輸層協定(Secure Sockets Layer/Transport Layer Security,SSL/TLS)虛拟專用網絡
3.1.1 PPTP虛拟專用網絡的原理
PPTP使用建立于TCP之上的通道來進行控制,使用通用路由封裝協定(Generic Routing Encapsulation,GRE)隧道技術來封裝點到點協定(Point to Point Protocol,PPP)包。PPTP規範裡面沒有描述加密和認證的特性,它依賴于底層的PPP協定來實作資料安全的功能。
PPTP的第1個隧道首先通過和對端伺服器的TCP 1723端口進行通信來建立。在該TCP連接配接建立後,再建立第2個隧道GRE來進行資料傳輸。在RFC 2673中較長的描述了PPTP協定的控制和資料通信過程。
在Linux環境中,我們可以使用pptpd進行PPTP虛拟專用網絡的架設。
3.1.2 IPSec虛拟專用網絡的原理
IPSec是一組基于IP協定的協定組。它使得兩台或者多台主機之間通過認證和加密每個IP包以一個安全的方式進行通信。IPSec由以下協定組成。
- 封裝的安全負荷(Encapsulated Security Payload,ESP):通過使用對稱加密算法(比較常用的,如Blowfish和3DES)來加密通信内容,以防止被第三方竊聽和幹擾通信。
- 認證頭部(Authentication Header,AH):通過計算校驗和的方式來對通信雙方的資料進行認證,防止被第三方篡改。
- IP負荷壓縮協定(IP Payload Compression Protocol,IPComp):通過壓縮IP的負荷來減少資料通信量,提高性能。
IPSec虛拟專用網絡有以下兩種工作模式。
- 傳輸模式:僅IP資料負荷被加密,IP和路由資訊不做修改。這個模式主要在兩個伺服器之間進行Host-to-Host加密通信時使用。
-
隧道模式:整個IP包都被加密。這個模式主要在不同網絡之間建構Network-to-Network的虛拟專用網絡時使用。
在Linux環境中,使用範圍比較多的IPSec虛拟專用網絡實作方案是strongSwan(官方網站:
https://www.strongswan.org )和FreeS/WAN(官方網站: https://www.freeswan.org )。
IPSec也是大部分商業硬體防火牆或者路由器所支援的VPN建構協定。
3.1.3 SSL/TLS虛拟專用網絡的原理
SSL/TLS虛拟專用網絡的工作過程如下。
- 認證過程:在SSL/TLS的握手過程中,用戶端和伺服器端分别使用對方的證書來進行認證。
- 加密過程:在SSL/TLS的握手過程中,用戶端和伺服器端使用非對稱算法計算出對稱密鑰進行資料加密。
SSL/TLS虛拟專用網絡主要使用了以下的虛拟裝置。
tun/tap裝置:Linux中提供了兩種虛拟網絡裝置tun/tap裝置。通過對這兩種裝置的讀寫操作,實作核心與使用者态程式的互動。
在Linux環境中,SSL/TLS虛拟專用網絡的典型代表是OpenVPN(OpenVPN項目的官方網站是
https://openvpn.net對于3.1.1節、3.1.2節和本節中講到的3種虛拟專用網絡技術來說,其各有特點。總的來說:
- PPTP需要建立兩個隧道進行通信,控制和資料傳輸分離,其中傳輸資料使用GRE。在同一個區域網路裡面的多個内網主機需要建立多條GRE通道連接配接到同一台虛拟專用網絡伺服器時,需要在防火牆或者網絡位址轉換裝置上進行特殊設定,以增加對Call ID的支援,否則會導緻隧道建立失敗。
- IPSec虛拟專用網絡是一個成熟的方案,但其配置較複雜,學習成本較高。IPSec虛拟專用網絡在商業硬體裝置上實作得較多。
- SSL/TLS虛拟專用網絡工作在使用者态,不需要對核心做特殊的修改,可移植性較高;且配置簡單,學習成本低。接下來的章節将重點介紹該開源虛拟專用網絡軟體的最佳配置。
3.2 深入了解OpenVPN的特性
使用OpenVPN,我們可以實作以下功能:
- 對任何IP子網或者虛拟以太網通過一個UDP或者TCP端口來建立隧道。
- 架構一個可擴充的、負載均衡的虛拟專用網絡叢集系統,同時支援來自上千使用者的連接配接。
- 使用任意的加密算法、密鑰長度或者HMAC摘要。這些功能是使用OpenSSL庫來實作的。
- 可以選擇最簡單的靜态密碼的傳統加密算法或者基于證書的公鑰私鑰加密算法。
- 對資料流進行實時壓縮。
- 支援對端節點通過動态方法擷取IP位址,例如DHCP等。
- 對于面向連接配接的有狀态防火牆,不需要使用特殊的設定。
- 支援網絡位址轉換。
- 在Windows或者mac OS上提供GUI工具,友善配置。
3.3 使用OpenVPN建立點到點的虛拟專用網絡
在某些運維場景中,我們會遇到隻需要把兩台處于Internet上的伺服器使用虛拟專用網絡互聯起來的需求,比如遠端的SNMP資訊抓取、遠端資料庫備份等。
在這種情況下,我們可以使用OpenVPN來建立點到點(Peer-to-Peer)的虛拟專用網絡的實體架構,如圖3-1所示。

建立點到點模式的虛拟專用網絡的操作步驟如下。
1)在兩台需要互聯的伺服器x.y.z.28和a.b.c.239上都執行如下安裝操作。
#下載下傳epel的擴充倉庫,其中提供了OpenVPN的rpm包
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
#安裝epel的rpm包
rpm -ivh epel-release-latest-6.noarch.rpm
#安裝OpenVPN前,需要安裝OpenVPN的依賴庫(lzo庫用于壓縮;openssl庫用于支援加密和證書認證)
yum -y install lzo lzo-devel openssl openssl-devel
#安裝OpenVPN
yum -y install openvpn
2)在伺服器x.y.z.28上生成靜态密碼。使用的指令如下。
openvpn --genkey --secret key
key的内容如下:
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
8acc8d8feae2fc13ec66fac4eabc72b8
10fa75f239e8cd77d0cec0361dd77046
c6e757c9ed392410b6671899229983cc
6c85f9a3449ae6847fb569559bdebd93
bfecdf00bee63453e2cac80e4429e98d
3162eae826837836fe37959fd96040c4
445b568028e8cc251e557d3ce39b88e2
385af0b64bcb7860bc133859bcd9a8da
63f2729b1f5ebf003cb26005249dcf03
9fd37cba370af73be523ad549a3df6b5
b53f441e674f8e05201f051ce66f2f87
83c3c33fd29cf7bfb85be3370ee00c07
a8e7227e78557155fb365c812570d8bf
c0bf845a7c24abc262de77a68567d1b2
afc96447fcfc1e3286f18a22512abfa3
f68bcd0bfe892fa14848166bc1b36bac
-----END OpenVPN Static key V1-----
3)使用scp把該key檔案傳到對端a.b.c.239伺服器上。
4)建立隧道。
在伺服器x.y.z.28上執行以下指令。
openvpn --remote a.b.c.239--dev tun0 --ifconfig 10.6.0.1 10.6.0.2 --secret key --daemon
在對端伺服器a.b.c.239上執行以下指令。
openvpn --remote x.y.z.28 --dev tun0 --ifconfig 10.6.0.2 10.6.0.1 --secret key --daemon
其中的關鍵配置項解釋如下:
- --remote,指定點到點架構中對端的公網IP。
- --dev,指定使用tun裝置。
- --ifconfig,指定虛拟隧道的本端和遠端IP位址。
- --secret,指定包含靜态密碼的檔案。
- --daemon,指定使用背景駐守程序的模式。
執行步驟4後,兩台伺服器之間的虛拟專用網絡如圖3-2所示。
5)驗證隧道功能。
ping 10.6.0.2 -c 2
在a.b.c.239使用tcpdump可以看到以下輸出。
tcpdump -vvv -nnn -i tun0 icmp
tcpdump: listening on tun0, link-type RAW (Raw IP), capture size 65535 bytes
10:07:04.031236 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.6.0.1 > 10.6.0.2: ICMP echo request, id 26451, seq 1, length 64
10:07:04.031272 IP (tos 0x0, ttl 64, id 42617, offset 0, flags [none], proto ICMP (1), length 84)
10.6.0.2 > 10.6.0.1: ICMP echo reply, id 26451, seq 1, length 64
10:07:05.032546 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.6.0.1 > 10.6.0.2: ICMP echo request, id 26451, seq 2, length 64
10:07:05.032565 IP (tos 0x0, ttl 64, id 42618, offset 0, flags [none], proto ICMP (1), length 84)
10.6.0.2 > 10.6.0.1: ICMP echo reply, id 26451, seq 2, length 64
10:07:06.033775 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
tun和tap是Linux等作業系統中提供的一種虛拟網絡裝置。tun裝置可以了解為Point-to-Point的裝置;tap裝置可以了解為Ethernet裝置。
需要注意的是:tun/tap裝置不是從實體網卡裝置中讀取包,而是從使用者空間的程式中讀取包;向該裝置寫入時,并不實際從實體網卡裝置上發出包,而是由核心送出到應用程式。
講起來比較難以了解,那麼我們以本案例中的ping 10.6.0.2為例,對OpenVPN使用到的關鍵技術tun裝置進行詳細說明。
在伺服器x.y.z.28上由使用者使用BASH輸入ping 10.6.0.2後,tun裝置和核心、OpenVPN及實體網卡之間的工作流程如圖3-3所示。
詳細說明如下:
1)使用者使用BASH程序輸入ping 10.6.0.2。此時,核心收到的IP包位址資訊為:源位址10.6.0.1,目的位址10.6.0.2。
2)核心經過路由判斷,把該IP包寫入tun0裝置(tun0的IP位址是10.6.0.1)。
3)OpenVPN程序讀取該IP包。
4)OpenVPN對該包進行封裝、加密後,向核心寫入,此時IP包位址資訊為:源位址x.y.z.28,目的位址a.b.c.239。1)中的包資訊,含IP頭部,被封裝到該IP包内。
5)核心經過路由判斷,把該包寫入實體網卡(Physical NIC)。
6)實體網卡經過封裝成幀(Frame)通過實體鍊路,經過網際網路發送到a.b.c.239上。
伺服器a.b.c.239收到經過網際網路傳輸過來的資料時,它的工作流程如圖3-4所示。
1)實體網卡收到幀(Frame)。
2)實體網卡将幀送出到核心。
3)OpenVPN讀取該IP包後,經過解封裝、解密,獲得内容是ICMP的ping包,目的位址是tun0。
4)OpenVPN向tun0寫入經過步驟3解封的ICMP包。
5)核心子產品處理。
核心子產品處理完成後,會發回ICMP請求響應。回包的流程與圖3-3中所示的流程相同。
3.4 使用OpenVPN建立遠端通路的虛拟專用網絡
在上個實踐中,我們建立了兩台具有公網IP的伺服器之間的虛拟專用網絡,進行安全的資料傳輸。在本案例中,我們将建立遠端通路(Remote Access)模式的虛拟專用網絡。
在某些文檔中,遠端通路被稱為Road Warrior(可以翻譯為“移動辦公”),是指為經常不在辦公室的駐場人員或者遠端辦公的人員提供通路伺服器資源或者辦公網絡資源的通道。在這些場景中,遠端通路者一般沒有公網IP,他們使用内網位址通過防火牆裝置進行網絡位址轉換後連接配接網際網路。
在本例中,我們使用的實體網絡結構圖如圖3-5所示。
建立遠端通路模式的虛拟專用網絡的操作步驟如下。
1)在伺服器a.b.c.239上生成CA憑證、伺服器證書、用戶端證書。
在OpenVPN 2.0.9的源碼包中有相關的腳本可以輔助我們進行證書的生成和管理。
我們首先從
http://build.openvpn.net/downloads/releases/openvpn-2.0.9.tar.gz下載下傳該代碼。使用如下指令:
wget http://build.openvpn.net/downloads/releases/openvpn-2.0.9.tar.gz
解壓縮後,進入以下目錄:
[root@localhost easy-rsa]# cd openvpn-2.0.9/easy-rsa
[root@localhost easy-rsa]# ls
2.0 build-dh build-key build-key-pkcs12 build-req clean-all make-crl README revoke-full vars
build-ca build-inter build-key-pass build-key-server build-req-pass list-crl openssl.cnf revoke-crt sign-req Windows
生成如下CA憑證:
[root@localhost easy-rsa]# . vars #初始化環境變量
NOTE: when you run ./clean-all, I will be doing a rm -rf on /root/openvpn/openvpn-2.0.9/easy-rsa/keys
[root@localhost easy-rsa]# ./clean-all #删除舊的檔案
[root@localhost easy-rsa]# ./build-ca #建立root 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]:CN #填寫國家代碼
State or Province Name (full name) [NA]:SH #填寫省份
Locality Name (eg, city) [BISHKEK]:SH #填寫城市
Organization Name (eg, company) [OpenVPN-TEST]:XUFENG-INFO #填寫組織名
Organizational Unit Name (eg, section) []:DEVOPS #填寫部門名稱
Common Name (eg, your name or your server's hostname) []:cert.xufeng.info
Email Address [[email protected]]:[email protected] #填寫管理者郵箱位址
生成OpenVPN伺服器證書和私鑰如下:
[root@localhost easy-rsa]# ./build-key-server vpnserver #extension = server
Generating a 1024 bit RSA private key
...........++++++
..........................................++++++
writing new private key to 'vpnserver.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]:CN
State or Province Name (full name) [NA]:SH
Locality Name (eg, city) [BISHKEK]:SH
Organization Name (eg, company) [OpenVPN-TEST]:XUFENG-INFO
Organizational Unit Name (eg, section) []:VPN
Common Name (eg, your name or your server's hostname) []:vpnserver.xufeng.info
Email Address [[email protected]]:[email protected]
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /root/openvpn/openvpn-2.0.9/easy-rsa/openssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'CN'
stateOrProvinceName :PRINTABLE:'SH'
localityName :PRINTABLE:'SH'
organizationName :PRINTABLE:'XUFENG-INFO'
organizationalUnitName:PRINTABLE:'VPN'
commonName :PRINTABLE:'vpnserver.xufeng.info'
emailAddress :IA5STRING:'[email protected]'
Certificate is to be certified until Dec 8 06:56:36 2025 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
生成用戶端需要的證書和私鑰如下:
[root@localhost easy-rsa]# ./build-key vpnclient2
Generating a 1024 bit RSA private key
........................++++++
......++++++
writing new private key to 'vpnclient1.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]:CN
State or Province Name (full name) [NA]:SH
Locality Name (eg, city) [BISHKEK]:SH
Organization Name (eg, company) [OpenVPN-TEST]:XUFENG-INFO
Organizational Unit Name (eg, section) []:VPN
Common Name (eg, your name or your server's hostname) []:vpnclient2.xufeng.info
Email Address [[email protected]]:[email protected]
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /root/openvpn/openvpn-2.0.9/easy-rsa/openssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'CN'
stateOrProvinceName :PRINTABLE:'SH'
localityName :PRINTABLE:'SH'
organizationName :PRINTABLE:'XUFENG-INFO'
organizationalUnitName:PRINTABLE:'VPN'
commonName :PRINTABLE:'vpnclient2.xufeng.info'
emailAddress :IA5STRING:'[email protected]'
Certificate is to be certified until Dec 8 06:57:53 2025 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
2)在伺服器a.b.c.239配置OpenVPN,配置檔案是server.conf。配置檔案的内容如下:
port 1194 #使用1194端口進行監聽
proto udp #使用UDP協定
dev tun #使用IP路由模式
ca /etc/openvpn/ca.crt #指定CA憑證位置
cert /etc/openvpn/vpnserver.crt #指定伺服器端證書位置
key /etc/openvpn/vpnserver.key #指定伺服器端私鑰位置
dh /etc/openvpn/dh1024.pem #使用Diffie-Hellman算法進行加密密鑰計算
server 172.16.100.0 255.255.255.0 #用戶端連接配接上虛拟專用網絡後從此網段配置設定隧道IP
client-config-dir /etc/openvpn/ccd #使用此目錄對各個虛拟專用網絡用戶端進行細粒度控制
route 192.168.20.0 255.255.255.0 #配置伺服器增加一條到用戶端網絡的路由
client-to-client #允許不同的用戶端進行互相通路,使用OpenVPN内部路由
keepalive 10 120 #每10s發送保活,120s内未收到保活資訊時向OpenVPN程序發送SIGUSR1信号
#在TLS控制通道的通信協定上增加一層HMAC(Hash-based Message Authentication Code)防止dos攻擊
tls-auth /etc/openvpn/ta.key 0
comp-lzo #啟用壓縮
max-clients 100 #最大使用者數
user nobody #執行OpenVPN程序的使用者
group nobody #執行OpenVPN程序的組
persist-key #收到信号SIGUSR1時不重新讀取key檔案
persist-tun #收到信号SIGUSR1時不關閉tun虛拟網口和重新打開
#建立并修改權限,使nobody可以讀寫 /var/log/openvpn
status /var/log/openvpn/status.log #指定狀态日志位置
log-append /var/log/openvpn/openvpn.log #指定運作日志位置
verb 4 #設定日志級别為一般級别,會記錄正常連接配接資訊和報錯
我們來看看/etc/openvpn/ccd下檔案vpnclient2.xufeng.info中的内容:
ifconfig-push 172.16.100.9 172.16.100.10 #指定用戶端的IP為172.16.100.9
iroute 10.192.168.20.0 255.255.255.0 #加一條内部路由
push "route 10.168.103.0 255.255.255.0" #把該路由推送到用戶端執行
啟動OpenVPN伺服器程序。使用如下的指令:
openvpn --daemon --config /etc/openvpn/server.conf
3)在192.168.20.96上安裝OpenVPN GUI,并部署配置檔案。
在
https://openvpn.net/index.php/download/community-downloads.html頁面進行下載下傳。
在32位Windows 7 系統上,我們通過以下連結進行下載下傳并安裝:
https://swupdate.openvpn.org/community/releases/openvpn-install-2.3.9-I601-i686.exe在安裝過程中,可能會出現确認界面,如圖3-6所示。
請勾選“始終信任來自‘OpenVPN Technologies,Inc.’的軟體(A)”。
安裝完成後,在目錄C:Program FilesOpenVPNconfig下面部署如下檔案,如圖3-7所示。
vpnclient.ovpn内容如下:
client #指定角色為用戶端
dev tun #和伺服器端一緻
proto udp #和伺服器端一緻
remote a.b.c.239 1194 #指定伺服器端IP和端口
resolv-retry infinite #連接配接失敗時重複嘗試
nobind #不指定本地端口
persist-key #收到信号SIGUSR1時不重新讀取key檔案
persist-tun #收到信号SIGUSR1時不關閉tun虛拟網口和重新打開
ca ca.crt #指定CA憑證位置
cert vpnclient2.crt #指定用戶端證書位置
key vpnclient2.key #指定用戶端私鑰位置
ns-cert-type server #要求伺服器端的證書的擴充屬性為server
#在TLS控制通道的通信協定上增加一層HMAC(Hash-based Message Authentication Code)防止dos攻擊
tls-auth ta.key 1
comp-lzo #啟用壓縮
verb 4 #設定日志級别為一般級别,會記錄正常連接配接資訊和報錯
keepalive 10 120 #每10s發送保活,120s内未收到保活資訊時向OpenVPN程序發送SIGUSR1信号
log-append openvpn.log #指定log位置
經過以上3個步驟後,用戶端192.168.20.96可以使用虛拟隧道和虛拟專用網絡伺服器進行通信。但此時無法與10.168.103.171通信。為了實作用戶端192.168.20.96可以與10.168.103.171通信,必須在a.b.c.239這個虛拟專用網絡伺服器上執行以下的操作:
#啟用ip_forward
sed -e 's/net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf
sysctl -p
#增加iptables對tun0的轉發支援
iptables -A FORWARD -i tun0 -j ACCEPT
#加入網絡位址轉換的轉發
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE #eth1為伺服器内網端口
iptables -t nat -A POSTROUTING -o tun0
-j MASQUERADE #tun0為虛拟隧道端口
同時在10.168.103.171伺服器上執行以下的操作:
route add -net 192.168.20.0/24 gw 10.168.103.239
4)在192.168.20.96上,連接配接OpenVPN伺服器并進行網絡測試。
連接配接後,我們在192.168.20.96上可以看到它獲得的隧道IP位址,如圖3-8所示。
由此可見,它獲得的隧道IP位址和伺服器端配置檔案/etc/openvpn/ccd/vpnclient2.xufeng.info中使用ifconfig-push指令配置的完全一緻。
它獲得的路由如圖3-9所示。
在遠端通路模式下,從虛拟專用網絡用戶端192.168.20.96使用ICMP ping伺服器Host:a.b.c.239所在區域網路中的一台伺服器10.168.103.171的虛拟網絡資料流圖如圖3-10所示。
可以看到,OpenVPN起到虛拟路由器的作用,使用net30的模式,建立起遠端通路者和虛拟專用網絡伺服器之間的虛拟專用網絡。方框中的IP包标示出了在虛拟專用網絡用戶端發出的包到達虛拟專用網絡伺服器時經過網絡位址轉換的情況。此時,在伺服器10.168.103.171上看到的ICMP的來源IP位址是虛拟專用網絡伺服器(Host:a.b.c.239)的内網IP位址10.168.103.239。
在伺服器10.168.103.171使用tcpdump抓取ICMP網絡通信的結果如下:
# tcpdump -vvv -nnn -i em1 -c 3 icmp
tcpdump: listening on em1, link-type EN10MB (Ethernet), capture size 65535 bytes
10:38:35.015495 IP (tos 0x0, ttl 127, id 654, offset 0, flags [none], proto ICMP (1), length 60)
10.168.103.239 > 10.168.103.171: ICMP echo request, id 1, seq 9923, length 40 #源位址已經被轉換成VPN伺服器的内網位址
10:38:35.016139 IP (tos 0x0, ttl 64, id 64964, offset 0, flags [none], proto ICMP (1), length 60)
10.168.103.171 > 10.168.103.239: ICMP echo reply, id 1, seq 9923, length 40
10:38:36.017624 IP (tos 0x0, ttl 127, id 655, offset 0, flags [none], proto ICMP (1), length 60)
10.168.103.239 > 10.168.103.171: ICMP echo request, id 1, seq 9924, length 40 #源位址已經被轉換成虛拟專用網絡伺服器的内網位址
3 packets captured
4 packets received by filter
0 packets dropped by kernel
3.5 使用OpenVPN建立站點到站點虛拟專用網絡
站點到站點(Site-to-Site)虛拟專用網絡,用于連接配接兩個或者多個地域上不同的區域網路LAN,每個LAN有一台OpenVPN伺服器作為接入點,組成虛拟專用網絡,使得不同LAN裡面的主機和伺服器能夠互相通信。
一個典型的站點到站點的虛拟專用網絡實體架構如圖3-11所示。
在部署這種站點到站點模式虛拟專用網絡時,需要注意以下幾點:
- 在所有虛拟專用網絡的接入點,把系統路由轉發打開。
- 在所有虛拟專用網絡的接入點,在tun0端口和内網端口全部配置成網絡位址轉換模式,這樣可以極大地簡化虛拟專用網絡路由設定。
- 在所有虛拟專用網絡的接入點,把iptables轉發設定為允許。
- 每個LAN的主機,通過設定靜态路由或者預設路由,把到對端LAN的通路下一跳指向到本LAN的接入點伺服器的内網IP。
本架構中的虛拟專用網絡用戶端x.y.z.28配置檔案如下,供大家參考。
[root@localhost openvpn]# cat vpnclient.conf
client
dev tun
proto udp
remote a.b.c.239 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca /etc/openvpn/ca.crt
cert /etc/openvpn/vpnclient1.crt
key /etc/openvpn/vpnclient1.key
ns-cert-type server
tls-auth /etc/openvpn/ta.key 1
comp-lzo
verb 4
route-delay 2
keepalive 10 120
log-append /var/log/openvpn/openvpn.log
3.6 回收OpenVPN用戶端的證書
如果我們分發給用戶端的證書不慎被竊取了,或者相關員工離職了,那麼我們必須确認它不能繼續通過OpenVPN接入我們的虛拟專用網絡。在此情況下,我們以收回vpnclient2的證書為例,需要使用如下的指令:
. ./vars
./revoke-full vpnclient2
這樣會在keys目錄下産生一個檔案crl.pem。我們把它複制到/etc/openvpn目錄下。然後在server.conf中加入下面一行:
crl-verify crl.pem
這樣,每次建立虛拟專用網絡連接配接前,OpenVPN伺服器會檢視crl.pem,來确定用戶端的證書是否在收回的清單裡面。如果比對到,則禁止用戶端進行連接配接。
3.7 使用OpenVPN提供的各種script功能
在以上的各個實踐中,我們分别使用了靜态密碼或者證書的方式來提供用戶端的認證。那麼,是不是還有其他方法呢?
答案是肯定的。
可以展現OpenVPN靈活性特點的一個重要方面是它提供了從用戶端認證前、認證中、認證後、隧道建立後等各個階段的script處理功能。我們可以用這些script來實作各種控制功能。
OpenVPN按照執行的順序,提供了以下的一系列腳本功能:
- --up,在TCP/UDP在socket上執行了bind、TUN/TAP打開後執行。
- --tls-verify,遠端開始進行tls認證時執行。
- --ipchange,在用戶端,OpenVPN連接配接認證後執行。
- --client-connect,在伺服器端,用戶端認證後立即執行。
- --route-up,連接配接認證後執行。
- --route-pre-down,路由删除前執行。
- --client-disconnect,在伺服器上,用戶端斷開連接配接時執行。
- --down,TCP/UDP和TUN/TAP關閉後執行。
- --learn-address,在伺服器端,任何路由或者IP位址對應的MAC位址學習時執行。
- --auth-user-pass-verify,在伺服器端,新的用戶端連接配接開始建立的時候執行。
回歸到前面提到的對用戶端進行其他方式認證的問題,那麼我們可以使用--auth-user-pass-verify這個指令實作。
在server.conf中增加如下配置項:
auth-user-pass-verify /etc/openvpn/myauth.pl via-file
myauth.pl腳本輸出0(成功)或者1(失敗)以通知OpenVPN是否認證通過。
通過如下的腳本,我們使用Windows Active Directory來進行使用者的控制,隻有合法的Active Directory賬戶才可以連接配接到我們的虛拟專用網絡。腳本内容如下:
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Net::LDAP;
my $tmpfile = $ARGV[0];#OpenVPN程序會把用戶端送出過來的使用者名和密碼記錄在臨時檔案中
my $line = 1;
my $username;
my $password;
my $not_verified = 1;
open( TMP, '<', $tmpfile ) or exit(1); #打開臨時檔案
while (<TMP>) {
chomp;
if ( $line eq 1 ) {
$username = $_; #擷取使用者名
}
else {
$password = $_; #擷取密碼
}
$line++;
}
close(TMP);
if ( !( $username && $password ) ) {
exit(1);
}
# verify via active directory
my $ldap = Net::LDAP->new('shrd.woyo.com', timeout =>3) or exit(1);
my $mesg =
$ldap->bind( $username . "\@" . 'shrd.woyo.com', password => $password );
$mesg->code && exit(1); #使用使用者名和密碼到AD中進行認證
my $searchbase = 'dc=shrd,dc=woyo,dc=com';
#虛拟專用網絡使用者必須屬于vpn組
my $filter = "memberOf=CN=vpn,OU=Accounts,DC=shrd,DC=woyo,DC=com";
my $results = $ldap->search( base => $searchbase, filter => $filter );
foreach my $entry ( $results->entries ) {
if($entry->get_value('mailNickname') && ($entry->get_value('mailNickname') eq $username )) {
$not_verified = 0;
last;
}
}
$ldap->unbind;
exit($not_verified);
3.8 OpenVPN的排錯步驟
在實踐中,運維工程師們經常需要搭建一套OpenVPN的系統或者運維一套已經線上上生産環境中使用的OpenVPN系統。在配置或者維護OpenVPN虛拟專用網絡的過程中,根據不同的需求,我們可能會遇到各種各樣不同的問題。
在此,我們總結了對于OpenVPN系統最佳的排錯步驟。在遇到問題時,可以按照下面的步驟進行排查。
1)認真檢視與分析伺服器端和用戶端的OpenVPN日志。
在伺服器上,我們使用如下指令配置OpenVPN的日志:
log-append /var/log/openvpn/openvpn.log
verb 4
那麼在出現異常時,我們首先需要分析這個檔案。
該檔案分以下幾個部分:
- OpenVPN實際運作時讀取的配置檔案位置和配置項。
以如下的格式開始。
Fri Dec 18 13:25:44 2015 us=656293 Current Parameter Settings:
Fri Dec 18 13:25:44 2015 us=656383 config = '/etc/openvpn/server.conf'
- OpenVPN的版本和OpenSSL版本。
Fri Dec 18 13:25:44 2015 us=660554 OpenVPN 2.3.8 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [MH] [IPv6] built on Aug 4 2015
Fri Dec 18 13:25:44 2015 us=660566 library versions: OpenSSL 1.0.1e-fips 11 Feb 2013, LZO 2.03
Fri Dec 18 13:25:44 2015 us=663615 Diffie-Hellman initialized with 1024 bit key
- OpenVPN本地添加的路由資訊。
Fri Dec 18 13:25:44 2015 us=665243 /sbin/ip link set dev tun0 up mtu 1500
Fri Dec 18 13:25:44 2015 us=668536 /sbin/ip addr add dev tun0 local 172.16.100.1 peer 172.16.100.2
Fri Dec 18 13:25:44 2015 us=670061 /sbin/ip route add 10.128.119.0/24 via 172.16.100.2
Fri Dec 18 13:25:44 2015 us=671212 /sbin/ip route add 192.168.20.0/24 via 172.16.100.2
Fri Dec 18 13:25:44 2015 us=672122 /sbin/ip route add 172.16.100.0/24 via 172.16.100.2
- 用戶端連接配接時的資訊。
Fri Dec 18 13:25:54 2015 us=348333 x.y.z.28:58937 Re-using SSL/TLS context
#壓縮啟用成功
Fri Dec 18 13:25:54 2015 us=348369 x.y.z.28:58937 LZO compression initialized
Fri Dec 18 13:25:54 2015 us=348505 x.y.z.28:58937 Control Channel MTU parms [ L:1542 D:166 EF:66 EB:0 ET:0 EL:3 ]
Fri Dec 18 13:25:54 2015 us=348537 x.y.z.28:58937 Data Channel MTU parms [ L:1542 D:1450 EF:42 EB:143 ET:0 EL:3 AF:3/1 ]
#和用戶端建立連接配接時,本地的配置項
Fri Dec 18 13:25:54 2015 us=348679 x.y.z.28:58937 Local Options String: 'V4,dev-type tun,link-mtu 1542,tun-mtu 1500,proto UDPv4,comp-lzo,keydir 0,cipher BF-CBC,auth SHA1,keysize 128,tls-auth,key-method 2,tls-server'
#和用戶端建立連接配接時,對用戶端配置項的要求
Fri Dec 18 13:25:54 2015 us=348706 x.y.z.28:58937 Expected Remote Options String: 'V4,dev-type tun,link-mtu 1542,tun-mtu 1500,proto UDPv4,comp-lzo,keydir 1,cipher BF-CBC,auth SHA1,keysize 128,tls-auth,key-method 2,tls-client'
Fri Dec 18 13:25:54 2015 us=348743 x.y.z.28:58937 Local Options hash (VER=V4): '14168603'
Fri Dec 18 13:25:54 2015 us=348766 x.y.z.28:58937 Expected Remote Options hash (VER=V4): '504e774e'
Fri Dec 18 13:25:54 2015 us=348824 x.y.z.28:58937 TLS: Initial packet from [AF_INET]x.y.z.28:58937, sid=5e66e4eb b8382cc8
#CA憑證資訊
Fri Dec 18 13:25:54 2015 us=652935 x.y.z.28:58937 VERIFY OK: depth=1, C=CN, ST=SH, L=SH, O=XUFENG-INFO, OU=DEVOPS, CN=cert.xufeng.info, [email protected]
#用戶端證書,注意VERIFY的後面必須是OK
Fri Dec 18 13:25:54 2015 us=653140 x.y.z.28:58937 VERIFY OK: depth=0, C=CN, ST=SH, O=XUFENG-INFO, OU=VPN, CN=vpnclient1.xufeng.info, [email protected]
Fri Dec 18 13:25:54 2015 us=704318 x.y.z.28:58937 Data Channel Encrypt: Cipher 'BF-CBC' initialized with 128 bit key #加密算法
Fri Dec 18 13:25:54 2015 us=704352 x.y.z.28:58937 Data Channel Encrypt: Using 160 bit message hash 'SHA1' for HMAC authentication #HMAC算法
Fri Dec 18 13:25:54 2015 us=704436 x.y.z.28:58937 Data Channel Decrypt: Cipher 'BF-CBC' initialized with 128 bit key
Fri Dec 18 13:25:54 2015 us=704453 x.y.z.28:58937 Data Channel Decrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
Fri Dec 18 13:25:54 2015 us=729243 x.y.z.28:58937 Control Channel: TLSv1.2, cipher TLSv1/SSLv3 DHE-RSA-AES256-GCM-SHA384, 1024 bit RSA
Fri Dec 18 13:25:54 2015 us=729287 x.y.z.28:58937 [vpnclient1.xufeng.info] Peer Connection Initiated with [AF_INET]x.y.z.28:58937
Fri Dec 18 13:25:54 2015 us=729344 vpnclient1.xufeng.info/x.y.z.28:58937 OPTIONS IMPORT: reading client specific options from: /etc/openvpn/ccd/vpnclient1.xufeng.info #确認伺服器上讀到了用戶端的專用配置檔案
Fri Dec 18 13:25:54 2015 us=729586 vpnclient1.xufeng.info/x.y.z.28:58937 MULTI: Learn: 172.16.100.5 -> vpnclient1.xufeng.info/x.y.z.28:58937
Fri Dec 18 13:25:54 2015 us=729610 vpnclient1.xufeng.info/x.y.z.28:58937 MULTI: primary virtual IP for vpnclient1.xufeng.info/x.y.z.28:58937: 172.16.100.5
Fri Dec 18 13:25:54 2015 us=729628 vpnclient1.xufeng.info/x.y.z.28:58937 MULTI: internal route 10.128.119.0/24 -> vpnclient1.xufeng.info/x.y.z.28:58937
Fri Dec 18 13:25:54 2015 us=729648 vpnclient1.xufeng.info/x.y.z.28:58937 MULTI: Learn: 10.128.119.0/24 -> vpnclient1.xufeng.info/x.y.z.28:58937
Fri Dec 18 13:25:56 2015 us=789781 vpnclient1.xufeng.info/x.y.z.28:58937 PUSH: Received control message: 'PUSH_REQUEST'
Fri Dec 18 13:25:56 2015 us=789819 vpnclient1.xufeng.info/x.y.z.28:58937 send_push_reply(): safe_cap=940
Fri Dec 18 13:25:56 2015 us=789862 vpnclient1.xufeng.info/x.y.z.28:58937 SENT CONTROL [vpnclient1.xufeng.info]: 'PUSH_REPLY,route 172.16.100.0 255.255.255.0,topology net30,ping 10,ping-restart 120,route 10.168.103.0 255.255.255.0,route 192.168.20.0 255.255.255.0,ifconfig 172.16.100.5 172.16.100.6' (status=1) #向用戶端發送的PUSH内容
2)對比分析伺服器端和用戶端的配置檔案,確定相關配置項一緻。
這裡提供一個簡單有效的方法。首先把伺服器配置檔案和用戶端配置檔案都下載下傳下來,對二者内容使用Linux中的diff或者Windows中的Beyond Compare進行對比。使用diff指令時操作如下:
sort server.conf > server.conf.1
sort vpnclient.conf > vpnclient.conf.1
diff server.conf.1 vpnclient.conf.1
3)檢查伺服器是否打開轉發并被防火牆允許。
使用如下的指令,确認值是1。
# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
使用如下的指令,确認chain FORWARD為ACCEPT,或者顯式地指定了tun0的FORWARD為ACCEPT。
iptables -L -n
4)檢查伺服器上網絡位址轉換的設定。
如下是一個正确使用iptables-save之後的網絡位址轉換配置内容:
*nat
:PREROUTING ACCEPT [176:15277]
:POSTROUTING ACCEPT [44:2480]
:OUTPUT ACCEPT [36:2160]
-A POSTROUTING -o eth1 -j MASQUERADE #虛拟專用網絡伺服器内網口啟用網絡位址轉換
-A POSTROUTING -o tun0 -j MASQUERADE #虛拟專用網絡伺服器隧道口啟用網絡位址轉換
COMMIT
5)檢查主機的路由表。在所有參與網絡通信的伺服器上,按照網絡資料流的路徑,依次使用route或者traceroute指令檢查下一跳是否正确。如指向不正确,則修正。
6)使用tcpdump進行分析。
如以上步驟依然無法排除問題,可以使用tcpdump進行抓包分析。
3.9 本章小結
虛拟專用網絡通過使用軟體來互聯不同地域分布的分支機構、人員,為業務提供安全的加密通道,有效地擴充了區域網路的範圍。同時,借助開源方案,能夠顯著降低總擁有成本(Total Cost of Ownership,TCO)。
本章首先介紹了常見的虛拟專用網絡建構技術和原理,并簡要對比分析了它們的特點。然後我們實踐了OpenVPN建構3種不同網絡結構的虛拟專用網絡,指出其中核心配置内容和證書管理等。通過對OpenVPN排錯步驟的梳理,我們希望讀者能夠建立一套高效的問題排查思路,在遇到任何OpenVPN相關的故障時,都能從容不迫地去分析、處理、總結。
OpenVPN作為一款具有超過10年曆史的開源SSL虛拟專用網絡實作方案,具有良好的穩定性和性能,同時在國内外也有良好的技術生态圈,應用非常廣泛,值得每個運維工程師去研究、學習、使用。
推薦閱讀材料
https://openvpn.net/community-resources/how-to,OpenVPN手冊。
《Troubleshooting OpenVPN》,Eric F Crist著。該書專注于OpenVPN的調試和排錯。
本章重點内容助記圖
本章涉及的内容較多,是以,筆者特編制了圖3-12以幫助讀者了解和記憶重點内容。