StrongSwan 實驗

我的手機不知道在哪一年的更新之後,內建的 VPN 就只剩下 IKEv2/IPsec 這種方式了,又不知道在哪天我就開始想要自己架一個 VPN 伺服器,2024 年的寒假我就開始研究怎麼樣用 VPN 連線回家。

因為系統是 Linux,第一個在網路上找到的就是 strongSwan 這套軟體,然後又找了一下網路上的教學,但我照著教學不知道為什麼就是連線不了,憑證也是簽了又刪無數次。但我沒有因此放棄,我直接去看官方文件,官方的文件都是用 swanctl 設定檔的格式寫的,我本來還堅持用 strongSwan 的預設格式,因為網路上的教學撰寫的時間久遠,我最一開始接觸到的就是如此,但在試用之後才發現 swanctl 的設定檔更加的人性化,比原本的格式不知道好了多少。strongSwan 官方還給出了大部分設定的範例,應該百分之九十的情況都可以處理。

因此我決定寫一篇相對比較新的教學,也算是做個紀錄,給未來想要架設的人有個方向。

概要

以下是我自己整理的重點:

  • IPsec 用於保護兩個節點之間的資料傳輸,使用 UDP 協議傳輸
  • IPsec 在開始傳輸之前需要先進行金錀協商和身份驗證,而實作方法常見的有 L2TP 或 IKEv2,因此常常可以在手機看到 L2TP/IPsec 或 IKEv2/IPsec,而 strongSwan 提供的是 IKEv2/IPsec
  • IKEv2 分為兩步
    • 第一步兩個節點會協商出保護第二步的密鑰和後續必要的資訊
    • 第二步會進行身份驗證及協商出 IPsec 的密鑰,此時的封包受到第一步協商出的密鑰加密
  • 理論上不存在伺服端跟客戶端,但實際上還是會有一端當成伺服器
  • 伺服端跟客戶端都需要設定驗證方式,只有在兩邊都驗證通過才能連線
  • 驗證方式有憑證、EAP、PSK 三種,EAP 在易用性跟安全性上取得了平衡
    • EAP 如果想要也可以用第三方伺服器驗證(RADIUS)
  • 伺服器一般來說都會用憑證做為自身的憑證方式,手機版 strongSwan 客戶端也只能連線使用憑證驗證的伺服器

連接握手

下方使用設定如下:

  • 伺服器為憑證驗證
  • 客戶端為 EAP 驗證

IKEv2 握手有四步:

  1. 客戶端對伺服器握手
  2. 伺服器返回握手,如果有開啟憑證請求會在這一步傳送
  3. 客戶端返回對應的驗證方式,這裡是 EAP。若有開啟憑證請求也會一同傳送
  4. 伺服器返回憑證
  • 在握手的前兩步雙方會協商出密鑰保護第三步和第四步
  • 憑證請求的目地在於雙方皆可以設定不主動傳送憑證,若不主動傳送則需要憑證請求才能得到憑證
    • 例如 Windows 或 strongSwan-network-manager 皆不會主動傳送憑證
    • 憑證請求較消耗流量,可以自行決定是否開啟

參考資料

架設

以下是我自己整理的重點:

  • 如果使用 Docker 要開始 privileged 才能使用
  • strongswan 需要在 ipsec 這個套件上面運作,在安裝 strongswan 的時候會自動連同 ipsec 一起安裝
  • 新版的 strongswan 使用 swanctl 來管理各種設定,網路上有些教學使用僅 strongSwan 的設定檔,兩者功能相同
  • 架設需要安裝套件,下方列出的套件皆可使用 apt 安裝
    • iptables 流量轉發用,不裝僅能連線但沒有網路
    • strongswan 核心
    • strongswan-swanctl 管理 strongswan 的設定檔等,強烈推薦使用
    • strongswan-pki 可由 OpenSSL 替代
    • libstrongswan-extra-plugins 加解密等等的算法套件
  • 若直接安裝套件有些功能無法使用,例如 TPM 等等,因此特殊功能需要自行編譯
  • 需要準備伺服器用的憑證
  • 伺服器的封包轉發和 iptables 流量轉發要設定才能連到外網

憑證

以下是我自己整理的重點:

  • 一定要先懂基本的 PKI,可以參考這部影片
  • 能不自簽就不自簽,因為細節非常多,一個不小心就不能連線
    • 我自己測試了網路上申請的憑證 Buypass、Let’s Encrypt 皆沒有問題
    • 從網路上申請的憑證一定需要域名,換句話說不想自簽就一定需要有域名
  • 如果客戶端要使用憑證做為驗證,除非客戶端有辦法從網路上申請到憑證,否則一定需要自簽

申請憑證重點如下:

  • 一定需要域名,沒有域名無法申請
  • 推薦 Let’s Encrypt 的憑證,註冊方法可以參考官方文件
    • 自動化申請可以使用 Certbot,使用方法可以參考官方文件,這個是最簡單的方法

自簽憑證重點:

  • 如果沒有域名,則自簽憑證內容的所有域名都以 IP 代替

  • 手機版 strongSwan 跟 Windows 當客戶端連線對憑證各自不同的要求,自簽一定需要注意

  • 需要準備根憑證,只有被根憑證簽屬的憑證才可以被信任,因此根憑證的私鑰強烈建議要加密

    • 假設客戶端使用自簽憑證做為驗證手段,則伺服端一定要有根憑證才可以驗證,反之亦然
  • 所有憑證需要是 X509v3 的版本才能使用,因為需要有一些額外的資訊用於驗證

  • 過程中所有的金鑰生成請使用 RSA 或 ECDSA,因為本人在測試時發現會發生錯誤

    • 我僅在 Zenfone 8 和 Windows 10 上進行測試,其它系統因為我也沒有,所以無法測試
  • Android 和 Windows 憑證安裝使用 PKCS#12 格式

  • CN 和 SAN 一定要設定成域名,缺一不可

  • Extended Key Usage 需要有 TLS Web Server Authentication

  • 伺服器憑證我推薦使用 OpenSSL 簽發,因為需要比較多細項,建議使用設定檔或 pki 生成

    伺服器憑證設定檔範例```plaintext [ req ] prompt = no # 天數 days = 30 distinguished_name = req_distinguished_name req_extensions = v3_req

    [ req_distinguished_name ]

    根域名

    commonName = worldofwheat.us.to

    [ v3_req ] basicConstraints = critical, CA:FALSE extendedKeyUsage = serverAuth subjectAltName = @sans

    [ sans ]

    IKEv2 主要驗的就是下面的值,可以新增多筆紀錄

    DNS.0 = worldofwheat.us.to DNS.1 = vpn.worldofwheat.us.to

    DNS.1 = test.worldofwheat.us.to

    1
    
    </details>
    

常用指令如下,OpenSSL 和 pki 指令功能相同:

  • 過程中需要動用到很多指令的操作。strongSwan 官方有給出 pki 這套工具,也可以使用 OpenSSL 代替
  • 生成私鑰
    • openssl genpkey -outform pem -algorithm rsa -pkeyopt rsa_keygen_bits:4096 -quiet -out <私鑰路徑>
    • pki --gen --type rsa --size 4096 --outform pem > <私鑰路徑>
    • 如果私鑰需要加密,則可以在 OpenSSL 的指令內加上 -aes256 來啟用
  • 識別名稱只需要填寫 CN 就足夠了,如果有其它欄位需求在按照相同的格式填入
  • 根憑自簽指令如下:
    • 根憑證一般有效時間都會比較長,下方範例為 3650 天
      OpenSSL```bash openssl req -key <根憑證私鑰路徑> -out <憑證路徑> \ -x509 -days 3650 -subj /C=NO/ ```
      pki```bash pki --self --in <根憑證私鑰路徑> \ --type priv --outform pem --lifetime 3650 \ --dn "CN=域名" > <憑證路徑> ```
  • 簽發憑證指令如下:
    OpenSSLOpenSSL 需要先有 CSR 才能簽憑證,因此分為兩步 ```bash openssl req -new -key <私鑰路徑> -out -config <設定檔路徑> openssl req -x509 -in -out <憑證路徑> -CA <根憑證路徑> -CAkey <根憑證私鑰路徑> ```
    pki```bash pki --pub --in <私鑰路徑> | \ pki --issue --cakey <根憑證私鑰路徑> --cacert <根憑證路徑> \ --dn "CN=域名" --lifetime <有效天數> \ --flag serverAuth --outform pem > <憑證路徑>.pem ```
  • 查看憑證資訊
    • openssl x509 -in <憑證路徑> -text -noout
    • pki --print --in <憑證路徑>

設定檔

  • 下方僅給出本人使用過的範例,更多範例可以參考(官方文件)[https://docs.strongswan.org/docs/5.9/config/IKEv2.html]

  • 配置資料夾預設位於 /etc/swanctl/ 底下

    • 設定檔放在 conf.d/ 底下,需要自行創建檔案
      • 設定檔副檔名為 .conf
      • 可以有多組設定檔,並且所有設定檔都會在開啟時讀取
    • 憑證放在 x509/ 底下
    • 私鑰放在 private/ 底下
      • 憑證和私鑰需要對應才能使用,缺一不可
    • 根憑證放在 x509ca 底下
      • 憑證鏈可以包成一個檔案放入
  • Windows 對於 IKEv2 握手算法有限制,可以參考下方的列表

    可用選項

    3DES 系列 3des-sha1-prfsha1-modp1024 3des-sha256-prfsha256-modp1024 3des-sha384-prfsha384-modp1024

    AES CBC 系列 aes128-sha1-prfsha1-modp1024 aes128-sha256-prfsha256-modp1024 aes128-sha384-prfsha384-modp1024 aes192-sha1-prfsha1-modp1024 aes192-sha256-prfsha256-modp1024 aes192-sha384-prfsha384-modp1024 aes256-sha1-prfsha1-modp1024 aes256-sha256-prfsha256-modp1024 aes256-sha384-prfsha384-modp1024

    AES GCM 系列 aes128gcm128-prfsha1-modp1024 aes128gcm128-prfsha256-modp1024 aes128gcm128-prfsha384-modp1024 aes256gcm128-prfsha1-modp1024 aes256gcm128-prfsha256-modp1024 aes256gcm128-prfsha384-modp1024

範例
  • 下方會給出最基本的設定檔範例,可以按照範例修改
 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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
connections {
    rw-eap-mschapv2 {
        version = 2

        # 是否傳送憑證給終端,一定要開啟,因為這裡使用 PKI 進行身份驗證
        # 可選 never、ifasked、always
		# never:不傳送
		# ifasked:收到憑證請求才傳送
		# always:主動傳送
        # 預設為 ifasked
        send_cert = always

		# 是否傳送憑證請求
		# 預設為 yes
        send_certreq = no

        # 如果資料比較大,是否要進行分割
        # 可選 yes、accept、force、no
        # yes:只要對方同意則資料進行分割
        # accept:本身的資料不分割,但通知對方可以接收資料分割
        # force:所有資料皆分割
        # no:自已不分割,並且告知對方不可分割
        # 預設為 yes
        fragmentation = yes

		# 指定 DHCP 池
        pools = rw_pool

		# IKEv2 加密算法
		# 可以選擇多個加密算法,使用逗號分開
		# 需要注意 Windows 和 strongSwan-network-manager
        proposals = chacha20poly1305-prfsha512-modp4096,aes256gcm128-prfsha256-modp1024,aes256-sha1-prfsha1-modp4096
			  
		# 是否允許多個客戶端
		# 預設為 yes
        mobike = yes

		# 伺服器驗證
        local {
            auth = pubkey
			# 憑證名稱
            certs = test-server.crt
			# 填入連接時的域名或者 IP
            id = vpn.worldofwheat.cloudns.ch
        }

		# 客戶端驗證
        remote {
			# 客戶端驗證方式,可以參考官方文件
            auth = eap-mschapv2
            id = %any
        }
			  
		# IPsec 選項
        children {
            rw-eap-mschapv2 {
                local_ts = 0.0.0.0/0
				# 加密算法
                esp_proposals = chacha20poly1305,aes256-sha1,aes256gcm128
            }
        }
    }
}

# DHCP 池
pools {
    rw_pool {
        addrs = 192.168.10.0/24
    }
}

# 機密資訊
secrets {
	# 處理加密過的私鑰
	private-server {
		file = "private.key"
		secret = XXXXXX
	}
	# 設定一個 EAP 帳號
    eap-Alice {
        id = Alice
        secret = XXXXX
    }
}

指令操作

如何 Debug

第一件事是先學會 IKEv2/IPsec 連線時候的握手協議,我推薦這篇,只有學會了握手協議下面提到的工具才有用。

debug 一定要會的方法:

  • swanctl –log
    • swanctl 提供的指令,可以讓連線過程中的所有封包都紀錄下來
  • 手機版 strongSwan
    • 原生的 UI 沒有辦法提供 log,基本上完全沒辦法 debug
  • Windows 事件檢視器
    • Windows 問題很多而且 debug 相對困難,連線出現問題的時候只會給出沒有任何幫助的訊息。事件檢視器可以給出錯誤碼,可以到網路上查找對應的問題。
Licensed under CC BY-NC-SA 4.0
使用 Hugo 建立
主題 StackJimmy 設計