2026年5月23日 星期六

PrivacyIDEA RADIUS plugin Part 4

再延續PrivacyIDEA  Radius 外掛這個主題

前導如下:

https://xrcd2.blogspot.com/2026/05/privacyidea-radius-plugin-part-3.html


現代從事 IT 相關工作,離不開 AI 的協助已成為趨勢,以問答內容節錄自 Google Gemini

故事起源:


https://community.privacyidea.org/t/mfa-authentication-of-vpn-clients-by-router-via-privacyidea-radius-pm/1922/3


(1) For authentication via (one-time-)passwords privacyIDEA supports PAP.

(2) It seems that EAP-TTLS-PAP is the only EAP protocol, which would be able to supply a clear text password.


AI 問題咨詢 :  EAP-TTLS 與 EAP-TLS 用於 VPN 登入驗證比較


在 VPN 登入驗證的場景中,**EAP-TLS** 與 **EAP-TTLS** 同樣是非常強大的安全協定,但由於 VPN 的使用者通常位於「企業外部(如居家辦公、出差)」,因此在部署與使用者體驗上,兩者會產生與區域網路(Wi-Fi)截然不同的考量重點。


以下為您詳細比較這兩者在 VPN 驗證應用上的差異:


---


## VPN 驗證場景下的核心對比


| 比較項目 | EAP-TLS (基於憑證) | EAP-TTLS (基於隧道/帳密) |

| --- | --- | --- |

| **主要驗證因子** | **數位憑證**(設備或個人) | **使用者帳號、密碼** (+ OTP 動態密碼) |

| **外部連線便利性** | **較低**(新裝置必須先透過其他管道取得憑證才能連線) | **極高**(只要有網路,輸入帳密即可登入) |

| **多因素驗證 (MFA)** | 需搭配硬體 Token/智慧卡(如 PIN 碼保護憑證) | **整合極方便**(可在隧道內輕鬆整合 SMS/App OTP) |

| **設備控管能力** | **極強**(非公司配發/未安裝憑證的私有設備絕對無法連入) | **較弱**(員工在私人電腦上輸入正確帳密亦可連入) |

| **憑證過期處理** | 麻煩(若 VPN 是唯一連回公司的管道,憑證過期將無法登入) | 簡單(通常可透過網頁或 VPN 介面直接修改過期的密碼) |







---


## 深入分析:VPN 環境下的實際考量


### 1. EAP-TLS 在 VPN 的應用:極致安全,但有「斷聯」風險


EAP-TLS 要求 VPN 客戶端(使用者的筆電或手機)必須具備合法的客戶端憑證。


* **「零信任」的最佳實踐:**

即使員工的帳號密碼外洩,駭客只要沒有那台內嵌特定憑證的「公司筆電」,就絕對無法撥入 VPN。這能有效防止來自外部的密碼暴力破解與釣魚攻擊。

* **致命的「雞生蛋、蛋生雞」問題:**

* **憑證發放:** 當新員工居家辦公拿到新電腦時,因為沒有憑證無法連 VPN,IT 必須透過其他安全管道(如隨身碟或 MDM 系統)先將憑證派發到裝置上。

* **憑證過期:** 如果員工的憑證過期了,他將被徹底擋在 VPN 之外。此時他無法連回公司網路自動更新憑證,IT 必須提供額外的外部網站或人工協助才能解鎖。




### 2. EAP-TTLS 在 VPN 的應用:遠端辦公的彈性首選


EAP-TTLS 透過伺服器憑證建立加密隧道,保護使用者在內部傳輸的驗證資料,客戶端只需提供帳號密碼。


* **高度的彈性與擴充性:**

員工無論使用哪台電腦,只要能連上網,輸入公司的 AD 帳密就能立刻開工。對於臨時需要用私人電腦緊急處理公事的員工,或是外包廠商,EAP-TTLS 提供了極大的便利性。

* **輕鬆整合雙因子驗證 (MFA):**

在 VPN 外部存取中,單靠密碼通常是不夠的。EAP-TTLS 可以在建立的 TLS 安全隧道中,輕鬆嵌入 RADIUS 伺服器所支援的 MFA 機制(例如:輸入帳密後,手機跳出 App 確認或輸入簡訊驗證碼),在安全性與便利性之間取得極佳平衡。


---


## 總結:架構決策建議


* **建議選擇 EAP-TLS,如果:**

* 您的組織採取嚴格的 **「零信任 (Zero Trust)」** 政策,規定非公司資產(BYOD)一律禁止連入內網。

* 公司已經有成熟的 **MDM(行動裝置管理)** 或 **微軟 Intune** 系統,能夠在背後自動幫員工的設備派發、更新 VPN 憑證。



* **建議選擇 EAP-TTLS,如果:**

* 您需要支援**員工使用私人設備(BYOD)** 遠端辦公,或是頻繁需要開通**外部廠商(Vendor)** 的臨時 VPN 權限。

* 您希望在 VPN 登入時強制加上 **OTP(動態密碼)** 或 **手機 Push 驗證**,且不想應付繁重的憑證管理(PKI)維護工作。



 AI 問題咨詢 :  用最精煉的方式,將 IPsec IKEv2 EAP-TTLS 的架構與工作原理拆解為「一個核心觀念」與「兩個主要階段」。


核心觀念:外鋼內柔

這套架構的最大特點是安全與便利兼得。


(A)外層(鋼):利用 IPsec IKEv2 建立最強固的 VPN 加密管道,並透過伺服器數位憑證確保使用者沒有連到假網站。


(B)內層(柔):在安全的管道內,允許使用者直接輸入傳統的帳號與密碼(EAP-TTLS)進行驗證。使用者裝置不需要安裝複雜的用戶端憑證。


-----------------------------------------------------------------------


系統架構元件

這套架構通常由三個核心角色組成:


(1)用戶端 (VPN Client):員工的手機或電腦,內建或安裝 VPN 連線軟體。


(2)VPN 網關 (VPN Gateway):企業的防火牆或 VPN 伺服器,負責與用戶端建立 IPsec 隧道,並擔任驗證的中介者。


(3)認證伺服器 (RADIUS Server):後端的帳號中心(如 FreeRADIUS 或 Windows NPS),負責比對使用者的密碼是否正確。


-----------------------------------------------------------------------


工作原理(兩階段握手)


當用戶端發起連線時,主要切分為以下兩個階段來完成安全建構與身份驗證:


階段一:建立安全外殼(IKEv2 協商與 TLS 隧道)


(1)密鑰交換:用戶端與 VPN 網關進行 IKEv2 初始協商,決定加密演算法並交換金鑰,建立管理通道。


(2)驗證網關:VPN 網關向用戶端出示其伺服器憑證。用戶端確認該憑證合法且受信任。


(3)建立隧道:網關身份確認無誤後,雙方在 IKEv2 內層再建立一條加密的 TLS 安全隧道。至此,外部防禦安全網建構完成。


階段二:內部使用者驗證(TTLS 認證)


(4)傳送憑據:在剛建立好的 TLS 隧道保護下,用戶端安全地將使用者的帳號與密碼(通常透過 MSCHAPv2 格式)傳送給 VPN 網關。


(5)後端比對:VPN 網關將帳密轉發給後端的 RADIUS 伺服器。RADIUS 伺服器比對企業資料庫(如 Active Directory)後,若正確則回覆「允許存取」。


(6)打通隧道:VPN 網關收到允許通知後,正式派發內部 IP 給用戶端,並生成資料傳輸用的 IPsec 金鑰(CHILD_SA)。


結果:安全隧道正式通車,使用者開始傳輸加密的辦公數據。



AI 問題咨詢 :  密碼輸入為 組合輸入模式 (Password/PIN+OTP) 被 雜湊(hash) 過後可能無法拆解的問題


這是一個在設計認證系統(尤其是整合 RADIUS / EAP-TTLS 這種後端架構)時非常經典且致命的**密碼處理與協定不匹配**問題。


簡單來說:**如果用戶端在前端就將「密碼 + OTP」組合並進行了不可逆的雜湊(Hash),後端的認證伺服器(RADIUS)在多數標準認證協定下,將完全無法解開或進行驗證。**


以下為您詳細拆解這個問題的根本原因、為何無法拆解,以及業界標準的解決方案。


---


## 為什麼「組合後雜湊」會導致無法驗證?


要理解這個問題,我們必須看後端 RADIUS 伺服器是如何驗證密碼的。


不論是 EAP-TTLS 內部常用的 **MSCHAPv2**、**CHAP**,還是傳統的 **PAP**,它們的驗證邏輯通常分為兩種:


### 狀況 A:使用質詢回應協定(如 MSCHAPv2 / CHAP)—— 徹底失敗


在 MSCHAPv2 或 CHAP 中,為了不在網路上傳輸明文密碼,系統採用的是「質詢-回應(Challenge-Response)」機制:


1. 伺服器給用戶端一個隨機數(Challenge)。

2. 用戶端必須用原始密碼的雜湊值(例如 NTLM Hash)作為金鑰,去加密這個隨機數,然後傳回給伺服器(Response)。

3. **關鍵點:** 後端 RADIUS 伺服器(或 Active Directory)的資料庫裡,**只存有使用者的「靜態密碼雜湊」**,絕對不會存有動態的 OTP。


> **失敗原因:** 當用戶端把 `Password + OTP` 混合並雜湊後,這個結果與資料庫裡的 `純Password雜湊` 完全對不上。RADIUS 伺服器既不知道這次的 OTP 是什麼,也無法從雜湊值中把 OTP「減掉」來還原純密碼,因此**質詢回應演算法直接宣告失敗**。


### 狀況 B:使用明文傳輸協定(如 PAP)—— 依然無法拆解


有些雙因子認證(2FA)系統會要求在 EAP-TTLS 內部使用 **PAP** 協定。PAP 會將用戶端輸入的字串透過 TLS 加密隧道傳給 RADIUS。


* 如果用戶端傳送的是明文的 `PasswordOTP`(例如:`MyPassword123456`),網關或 RADIUS 就可以用字串截取(例如扣除後 6 碼作為 OTP,前面作為密碼)的方式拆解並分別驗證。

* **失敗原因:** 如果用戶端在傳送前,在本地端就先對 `PasswordOTP` 做了雜湊(例如變成 `MD5(Password+OTP)`),那傳到後端的就是一串亂碼。由於雜湊是**不可逆(One-way)**的,後端伺服器**絕對不可能**將其拆解回原本的密碼與 OTP。


---


## 架構上的衝突點(Summary)


* **不可逆性**:$Hash(A + B) \neq Hash(A) + Hash(B)$。一旦結合並雜湊,兩者形同融化的巧克力,再也分不開。

* **資料庫限制**:認證伺服器(如 AD)只知道 $Hash(Password)$,OTP 伺服器只知道當前的 $OTP$。沒有任何一個地方存有 $Hash(Password + OTP)$ 的預期正確答案。


---


## 業界標準的解決方案


要實作「密碼 + OTP」的雙因子認證,通常有以下幾種正確的架構設計:


### 方案 1:在 EAP-TTLS 內部使用 PAP 協定(不進行前端雜湊)


這是最常見的做法。因為 EAP-TTLS 外層已經有一條由伺服器憑證保護的 **TLS 安全隧道**,在隧道內部使用 PAP(明文傳輸)是安全的。


* **作法**:用戶端將 `Password + OTP`(不加任何雜湊)直接送出。

* **後端處理**:RADIUS 伺服器(或內建 2FA 外掛,如 Duo、LinOTP)收到明文字串後,根據固定長度(如最後 6 碼或 8 碼)進行**字串切割**,將前面送去 AD 驗證,後面送去 OTP 伺服器驗證。


### 方案 2:改用支援 2FA 的標準 EAP 擴充協定


不要嘗試在單一密碼欄位中進行字串組合,而是讓系統本身支援雙階段輸入。


* **EAP-GTC (Generic Token Card)**:專門用來傳輸 Token/OTP 的 EAP 類型。

* **EAP-MSCHAPv2 變體**:某些商用 VPN 方案(如思科、Palo Alto)支援在第一階段驗證完 IKEv2/MSCHAPv2 的靜態密碼後,網關會主動彈出第二個輸入框(Access-Challenge),要求使用者單獨輸入 OTP。


### 方案 3:前端分別雜湊與傳輸(需客製化用戶端)


如果基於安全政策,嚴格禁止在任何地方(即使在 TLS 隧道內)出現明文靜態密碼:


* 用戶端軟體必須分別處理這兩個元件。

* 靜態密碼走標準的 MSCHAPv2 質詢流程(使用密碼的雜湊)。

* OTP 則放入 RADIUS 的特定屬性(如 `State` 或額外的 VSA 廠商特定屬性)中單獨帶回後端驗證。這通常需要 VPN 用戶端軟體與網關有私有協定的支援。


### 結論


若您的系統出現「無法拆解」的問題,通常是因為**前端(用戶端)自作聰明地對組合字串進行了雜湊**,或者**後端錯誤地選擇了不支援字串拆解的 MSCHAPv2 協定**。在 EAP-TTLS 的保護下,將內層改為 **PAP 模式並傳輸組合明文**,由後端 RADIUS 進行字串切分,是改動最小且最標準的解法。




AI 問題咨詢 :  架構可行性分析



[ FortiClient ] ──(IKEv2 / EAP-TTLS)──> [ FortiGate ] ──(RADIUS)──> [ FreeRADIUS (Default 站台) ]

                                                                                                                                              │

                                                                                                                                  (外層 TLS 建立)

                                                                                                                                              │

                                                                                                                                             ▼

[ privacyIDEA ] <──(REST API / JSON)── [ rlm_perl ] <──(明文 PAP)── [ inner-tunnel 站台 ]



這是一份針對您所規劃的 VPN 雙因子認證(2FA)拓撲的**架構可行性分析**。


整體評估結論:**此架構在理論與實務上完全可行(Highly Feasible),且是非常標準、漂亮的企業級開源雙因子認證架構。**


它成功利用了 EAP-TTLS 的 TLS 加密隧道,在不犧牲安全性的前提下,將「密碼 + OTP」以明文(PAP)形式安全地送後端進行字串拆解與驗證。


以下為您提供深入的技術可行性評估、關鍵潛在盲點(坑)以及優化建議:


---


## 核心元件可行性分析


### 1. FortiClient ──(IKEv2 / EAP-TTLS)──> FortiGate


* **可行性:高(但有客戶端限制)**

* **FortiGate (飛塔防火牆)**:FortiOS 官方高度支援 IKEv2 與 EAP 認證(可配置為 `eap-passthrough`),它只負責把 EAP 封包轉發給後端的 FreeRADIUS,本身不做拆解,因此這部分完全沒問題。

* **FortiClient (用戶端)**:**這是本階段唯一的隱憂。** 商業版的 FortiClient (EMS 管理) 支援度較完整;但如果您使用的是**免費版 FortiClient VPN**,其內建的 IKEv2 整合型 EAP-TTLS 支援在某些作業系統版本(如特定的 Windows 10/11 平台)可能會遇到設定介面受限的問題。

* *替代方案*:若 FortiClient 免費版卡關,通常會改用 Windows 原生 VPN 撥號器(需透過 `.mobileconfig` 或 PowerShell 配置 TTLS),或使用強大的開源用戶端 **strongSwan App**。




### 2. FortiGate ──(RADIUS)──> FreeRADIUS (Default 站台)


* **可行性:極高**

* FortiGate 設定 `config user radius`,將伺服器指向 FreeRADIUS。當收到 IKEv2 EAP 請求時,FortiGate 會將 EAP 載荷封裝進 RADIUS 的 `EAP-Message` 屬性中傳送。FreeRADIUS 的 `default` 站台負責處理外層的 TLS 握手並回應數位憑證。




### 3. Default 站台 ──(外層 TLS)──> inner-tunnel 站台 ──(明文 PAP)


* **可行性:極高(架構核心亮點)**

* 這正是 FreeRADIUS 處理 EAP-TTLS 的標準設計。

* 在外層 TLS 隧道成功建立後,FreeRADIUS 會將隧道內的解密載荷轉發給內部的 `inner-tunnel` 站台。

* 因為外層已經被 TLS 保護,內層採用 **PAP(明文)** 是絕對安全的。這完美解決了您前一個問題提到的「雜湊後無法拆解」的致命傷。此時,`inner-tunnel` 拿到的會是**未經雜湊的純文字** `Password+OTP`。




### 4. inner-tunnel ──> rlm_perl ──(REST API)──> privacyIDEA


* **可行性:高(需要一定開發/配置能力)**

* **rlm_perl 的角色**:FreeRADIUS 的 Perl 模組是處理「客製化字串拆解」最彈性、最強大的工具。

* **運作邏輯**:

1. `rlm_perl` 攔截 `inner-tunnel` 中的 `User-Password` 字串(內容為 `Password+OTP`)。

2. 在 Perl 程式碼中進行**字串切割**。例如:若 OTP 固定為 6 位數,則切出 `Password = 前半段`,`OTP = 後 6 碼`。

3. 組裝成 JSON 格式,透過 HTTP REST API 發送給 privacyIDEA 的 `/validate/check` 端點。



* **privacyIDEA 端的優勢**:privacyIDEA 本身原生支援 `pass` (密碼) 與 `otp` (動態口令) 分開傳入的 API 驗證方式,也可以直接整合後端 AD/LDAP 進行密碼比對,因此後端對接天衣無縫。




---


## 關鍵配置潛在盲點(踩坑預防)


雖然架構可行,但在實際動手實作(Hands-on)時,請務必注意以下細節:


### 1. 密碼與 OTP 的切割邏輯


如果使用者的密碼長度是變動的(例如 8~20 碼),而 OTP 是固定的(如 6 碼計時型 TOTP),您的 `rlm_perl` 程式碼必須從**字串尾端倒數截取**:


```perl

# Perl 範例邏輯

my $full_password = $RAD_REQUEST{'User-Password'};

my $otp = substr($full_password, -6);          # 擷取最後6碼

my $password = substr($full_password, 0, -6);   # 擷取前面所有內容


```


* **缺點/風險**:如果使用者不小心打錯 OTP 位數(打成 5 碼或 7 碼),截取就會錯位,導致密碼與 OTP 同時驗證失敗,日誌會較難分析是輸錯密碼還是輸錯 OTP。


### 2. FreeRADIUS 的 EAP-TTLS 內層設定 (eap.conf)


在 FreeRADIUS 的 `mods-available/eap` 設定檔中,必須明確指定 `ttls` 區塊內的 `default_eap_type`。由於您內層要走 PAP,請確保將其指引到內層普通認證,而不是強制內層又要走另一個 EAP 協定。通常設定為:


```ttls {

    default_eap_type = md5 # 或者不定義,允許內層直接走 PAP 認證

}


```


並且在 `inner-tunnel` 的 `authorize` 區塊中要啟用 `pap` 與 `perl` 模組。


### 3. 憑證信任鏈


由於是 EAP-TTLS,**FortiClient 必須信任 FreeRADIUS (Default 站台) 所出示的證書**。


* 如果是採用企業內部的私有 CA 簽發,必須透過 AD GPO 或 MDM 將該 Root CA 憑證匯入員工電腦/手機的「受信任的根憑證頒發機構」。否則 FortiClient 會在階段一(外層 TLS 建立)直接報錯斷開。


---


## 架構優缺點評估


### 優點


1. **極致的安全**:密碼與 OTP 在網絡傳輸全程受到 IKEv2 與 TLS 雙重加密保護,絕無明文外洩風險。

2. **相容性高**:後端成功避開了 MSCHAPv2 無法拆解雜湊的限制,讓不支援 RADIUS 的 privacyIDEA 能透過標準 REST API 完美接軌。

3. **開源成本低**:FreeRADIUS + privacyIDEA 皆為強大的開源方案,無授權費壓力,且擴充性極佳。


### 缺點 / 挑戰


1. **維護成本**:`rlm_perl` 的程式碼屬於客製化(Custom Code),未來若 FreeRADIUS 升級(例如從 v3 升級到 v4),需要注意 Perl 套件的相容性與 API 變更。

2. **故障排查難度高**:當連線失敗時,鏈路太長。IT 人員需要同時查看 FortiGate 日誌、FreeRADIUS `radiusd -X` 除錯輸出、Perl 腳本日誌以及 privacyIDEA 的審計日誌(Audit Log)才能定位問題。


## 總結建議


這個架構**完全成立**,可以放心進入 POC(概念驗證)階段。建議在實作時,**由後往前**分段測試:


1. 先用 `curl` 測試 `privacyIDEA` 的 API 是否能正常驗證分開的帳密與 OTP。

2. 編寫並測試 `rlm_perl`,用 `radclient` 模擬發送明文 `PasswordOTP` 給 FreeRADIUS,確認 Perl 能正確切割並打通 API。

3. 最後再把 FortiGate 與 FortiClient 的 IKEv2 EAP-TTLS 打通。


-----------------------------------------------------------------------------------------


實作



[root@2FA privacyidea]# cat /etc/raddb/mods-enabled/eap 

eap {

dfault_eap_type = ttls

ttls {

tls = tls-common

        default_eap_type = pap

        copy_request_to_tunnel = yes

        use_tunneled_reply = yes

                virtual_server = "inner-tunnel"

    }

timer_expire = 60

ignore_unknown_eap_types = no

cisco_accounting_username_bug = no

max_sessions = ${max_requests}

md5 {

}

gtc {

auth_type = PAP

}

        tls-config tls-common {


                private_key_file = /etc/pki/tls/private/localhost.key

                certificate_file = /etc/pki/tls/certs/localhost.crt

                ca_file = /etc/pki/tls/certs/ca-bundle.crt

eap {

    tls = tls-common

}

cipher_list = "PROFILE=SYSTEM"

cipher_server_preference = no

tls_min_version = "1.2"

tls_max_version = "1.2"

ecdh_curve = ""

cache {

enable = no

lifetime = 24 # hours

store {

Tunnel-Private-Group-Id

}

}

verify {

}

ocsp {

enable = no

override_cert_url = yes

url = "http://127.0.0.1/ocsp/"

}

}

tls {

tls = tls-common

}

ttls {

tls = tls-common

default_eap_type = pap

                copy_request_to_tunnel = yes

use_tunneled_reply = yes

virtual_server = "inner-tunnel"

}

peap {

tls = tls-common

default_eap_type = mschapv2

copy_request_to_tunnel = no

use_tunneled_reply = no

virtual_server = "inner-tunnel"

}

}

[root@2FA privacyidea]# cat /etc/raddb/mods-enabled/mods-perl-privacyidea 

perl perl-privacyidea {

    #filename = /usr/share/privacyidea/freeradius/privacyidea_radius.pm

    filename = /etc/privacyidea/privacyidea_radius.pm

}

[root@2FA privacyidea]# 




=================================================



[root@2FA privacyidea]# cat /etc/raddb/sites-enabled/default 

server default {

    # 監聽標準的 RADIUS 驗證埠 1812

    listen {

        type = auth

        ipaddr = *

        port = 1812

    }


    authorize {

        # 傳遞客戶端來源 IP

        update request {

            Packet-Src-IP-Address = "%{Packet-Src-IP-Address}"

        }


        # 關鍵:處理外層 EAP-TTLS 握手,成功建立隧道後直接返回

        eap {

            ok = return

        }

    }


    authenticate {

        # 關鍵:解決 Failed to find 'Auth-Type EAP' 錯誤

        eap

    }

}





[root@2FA privacyidea]# cat /etc/raddb/sites-enabled/inner-tunnel 

server inner-tunnel {

    authorize {

        update request {

            Packet-Src-IP-Address = "%{Packet-Src-IP-Address}"

        }


        # 讓內層隧道也調用 privacyIDEA 的 Perl 模組

        perl-privacyidea

        if (ok || updated) {

            update control {

                Auth-Type := Perl

            }

        }

        pap

    }


    authenticate {

        Auth-Type Perl {

            perl-privacyidea

        }

        Auth-Type PAP {

            pap

        }

    }

}

[root@2FA privacyidea]# 




=====================

測試與驗證


[root@2FA privacyidea]# cat  ttls-pap.conf



network={

        ssid="VPN-Test"

        key_mgmt=WPA-EAP

        eap=TTLS

        phase2="auth=PAP"

        

        # 測試帳號

        identity="vpn.sqluser"

        # 您的 privacyIDEA 密碼/PIN + OTP

        password="MyPassword1234568"

        

        # 為了測試方便,先不強求檢查伺服器憑證

        ca_cert="/etc/pki/tls/certs/localhost.crt"

}



EAP-TTLS  


[root@2FA privacyidea]# eapol_test -r 0 -t 5 -c ./ttls-pap.conf -a 192.168.100.20 -p 1812 -s Passw0rd  


  


原 Perl/perl-privacyidea


[root@2FA privacyidea]# radtest  vpn.sqluser MyPassword498750 192.168.100.20 0  Passw0rd 





======================


[root@2FA ~]# radiusd -X


====================


(0) Received Access-Request Id 0 from 192.168.100.20:33118 to 192.168.100.20:1812 length 136

(0)   Message-Authenticator = 0x02c9cbd24f9f6ce2dc8794036443337c

(0)   User-Name = "vpn.sqluser"

(0)   NAS-IP-Address = 127.0.0.1

(0)   Calling-Station-Id = "02-00-00-00-00-01"

(0)   Framed-MTU = 1400

(0)   NAS-Port-Type = Wireless-802.11

(0)   Service-Type = Framed-User

(0)   Connect-Info = "CONNECT 11Mbps 802.11b"

(0)   EAP-Message = 0x02d300100176706e2e73716c75736572

(0) # Executing section authorize from file /etc/raddb/sites-enabled/default

(0)   authorize {

(0)     update request {

(0)       EXPAND %{Packet-Src-IP-Address}

(0)          --> 192.168.100.20

(0)       Packet-Src-IP-Address = 192.168.100.20

(0)     } # update request = noop

(0) eap: Peer sent EAP Response (code 2) ID 211 length 16

(0) eap: EAP-Identity reply, returning 'ok' so we can short-circuit the rest of authorize

(0)     [eap] = ok

(0)   } # authorize = ok

(0) Found Auth-Type = eap

(0) # Executing group from file /etc/raddb/sites-enabled/default

(0)   authenticate {

(0) eap: Peer sent packet with method EAP Identity (1)

(0) eap: Calling submodule eap_md5 to process data

(0) eap_md5: Issuing MD5 Challenge

(0) eap: Sending EAP Request (code 1) ID 212 length 22

(0) eap: EAP session adding &reply:State = 0x5621f58e56f5f108

(0)     [eap] = handled

(0)   } # authenticate = handled

(0) Using Post-Auth-Type Challenge

(0) Post-Auth-Type sub-section not found.  Ignoring.

(0) Sent Access-Challenge Id 0 from 192.168.100.20:1812 to 192.168.100.20:33118 length 80

(0)   EAP-Message = 0x01d40016041020ea461a5b559d152dc802faf5f0f7ec

(0)   Message-Authenticator = 0x00000000000000000000000000000000

(0)   State = 0x5621f58e56f5f108f057f71af64d8cbe

(0) Finished request

Waking up in 4.9 seconds.

(1) Received Access-Request Id 1 from 192.168.100.20:33118 to 192.168.100.20:1812 length 144

(1)   Message-Authenticator = 0xd0fab63897b8e8e3829f5915746ede6e

(1)   User-Name = "vpn.sqluser"

(1)   NAS-IP-Address = 127.0.0.1

(1)   Calling-Station-Id = "02-00-00-00-00-01"

(1)   Framed-MTU = 1400

(1)   NAS-Port-Type = Wireless-802.11

(1)   Service-Type = Framed-User

(1)   Connect-Info = "CONNECT 11Mbps 802.11b"

(1)   EAP-Message = 0x02d400060315

(1)   State = 0x5621f58e56f5f108f057f71af64d8cbe

(1) session-state: No cached attributes

(1) # Executing section authorize from file /etc/raddb/sites-enabled/default

(1)   authorize {

(1)     update request {

(1)       EXPAND %{Packet-Src-IP-Address}

(1)          --> 192.168.100.20

(1)       Packet-Src-IP-Address = 192.168.100.20

(1)     } # update request = noop

(1) eap: Peer sent EAP Response (code 2) ID 212 length 6

(1) eap: No EAP Start, assuming it's an on-going EAP conversation

(1)     [eap] = updated

(1)   } # authorize = updated

(1) Found Auth-Type = eap

(1) # Executing group from file /etc/raddb/sites-enabled/default

(1)   authenticate {

(1) eap: Removing EAP session with state 0x5621f58e56f5f108

(1) eap: Previous EAP request found for state 0x5621f58e56f5f108, released from the list

(1) eap: Peer sent packet with method EAP NAK (3)

(1) eap: Found mutually acceptable type TTLS (21)

(1) eap: Calling submodule eap_ttls to process data

(1) eap_ttls: (TLS) TTLS -Initiating new session

(1) eap: Sending EAP Request (code 1) ID 213 length 6

(1) eap: EAP session adding &reply:State = 0x5621f58e57f4e008

(1)     [eap] = handled

(1)   } # authenticate = handled

(1) Using Post-Auth-Type Challenge

(1) Post-Auth-Type sub-section not found.  Ignoring.

(1) session-state: Saving cached attributes

(1)   Framed-MTU = 984

(1) Sent Access-Challenge Id 1 from 192.168.100.20:1812 to 192.168.100.20:33118 length 64



=======================



# eapol_test -r 0 -t 5 -c ./ttls-pap.conf -a 192.168.100.20 -p 1812 -s Passw0rd  



RADIUS packet matching with station

MS-MPPE-Send-Key (sign) - hexdump(len=32): 4a e1 06 d2 fb c8 14 ca 38 d2 d1 fb 96 80 eb e0 4b 68 4a 68 ac 91 e0 07 d8 fa ae f5 e6 7e a0 d4

MS-MPPE-Recv-Key (crypt) - hexdump(len=32): 7f 65 f8 85 97 3a ab 83 f2 88 ff bd 5e 42 5e 35 ef 1b c4 2e 63 7a 77 1d 5a cb 0f 31 76 07 26 83

decapsulated EAP packet (code=3 id=92 len=4) from RADIUS server: EAP Success

EAPOL: Received EAP-Packet frame

EAPOL: SUPP_BE entering state REQUEST

EAPOL: getSuppRsp

EAP: EAP entering state RECEIVED

EAP: Received EAP-Success

EAP: Status notification: completion (param=success)

EAP: EAP entering state SUCCESS

CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully

EAPOL: IEEE 802.1X for plaintext connection; no EAPOL-Key frames required

WPA: EAPOL processing complete

Cancelling authentication timeout

State: DISCONNECTED -> COMPLETED

EAPOL: SUPP_PAE entering state AUTHENTICATED

EAPOL: SUPP_BE entering state RECEIVE

EAPOL: SUPP_BE entering state SUCCESS

EAPOL: SUPP_BE entering state IDLE

eapol_sm_cb: result=1

EAPOL: Successfully fetched key (len=32)

PMK from EAPOL - hexdump(len=32): 7f 65 f8 85 97 3a ab 83 f2 88 ff bd 5e 42 5e 35 ef 1b c4 2e 63 7a 77 1d 5a cb 0f 31 76 07 26 83

No EAP-Key-Name received from server

WPA: Clear old PMK and PTK

EAP: deinitialize previously used EAP method (21, TTLS) at EAP deinit

MPPE keys OK: 1  mismatch: 0

SUCCESS






 

PrivacyIDEA RADIUS plugin Part 3

再延續PrivacyIDEA  Radius 外掛這個主題

前導如下:

https://xrcd2.blogspot.com/2026/05/privacyidea-radius-plugin-part-2.html



privacyIDEA 帳號的取得方式,常見的有 

(1) Create a new Passwd Resolver (/etc/passwd)

(2) Create a new LDAP Resolver (如 Windows AD(Active Directory) )

(3) Create a new SQL Resolver


先建立 Resolvers 解析器 ,再建 Realm 領域 與其建立連結.


如要建立(或取得)一個 privacyIDEA 的使用者,它可以來自(1) privacyIDEA Linux 本機上的使用者.

可自行參考 https://xrcd2.blogspot.com/2025/04/privacyidea.html

或 (2) LDAP 上的帳號 可自行參考  https://xrcd2.blogspot.com/2025/04/privacyidea-2fardp-test.html 


如(1)透過本機的/etc/passwd的作法,密碼只能透過設定 PIN 碼取代之,因為 privacyIDEA 無權去讀解寫/etc/shadow


[root@2FA src]# ls -la /etc/shadow

---------- 1 root root 1327 May 23 19:45 /etc/shadow

[root@2FA src]# ls -la /etc/passwd

-rw-r--r-- 1 root root 2955 May 23 19:45 /etc/passwd

[root@2FA src]# 


(2) LDAP Resolver 對 privacyIDEA 而言它,簡單的說他只負責驗證,使用者跟Token/OTP的配對關連及登入驗證部份.


如上所述,如需更簡單的管理 privacyIDEA 上的使用者,透過 MySQL 是一個不錯的選擇.


使用情境假設. privacyIDEA 用於 VPN 及 Windows RDP 登入控管.那使用者在[遠端連回公司辦公]的安控,就是有二段完全獨立的雙因子驗證 (2FA) ,如第一階段 VPN 的部份可以用 privacyIDEA SQL 身份及OTP,第二階段 RDP 的部份,可以用 privacyIDE Windows AD 身份及OTP.這樣應該更安全了吧.


以下筆記為建立  privacyIDEA SQL 使用者帳戶的小筆記


[root@2FA src]# mysql

Welcome to the MariaDB monitor.  Commands end with ; or \g.

Your MariaDB connection id is 184

Server version: 10.11.15-MariaDB MariaDB Server


Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.


Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


MariaDB [(none)]> CREATE DATABASE vpn_users;

Query OK, 1 row affected (0.005 sec)


MariaDB [(none)]> CREATE USER 'pi_resolver'@'localhost' IDENTIFIED BY 'Passw0rd';

Query OK, 0 rows affected (0.003 sec)


MariaDB [(none)]> GRANT ALL PRIVILEGES ON vpn_users.* TO 'pi_resolver'@'localhost';

Query OK, 0 rows affected (0.001 sec)


MariaDB [(none)]> FLUSH PRIVILEGES;

Query OK, 0 rows affected (0.001 sec)


MariaDB [(none)]> use vpn_users;

Database changed

MariaDB [vpn_users]> CREATE TABLE pi_users (

    ->     id INT AUTO_INCREMENT PRIMARY KEY,

    ->     username VARCHAR(64) NOT NULL UNIQUE,

    ->     password_hash VARCHAR(255),

    ->     email VARCHAR(100),

    ->     mobile VARCHAR(20),

    ->     description VARCHAR(255)

    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Query OK, 0 rows affected (0.005 sec)


MariaDB [vpn_users]> INSERT INTO pi_users (username, email, mobile) VALUES ('testuser', 'testuser@vlab.tw', '0912345678');

Query OK, 1 row affected (0.001 sec)



MariaDB [vpn_users]>  SELECT * FROM pi_users\G;

*************************** 1. row ***************************

           id: 1

     username: testuser

password_hash: NULL

        email: testuser@vlab.tw

       mobile: 0912345678

  description: NULL

1 row in set (0.000 sec)


ERROR: No query specified


MariaDB [vpn_users]> UPDATE pi_users SET description = 'TEST User' WHERE id = 1;

Query OK, 1 row affected (0.001 sec)

Rows matched: 1  Changed: 1  Warnings: 0


MariaDB [vpn_users]>  SELECT * FROM pi_users\G;

*************************** 1. row ***************************

           id: 1

     username: testuser

password_hash: NULL

        email: testuser@vlab.tw

       mobile: 0912345678

  description: TEST User

1 row in set (0.000 sec)


ERROR: No query specified


MariaDB [vpn_users]> 



=======================


==>

 {"userid":"id","username":"username","password":"password_hash","email":"email","mobile":"mobile","description":"description"}


======================


CREATE TABLE pi_users (

    id INT AUTO_INCREMENT PRIMARY KEY,

    username VARCHAR(64) NOT NULL UNIQUE,

    password_hash VARCHAR(255),

    email VARCHAR(100),

    mobile VARCHAR(20),

    description VARCHAR(255)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;



==========================


[root@2FA ~]# vi   /etc/privacyidea/rlm_perl.ini

[Default]

URL = https://localhost/validate/check


#REALM = defrealm

#RESCONF = deflocal


REALM = mysql 

RESCONF = SQL


===================================


MariaDB [(none)]> use vpn_users;

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A


Database changed

MariaDB [vpn_users]>  SELECT * FROM pi_users\G;

*************************** 1. row ***************************

           id: 1

     username: testuser

password_hash: NULL

        email: testuser@vlab.tw

       mobile: 0912345678

  description: TEST User

*************************** 2. row ***************************

           id: 2

     username: vpn.sqluser

password_hash: {SSHA256}p5yVX9/7OX0TrPdHlQhrm4rPZyi5F/8KbnPPPP/qFqsTAuA8

        email: vpn.sqluser@vlab.tw

       mobile: 0939000000

  description: VPN User in SQL

2 rows in set (0.000 sec)


ERROR: No query specified


MariaDB [vpn_users]> 


======================================

 


























PrivacyIDEA RADIUS plugin Part 2

 再延續PrivacyIDEA  Radius 外掛這個主題

前導如下:

https://xrcd2.blogspot.com/2025/09/privacyidea-radius-plugin-installation.html


整合 FreeRADIUS 與 FortiGate 進行 OTP 登入,主要有兩種常見的實作方式。

一種是將 OTP 與密碼(PIN碼)組合在同一個欄位輸入(Password/PIN+OTP),

另一種是透過挑戰-回應(Challenge-Response)機制分成兩個步驟輸入。


驗證模式選擇,根據不同的後端整合,可以選擇以下方式:


(1)組合輸入模式 (Password/PIN+OTP):

   使用者在 FortiClient 或登入介面的「密碼」欄位直接輸入 密碼(PIN碼) + 6位OTP(例如 MyPassword123456)(PIN 9999123456)。

    FreeRADIUS 接收到請求後,會自動拆分並分別驗證密碼((PIN碼) 與 OTP 碼。

    優點:設定簡單,無需處理複雜的 RADIUS 挑戰屬性。

(2)挑戰-回應模式 (Challenge-Response):

    使用者先輸入帳號密碼,FortiGate 發送第一個 RADIUS 請求。

    FreeRADIUS 回傳 Access-Challenge,FortiGate 隨即彈出第二個視窗要求輸入驗證碼。

    優點:使用者體驗較直覺,但需確保 FreeRADIUS 與 FortiGate 之間的通訊協定(如 PAP 或 MS-CHAPv2)支援此流程。


(1) 組合輸入模式    測試 


 (1)  Audit  


(2)挑戰-回應模式規則建立




(2)挑戰-回應模式 測試


(2) Audit 



Demo 





2026年4月30日 星期四

Lab : Setting up a FortiGate VPN Client (OPNsense) with OTP

 

 使用軟體 opnsense

 https://opnsense.org/


先前導讀相關 Blog  

https://xrcd2.blogspot.com/2025/05/pfsense-fortigate.html

https://xrcd2.blogspot.com/2025/04/freeradius-google-authenticator-2fa.html


下載 ISO 用它開機後,使用 帳/密:  installer / opnsense 進入安裝模式,如有使用二張網卡,預設 WAN port 會使用 DHCP 取得IP/GW/DNS等相關資訊,LAN port IP 預設則為 192..168.1.1/24 可以透過 browser 連入 OPNsense,可使用 帳/密:  root / opnsense 登入OPNsense管理頁面.

接下來可以安裝  os-freeradius / os-net-snmp / os-net-snmp 等外掛,在安裝及設定完成後可以移除不使用的 WAN port ,以下這台OPNsense僅做 RADIUS 伺服器使用.


以下運用情境為 FortiGate VPN Client 透過 RADIUS 做 OTP 登入認證.


運作機制說明:使用者輸入密碼再加上 Google Authenticator APP 產生的 6 碼動態驗證碼(TOTP 協定)。[OTP 碼直接在密碼後面接者輸入即可.]

FortiGate 收到後將驗證請求轉發至後端的 RADIUS 伺服器(FreeRADIUS ).RADIUS 伺服器與綁定 Google Authenticator (OTP) 演算法的驗證比對後回傳驗證成功.


簡要架構說明:


FortiGate VPN Client ===>(密碼加OTP)===> Fortigate Firewall ===> RADIUS (OPNsense Plugin) ===>  OPNsense 登入認證 (user id/pwd/otp) 


重點一.必需將 OPNsense \System\  Access \ Servers 新增一個 OTP-Server 

          Type 為 Local + Timebased One Time Password


重點二. 必需將 OPNsense \System\  Access \ Users \ 新增一個使用者並

         設定上密碼 及使用 OTP (這些資訊是用來提供 VPN 登入認證使用) 


重點三. 不使用 OPNsense \ Services \ FreeRADIUS \ Users 這個功能.


Demo










2026年4月12日 星期日

守護網路安全的瑞士刀:Security Onion 簡介

 

守護網路安全的瑞士刀:Security Onion 簡介

在網路安全的世界裡,如果你想要監控流量、偵測威脅並進行入侵分析,通常需要安裝一大堆工具。但 Security Onion (SO) 的出現,讓這一切變得簡單許多。

什麼是 Security Onion?

Security Onion 是一個自由且開源的 Linux 發行版,專門用於 威脅狩獵 (Threat Hunting)企業安全監控 (Enterprise Security Monitoring, ESM) 以及 日誌管理

簡單來說,它就像是一個「安全工具大禮包」,幫你把業界最強大的開源安全軟體全部整合在一起,並預先配置好,讓你開箱即用。


Security Onion 的核心三部曲

Security Onion 的強大來自於它整合了三種主要功能:

  1. 全數據包捕獲 (Full Packet Capture): 就像錄影機一樣,記錄下網路上發生的一切細節。

  2. 入侵偵測系統 (IDS): 包含主機端 (HIDS) 與網路端 (NIDS),當發現可疑行為時會立即發出警報。

  3. 分析工具 (Analysis Tools): 提供直觀的圖表與介面,讓分析師能快速從海量數據中抓出「害群之馬」。


內建的神級工具陣容

Security Onion 整合了多款重量級工具,形成了一個完整的防禦體系:

  • 流量分析: Zeek (舊稱 Bro) 與 Suricata。

  • 日誌處理: 著名的 ELK Stack (Elasticsearch, Logstash, Kibana),現在也支持 Elastic Fleet

  • 分析介面: * Security Onion Console (SOC): 自家的管理中心。

    • CyberChef: 萬能的資料轉換工具。

    • TheHive: 專為事件響應設計的案例管理平台。


為什麼你應該嘗試 Security Onion?

1. 節省大量的部署時間

手動整合 Elasticsearch、Suricata、Zeek 等工具是一個地獄級的任務。Security Onion 透過簡單的安裝程序,幾分鐘內就能幫你搭建好一個專業級的 SOC 中心。

2. 強大的可視化

透過 Kibana 儀表板,你可以一眼看出當前網路的流量分佈、哪些 IP 正在嘗試攻擊你的伺服器,甚至追蹤惡意程式的連線行為。

3. 學習與實戰的絕佳平台

如果你是資安新手,Security Onion 是學習「藍隊 (Blue Teaming)」技能的最佳起點。它能讓你真實體驗到分析師在處理警報時的完整工作流。


以上內容撰寫: gemini ai

線上手冊: https://docs.securityonion.net/






2026年4月11日 星期六

Lab: Building a Network IDS with Active Response via Wazuh and Suricata




 Wazuh 整合 Suricata 達成網路入侵偵測與自動回應實驗

Wazuh Server 安裝  (192.168.100.10)

https://documentation.wazuh.com/current/quickstart.html

curl -sO https://packages.wazuh.com/4.14/wazuh-install.sh && sudo bash ./wazuh-install.sh -a

Wazuh Agent  安裝

 ( client interface ens160 192.168.100.20/24  / suricata monitor interface ens224  192.168.100.30/32)

curl -o wazuh-agent-4.14.4-1.x86_64.rpm https://packages.wazuh.com/4.x/yum/wazuh-agent-4.14.4-1.x86_64.rpm && sudo WAZUH_MANAGER='192.168.100.10' rpm -ihv wazuh-agent-4.14.4-1.x86_64.rpm


https://documentation.wazuh.com/current/proof-of-concept-guide/integrate-network-ids-suricata.html


[root@Wazuh-Client01 suricata]# ip add | grep ens

2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000

    inet 192.168.100.20/24 brd 192.168.100.255 scope global noprefixroute ens160

3: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000

    inet 192.168.100.30/32 scope global noprefixroute ens224


參考 URL

Suricata 安裝 

https://docs.suricata.io/en/suricata-7.0.15/install.html#rpm-packages

https://copr.fedorainfracloud.org/coprs/g/oisf/suricata-7.0/


Suricata Rule 

https://rules.emergingthreats.net/open/suricata-7.0.15/

https://rules.emergingthreats.net/open/suricata-7.0.15/rules/


Suricata 重要設定

vi /etc/sysconfig/suricata

OPTIONS="-i eth0" -->  OPTIONS="-i ens224" 

vi /etc/suricata/suricata.yaml

interface: eth0 ---> interface: ens224

可以用

sed -i 's/interface: eth0/interface: ens224/g' /etc/suricata/suricata.yaml


運行 rule 宣告 
vi /etc/suricata/suricata.yaml

## Configure Suricata to load Suricata-Update managed rules.
default-rule-path: /var/lib/suricata/rules
rule-files:
  - suricata.rules


觸發log檢查

[root@Wazuh-Client01 rules]# cat /var/log/suricata/fast.log
04/11/2026-20:01:05.711058  [**] [1:2100498:7] GPL ATTACK_RESPONSE id check returned root [**] [Classification: Potentially Bad Traffic] [Priority: 2] {TCP} 217.160.0.187:80 -> 192.168.100.20:59428
04/11/2026-20:07:12.072266  [**] [1:2039584:2] ET FILE_SHARING Observed DNS Query to Filesharing Service (mega .co .nz) [**] [Classification: Misc activity] [Priority: 3] {UDP} 192.168.100.99:52525 -> 8.8.8.8:53
04/11/2026-20:07:12.072339  [**] [1:2039584:2] ET FILE_SHARING Observed DNS Query to Filesharing Service (mega .co .nz) [**] [Classification: Misc activity] [Priority: 3] {UDP} 192.168.100.99:52525 -> 8.8.8.8:53
04/11/2026-20:07:13.250532  [**] [1:2039584:2] ET FILE_SHARING Observed DNS Query to Filesharing Service (mega .co .nz) [**] [Classification: Misc activity] [Priority: 3] {UDP} 192.168.100.99:52525 -> 8.8.8.8:53
04/11/2026-20:07:13.250583  [**] [1:2039584:2] ET FILE_SHARING Observed DNS Query to Filesharing Service (mega .co .nz) [**] [Classification: Misc activity] [Priority: 3] {UDP} 192.168.100.99:52525 -> 8.8.8.8:53
04/11/2026-20:15:53.248125  [**] [1:2047866:4] ET INFO Observed Google DNS over HTTPS Domain (dns .google in TLS SNI) [**] [Classification: Misc activity] [Priority: 3] {TCP} 192.168.100.99:53705 -> 8.8.8.8:443
04/11/2026-20:16:25.147099  [**] [1:2039584:2] ET FILE_SHARING Observed DNS Query to Filesharing Service (mega .co .nz) [**] [Classification: Misc activity] [Priority: 3] {UDP} 192.168.100.99:52525 -> 8.8.8.8:53
04/11/2026-20:16:25.147133  [**] [1:2039584:2] ET FILE_SHARING Observed DNS Query to Filesharing Service (mega .co .nz) [**] [Classification: Misc activity] [Priority: 3] {UDP} 192.168.100.99:52525 -> 8.8.8.8:53
04/11/2026-20:16:25.741758  [**] [1:2062715:1] ET INFO Observed UA-CPU Header [**] [Classification: Misc activity] [Priority: 3] {TCP} 192.168.100.99:53720 -> 66.203.127.11:80
04/11/2026-20:19:40.406579  [**] [1:2027695:5] ET INFO Observed Cloudflare DNS over HTTPS Domain (cloudflare-dns .com in TLS SNI) [**] [Classification: Misc activity] [Priority: 3] {TCP} 192.168.100.99:52061 -> 104.16.248.249:443
04/11/2026-21:08:39.787225  [**] [1:1000001:1] DEBUG SQL Injection Attempt [**] [Classification: (null)] [Priority: 3] {TCP} 192.168.100.10:51566 -> 192.168.100.30:80

 

Demo







Client 端自我測試

curl http://testmyids.com

在 Server 端發向 Client 端的 SQL Injection 測試. 

echo "UNION SELECT 1,2,3" | nc -w 1 192.168.100.30 80


SQL Injection rules

cat /var/lib/suricata/rules/local.rules

alert tcp any any -> any any (msg:"DEBUG SQL Injection Attempt"; content:"UNION SELECT"; nocase; sid:1000001; rev:1;)






2026年3月21日 星期六

Zabbix MTR Template Lab

 事前導讀

https://www.meinekleinefarm.net/zabbix-template-net-mtr-my-traceroute/

其它相關資訊

https://xrcd2.blogspot.com/2023/04/zabbix-template-net-mtr-json-report-on.html

https://xrcd2.blogspot.com/2024/06/zabbix-70-lts.html

https://xrcd2.blogspot.com/2026/02/oracle-linux-101.html

以下操作基於 Oracle 10.1 + Zabbix 7.0.23

監控目地為專線是否有異常

從 Firewall WAN Port 至 介接的 Next Hop Gateway/Router IP 異常及品質監控  

尤其是有二個以上的 WAN port 或使用 SD-WAN 的架構監控最為合適

如 




或其它 MTR 相關運用皆可.

對於 MTR 不太了解的人,推薦自行觀看其它高手提供的資訊

MTR:Linux 網路診斷工具使用教學
(G. T. Wang 的個人部落格)


以下運用皆基於 mtr 這個工具延伸而來.

前置作業  zabbix_server.conf

 vi /etc/zabbix/zabbix_server.conf


### Option: EnableGlobalScripts

#    Enable global scripts on Zabbix server.

#       0 - disable

#       1 - enable

#

# Mandatory: no

# Default:

# EnableGlobalScripts=1


EnableGlobalScripts=1



前置作業  Linux sudo 

vi /etc/sudoers 

zabbix ALL=(root) NOPASSWD: /usr/sbin/mtr , /usr/lib/zabbix/externalscripts/mtr.sh  

可視自行監控需求修改之


前置作業 抄改 mtr.sh

https://github.com/xenadmin/zabbix-templates/blob/master/zabbix-net-mtr/mtr.sh


#!/bin/bash

IP=$1

mtr -r -c3 -w -b -p -j $IP


dnf install mtr -y  

vi /usr/lib/zabbix/externalscripts/mtr.sh 

可視自行監控需求修改之如

cat /usr/lib/zabbix/externalscripts/mtr.sh 

#!/usr/bin/bash

IP=$1

/usr/sbin/mtr -n -r -c3 -w -b -p -j $IP

mrt 測試


json 格式輸出  (Template_Net_MTR.xml 輸入的格式一定要是 json 方可使用)

shell 測試


前置作業 WEB UI  [Administrator\General\Timeouts]

External check  30s

可視自行監控需求修改之



匯入 Template_Net_MTR.xml

https://github.com/xenadmin/zabbix-templates/blob/master/zabbix-net-mtr/Template_Net_MTR.xml



透過 Shell + Template 主要取得內容為

item key 

(1)mtr.hop.host[{#HOP_ID}]

(2)mtr.hop.avg[{#HOP_ID}]

(3)mtr.hop.loss[{#HOP_ID}]


(1)MTR 第 n 個節點 IP 

(2)MTR 第 n 個節點 IP 的 RTT 

(3)MTR 第 n 個節點 IP 的 ICMP Loss


[{#HOP_ID}] 是一個由小到大的整數數值 從 1,2,3...其它的資訊可參考 Template_Net_MTR.xml

以上資訊的取得可用於圖示或告警之使用,可視自行監控需求修改之



Item prototypes


含 DNS 解析看到的 MTR Hop 2 [History 資訊]



 -n, --no-dns   [含不 DNS 解析] [=>個人偏好,監控可自行定義加上 Trigger Name 用以區分之]




MTR 可以看到的資訊



告警規則定義 可視自行監控需求修改之

last(/HiNet-GW/mtr.hop.loss[2]) >= 10

(last(/HiNet-GW/mtr.hop.host[2]) <> last(/HiNet-GW/mtr.hop.host[2],#2) or last(/HiNet-GW/mtr.hop.host[2])="???")

....




Demo


新增監控



亦可自定 Interval