[CentOS 7] 使用 OpenVPN 實作 Client to Site VPN 連線

by 4月 18, 2017 3 意見            


PPTP、L2TP/IPSec VPN 被擋掉了,怎麼辦?改用 SSL VPN 來試試吧!

虛擬私人網路 (VPN,Virtual Personal Network)  的用途是當我們人在外面的時候,可以透過 VPN 連線回辦公室,讓電腦的網路就像在內部網段一樣,能正常存取內部網路的資源,像是執行 ERP 軟體、操作資料庫程式、連上 File Server 備份、用網路芳鄰取得同事電腦裡分享的檔案 ...... 等。

可是,偏偏最為人所周知的用途,卻是所謂的 科學上網 ㄈㄢ ㄑ一尢 / 吧。

沒錯!
因為當我們到對岸出差的時候,如果想要收 Gmail、看 Facebook、用 Line ... 等等的服務,時常會被 GFW 擋掉。

我原本是提供 PPTP VPN Server 給外派的同事來連線,可是前陣子 對岸官方發佈了新禁令,再加上 iOS 10 跟 macOS 10.12 終止了 PPTP VPN 的支援。

爬了一些文章,再加上聽了前輩的建議之後,決定不使用 L2TP/IPSec,最終選擇實作 SSL VPN。


Server 端的安裝與設定


先切換到 root 帳號。
su -

加入 EPEL 套件庫,順便更新。
yum -y install epel-release && yum -y update

直接從 EPEL 套件庫裡安裝 OpenVPN 主套件跟 Easy-RSA 金鑰管理套件。
yum install -y openvpn easy-rsa

複製一份主設定檔的範本來設定。
cp /usr/share/doc/openvpn-*/sample/sample-config-files/server.conf /etc/openvpn

接著,依照需求修改主設定檔裡參數的設定值。
vi /etc/openvpn/server.conf

這是去掉註解之後,Server 端設定檔內容。

##### 開始 #####
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 168.95.192.1"
keepalive 10 120
tls-auth ta.key 0
cipher AES-256-CBC
comp-lzo
user nobody
group nobody
persist-key
persist-tun
status openvpn-status.log
verb 3
explicit-exit-notify 1
##### 結束 #####

因為是要讓對岸的同事收 Gmail、上 FB 用的,所以我讓所有的流量都透過 Server 連線:
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 168.95.192.1"

如果只是要連回辦公室裡的 192.168.1.0/24 網段,不需要對外連線,可以這樣子設定:
;push "redirect-gateway def1 bypass-dhcp"
;push "dhcp-option DNS 8.8.8.8"
;push "dhcp-option DNS 168.95.192.1"
push "route 192.168.1.0 255.255.255.0"

這些常用設定值的定義是:
  • 指定本機提供服務的 IP 位址
    local 10.1.2.3
  • 對外的通訊埠
    port 1194
  • 對外通訊埠的協定
    proto udp
  • CA (憑證授權中心,Certificate Authority) 用的憑證、Server 用的憑證、Server 用的金鑰,以及 DH 金鑰交換檔 (迪菲-赫爾曼金鑰交換,Diffie-Hellman key exchange) 儲存的位置
    ca ca.crtcert server.crtkey server.keydh dh2048.pem
  • 使用的網段跟子網路遮罩
    server 10.8.0.0 255.255.255.0
  • 記錄 Client 端使用中的 IP 位址
    ifconfig-pool-persist ipp.txt
  • 將 Client 端的通訊閘位址導向到 OpenVPN Server
    push "redirect-gateway def1 bypass-dhcp"
  • 指定 Client 的 DNS Server 位址
    push "dhcp-option DNS 8.8.8.8"
    push "dhcp-option DNS 168.95.192.1"
  • 允許 Client 端之間可以互連
    client-to-client
  • 允許多個 Client 端用同一組金鑰和憑證連線
    duplicate-cn
  • Server 端每 10 秒送出一次測試訊息,120 秒後 Client 沒回應就視為連線已中斷
    keepalive 10 120
  • HMAC 防火牆,0 代表 Server 端,1 代表 Client 端
    tls-auth ta.key 0
  • 啟用即時壓縮功能 (2.4 版開始支援的 lz4-v2 演算法)
    compress lz4-v2
    push "compress lz4-v2"
  • 啟用即時壓縮功能 (2.4 版之前的 lzo 演算法)
    comp-lzo
  • 同時間內可連線的 Client 端數量上限
    max-clients 100
  • 指定執行 OpenVPN 服務的帳號及群組
    user nobody
    group nobody
  • Server 重新啟動後,通知 Client 端重新建立連線
    explicit-exit-notify 1

產生憑證與金鑰


建立儲存檔案的目錄,並且準備好要產生憑證與金鑰的相關檔案。
mkdir -p /etc/openvpn/easy-rsa/keys
cp -rf /usr/share/easy-rsa/2.0/* /etc/openvpn/easy-rsa
cp /etc/openvpn/easy-rsa/openssl-1.0.0.cnf /etc/openvpn/easy-rsa/openssl.cnf

修改憑證的預設資料,之後產生憑證時就會自動填寫,不必再手動輸入。
vi /etc/openvpn/easy-rsa/vars

我會修改的設定值有:
  • CA 金鑰跟憑證的有效時間,單位是天(day)
    export CA_EXPIRE=3650
    export KEY_EXPIRE=3650
  • 所有憑證資料的預設值:國家、省份、城市、組織、電子郵件位址、單位。
    export KEY_COUNTRY="TW"
    export KEY_PROVINCE="Taiwan"
    export KEY_CITY="Taiching"
    export KEY_ORG="ITist.tw"
    export KEY_EMAIL="webmaster@itist.tw"
    export KEY_OU="IT Dept."

載入剛剛建立的憑證預設資料。
cd /etc/openvpn/easy-rsa
source ./vars

清除所有舊的金鑰跟憑證,上個步驟有提到清除的目錄是 /etc/openvpn/easy-rsa/keys。
./clean-all

產生 CA 的金鑰及憑證,設定值不需修改的話,可以直接按 Enter 使用 vars 檔案裡的預設值。
./build-ca

產生 VPN Server 端的金鑰及憑證,同樣可以使用 vas 檔案的預設值。
./build-key-server server

請注意,千萬別一直傻傻的狂按 Enter!
最後有 Sign the certificate? [y/n] 跟 commit? [y/n] ,都要按 y 才行。

產生 DH 金鑰交換檔,這個步驟比較久,可能要跑大約三到五分鐘左右。
./build-dh

將 Server 的金鑰及憑證放到主目錄裡。
cd /etc/openvpn/easy-rsa/keys
cp dh2048.pem ca.crt server.crt server.key /etc/openvpn

產生 Client 的金鑰及憑證,檔案名稱可以自訂,還可以選擇需不需要密碼。
cd /etc/openvpn/easy-rsa

產生不用輸入密碼的憑證。
./build-key client-keyless


產生需要輸入密碼的憑證。
./build-key-pass client


所以我們總共產生了這些金鑰及憑證。

別忘了,還要產生防止 DoS 攻擊跟 UDP port flooding 攻擊用的 HMAC 防火牆金鑰。
cd /etc/openvpn
openvpn --genkey --secret ta.key


防火牆設定及啟用 IP 轉遞


開啟必要的通訊埠,也啟用 IP 偽裝 (Masquerade) 功能。
firewall-cmd --permanent --add-service openvpn
firewall-cmd --permanent --add-masquerade
DEV=$(ip route get 8.8.8.8 | awk 'NR==1 {print $(NF-2)}')
firewall-cmd --permanent --direct --passthrough ipv4 -t nat -A POSTROUTING -s  10.8.0.0/24 -o $DEV -j MASQUERADE
firewall-cmd --reload

啟動 IP 轉遞功能。
echo "net.ipv4.ip_forward = 1"  >> /etc/sysctl.conf
sysctl -p


啟動服務


啟動網路功能及 OpenVPN 服務,並且讓 OpenVPN 開機後自動啟動。
systemctl restart network
systemctl restart openvpn@server
systemctl enable openvpn@server

我們就會看到一個新增的 OpenVPN 專用網路介面:tun0。


Client 端的安裝與設定


我們這邊同樣用 CentOS 7 來示範,而其他平台的 Client 程式下載位置在:

同樣先安裝 OpenVPN。
sudo yum -y install openvpn

建立 Client 端的設定檔。
vi ~/vpn-client.ovpn

這是去掉註解之後的 Client 設定檔內容。

##### 開始 #####
client
proto udp
dev tun
remote 10.1.1.217 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client-keyless.crt
key client-keyless.key
comp-lzo
verb 3
remote-cert-tls server
##### 結束 #####

請注意,
有些必要的設定值絕對要指定跟 Server 端相對應,例如:Server 啟用了 LZO 即時壓縮功能,Client 就一定要跟著啟用,否則會連不上去。

再把剛剛在 Server 建立的 CA 憑證、Client 的憑證和金鑰複製到 Client 這邊來。
scp root@10.1.1.217:/etc/openvpn/easy-rsa/keys/ca.crt ~
scp root@10.1.1.217:/etc/openvpn/easy-rsa/keys/client-keyless.crt ~
scp root@10.1.1.217:/etc/openvpn/easy-rsa/keys/client-keyless.key ~

但是,有些時候我們怕使用者忘了把這些憑證跟 Client 設定檔放在一起,而導致無法連線,所以我們也可以直接把憑證跟金鑰的內容直接貼在設定檔裡面就可以了。



##### 開始 #####
client
proto udp
dev tun
remote 10.1.1.217 1194
resolv-retry infinite
nobind
persist-key
persist-tun
comp-lzo
verb 3
remote-cert-tls server

<ca>
CA 憑證的內容
</ca>
<cert>
Client 憑證的內容
</cert>
<key>
Client 金鑰的內容
</key>
##### 結束 #####

如果我們使用的是免密碼的憑證,Client 會直接連線到 Server 。
openvpn --config vpn-client.ovpn

如果使用的是要密碼的憑證,在讀取憑證前,會要求我們輸入憑證密碼,正確輸入之後才能連線到 Server。

而其他平台也一樣,只要把這個設定檔、金鑰及憑證都複製過去,就可以用相同的設定值來連線了。


異常處理

Server 端的錯誤訊息

OpenSSL: error:0906D06C:PEM routines:PEM_read_bio:no start line
OpenSSL: error:140AD009:SSL routines:SSL_CTX_use_certificate_file:PEM lib

這代表 Server 憑證有問題,請重新產生憑證。

Client 端的錯誤訊息

WARNING: No server certificate verification method has been enabled.

這是因為沒有指定憑證的驗證方式,加上 remote-cert-tls server 這行設定值即可,可參閱 OpenVPN HOWTO

TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)
TLS Error: TLS handshake failed

金鑰無法通過驗證,這可能是因為通訊埠沒開、網路太慢或斷線,請參閱 OpenVPN FAQ


參考資料

圖片來源

更新紀錄
  • 2017/04/18 發文。

Heracles Jam,江湖人稱「海公公」

IT 技術家 - 創站部落客

一個常用 Windows、慣用 macOS、愛用 Linux 的 3C 阿宅
現職 MIS / 業界講師 / 資訊顧問 / 部落客

3 則留言 :

  1. OpenVPN 在大陸不會被擋嗎

    回覆刪除
    回覆
    1. 我很想回答你:「不會」....
      可是很遺憾,它還是有可能被擋,只是目前被阻擋的比例相對較低而已....

      刪除
  2. 真的超級詳細的,太感謝了!

    回覆刪除