iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
IT Operation

從裸機到叢集:以 Proxmox VE、Ceph、OPNsense 與 PostgreSQL HA 建立可驗證的安全私有雲系列 第 14 篇

Day 14|從預設拒絕到最小權限:OPNsense 防火牆的別名與規則順序

  • 分享至 

  • xImage
  •  

VLAN、IP 網段與 OPNsense 介面已經建立清楚的路由邊界,接下來要把流量需求轉成可以執行、驗證與維護的防火牆政策。

今天要解決的問題

一筆新連線進入 OPNsense 後,狀態表(State Table)與防火牆規則會如何處理?規則應放在哪個介面?浮動規則(Floating Rule)、介面群組規則(Interface Group Rule)與單一介面規則的先後順序是什麼?Alias 如何降低維護成本,又為什麼不等於權限?

本文閱讀方式

  • 完整理解技術與底層原理:依序閱讀全文。
  • 掌握完成部署所需的基本概念:優先閱讀標有「⭐」的章節。
  • 快速了解當天的部署內容:閱讀文末的 Lab/實作章節。
  • 跟著系列建立完整系統:依照 GitHub 詳細部署文件 的天數順序操作。

⭐ 從封包進入介面開始

前文已介紹狀態式防火牆、安全區域與最小權限。今天先複習必要概念,再從 OPNsense 底層使用的 pf 說明封包如何比對狀態與規則,最後把規則模型套用到已建立的 VLAN 介面。

封包抵達防火牆時,第一個可觀察位置是入站介面(Inbound Interface)。規則預設在封包進入 OPNsense 的方向比對,因此來源位於 SERVICE 的連線通常從 SERVICE 介面開始判斷。由 Internet 進入的連線則從 WAN 開始判斷。

封包依進入 OPNsense 的介面查詢狀態表,再比對對應的規則表

圖(一)新連線從入站介面進入規則表,既有連線則可直接符合狀態表

第一個符合允許規則(Pass Rule)的封包會建立連線狀態,後續屬於同一筆連線的封包可以直接符合狀態表,不必每次重新比對完整規則集(Ruleset)。因此一般只需允許連線發起方向,合法的回程封包會沿用既有狀態。

第一個封包符合規則後建立狀態,回程封包沿用既有狀態

圖(二)狀態式防火牆只需允許連線發起方向,回程封包可沿用既有狀態

這也會影響測試。修改規則或 Alias 後,既有連線可能繼續符合舊狀態,看起來像是新規則沒有生效。排錯時應先確認 Firewall → Diagnostics → States,必要時只移除相關狀態。清除全部狀態會中斷其他連線。

同 VLAN 主機可能直接交換訊框,不會進入 OPNsense。這裡建立的政策只能控制實際跨越 OPNsense 介面的流量。同 VLAN 的限制由更細的網路分段、PVE 防火牆或主機防火牆(Host Firewall)補足。

⭐ 一條規則最少要有什麼

建立防火牆規則時,依實際流量需求設定下列欄位:

規則欄位 設定原則
動作(Action) 必要流量使用 Pass。需要明確阻擋時使用 Block 或 Reject。
介面/方向(Interface/Direction) 選擇封包進入 OPNsense 的介面,方向通常使用 in。
IP 版本/協定(IP Version/Protocol) 只選實際使用的 IPv4、IPv6、TCP、UDP 或 ICMP。
來源(Source) 限定真正獲准發起連線的主機、網段或 Alias。
來源連接埠(Source Port) 用戶端通常使用臨時連接埠,因此多數規則保持 any。
目的(Destination) 限定實際服務主機、網段、VIP 或防火牆本身。
目的連接埠(Destination Port) 只填入伺服器實際提供的服務連接埠。
紀錄(Log) 只替需要稽核、排錯或驗證拒絕結果的規則啟用。
說明(Description) 寫明流量用途、來源、目的與服務,讓規則可以稽核。

三種常見動作的差異如下:

  • Pass:允許封包,預設會建立連線狀態。
  • Block:直接丟棄,用戶端通常等待到逾時。不受信任來源常使用這種方式。
  • Reject:拒絕並主動回覆。TCP 通常回覆 RST,UDP 則回覆 ICMP Unreachable。內部排錯時可以更快顯示連線遭拒。

⭐ 防火牆如何決定規則的實際比對順序?

OPNsense 會依規則所屬區段決定處理優先序。系統自動規則之外,主要順序為:

OPNsense 依序處理浮動規則、介面群組規則、單一介面規則與預設拒絕

圖(三)OPNsense 各規則區段的主要處理優先序

每個區段內還要再看順序(Sequence)。一般規則預設啟用 Quick,表示由上往下比對,第一條符合的規則立即決定結果。若取消 Quick,則會繼續比對並採用最後一條符合的規則。沒有明確需求時,維持 Quick,用「較精確的規則在上、較廣泛的規則在下」閱讀最容易稽核。

新版 OPNsense 的 Firewall → Rules [new] 中,一條規則選擇單一介面時是介面規則。選擇介面群組時是群組規則(Group Rule)。同時選擇多個介面或反向選取介面,會被歸入浮動規則。浮動規則的處理時間早於群組規則與單一介面規則。

介面群組規則又早於單一介面規則。若群組中先出現一條廣泛的 Block,後面單一介面的 Pass 沒有機會命中。共同政策與例外政策必須按照實際優先序設計,審查時應查看完整處理順序與所有相關區段。

介面群組建立的是共同規則入口,不會合併成員介面的廣播域。封包從任一成員介面進入 OPNsense 時,都會先比對該群組的規則。例如 SERVICE 是 LAB_INTERNAL 的成員,10.77.20.31 向 SERVICE 介面的 10.77.20.1 查詢 DNS 時,封包從 SERVICE 進入,便會比對 LAB_INTERNAL → This Firewall TCP/UDP 53 Pass。由管理用 LAN 進入的封包不屬於這個群組,因此不會套用這條群組規則。

⭐ 別名(Alias)與介面群組分別抽象不同資料

Alias 是可以重複引用的命名集合,常見類型包括:

  • Host(s):單一主機、位址範圍或完整網域名稱。
  • Network(s):使用 CIDR 表示的一個或多個網段。
  • Port(s):單一連接埠或連接埠範圍。
  • Network Group:組合其他 Host 或 Network 類型的 Alias。

Host、Network、Port 與 Network Group Alias 的內容與組合方式

圖(四)不同 Alias 類型保存不同形式的位址或連接埠資料

圖中由左至右分別是 Alias 類型、可供規則引用的名稱,以及實際展開內容。Host Alias 可以集合多台主機,Network Alias 保存一個或多個 CIDR 網段,Port Alias 集合服務連接埠。Network Group 則把既有的 Host、Network 或其他 Network Group Alias 再組成較大的位址集合,不能混入 Port Alias。

例如 PG_NODES 代表 10.77.30.11~10.77.30.13,比在多條規則中散落三個 PostgreSQL IP 更容易閱讀。圖中的 WEB_PORTS 則集中表示 TCP 80 與 443。Alias 只保存資料。防火牆規則引用 Alias 後才會形成實際權限。

名稱應描述穩定角色,Description 則記錄用途。修改一個 Alias 會同時影響所有引用它的規則,因此變更前要先查詢引用關係,變更後再到 Firewall → Diagnostics → Aliases 檢查實際展開內容。

介面群組組合的是介面,目的是讓多個介面套用共同規則。本系列把 SERVICE、DATABASE、BACKUP 與 BASTION 加入 LAB_INTERNAL,只用來承接 DNS、NTP、內部網段阻擋與套件更新等共同基準。

⭐ 預設拒絕要從流量需求轉成例外

前面提到,網路層的最小權限要同時縮小來源、目的、協定與目的連接埠。沒有符合明確允許條件的流量,則交由預設拒絕或明確的阻擋規則處理。

製作防火牆規則時,可以依下列流程把業務需求拆成規則欄位,並規劃完成後的驗證方式:

從業務需求確認入站介面、來源、目的、協定、連接埠、紀錄與驗證方式

圖(五)從業務需求拆解防火牆規則條件並規劃驗證方式

DNS、NTP、套件更新、監控、備份與管理連線都要明確記錄,並以具體的來源、目的與服務取代 any to any。必要流量尚未盤點完成前,直接收緊規則可能中斷名稱解析、校時、更新或管理路徑。

規則順序應先放必要而精確的允許規則,再放明確的區域間阻擋規則,最後才放較廣泛的外部服務允許規則。例如內部網段阻擋規則必須位於「到任何目的地的 TCP 80/443」之前,否則後者也可能允許存取其他內部區域的 Web 服務。

規則紀錄顯示哪一條規則被命中

規則紀錄(Log)保存啟用紀錄的規則命中結果。Firewall → Log Files → Live View 可以查看介面、來源、目的、動作與規則 ID(Rule ID),適合確認封包是被哪一條規則允許或阻擋。

狀態式規則(Stateful Rule)通常只在建立狀態的第一個封包留下規則紀錄,後續封包沿用狀態時不會持續出現在 Live View。因此沒有新紀錄不代表沒有流量。紀錄應保留給重要管理入口、預期遭拒的負向測試與需要稽核的區域邊界,避免大量低價值紀錄干擾排錯。

狀態表顯示目前存在的連線

Firewall → Diagnostics → States 顯示目前由 pf 追蹤的連線狀態,以及來源、目的、協定、連接埠與命中的規則。它適合判斷回程流量是否正在沿用既有狀態,也能解釋規則修改後舊連線為何仍可通過。

狀態表只顯示已建立且尚未逾時的連線。需要重新測試規則時,只移除與測試流量相關的狀態,避免中斷其他使用者連線。

封包擷取顯示封包實際經過的介面

Interfaces → Diagnostics → Packet Capture 直接擷取指定介面上的封包,能確認封包是否抵達 OPNsense、從哪個介面進入,以及是否從預期介面離開。封包擷取看得見實際流量,但不會直接告訴管理者是哪一條防火牆規則做出決定,需要與規則紀錄及狀態表交叉比對。

OPNsense Packet Capture 可選擇介面、位址家族、協定、主機與連接埠

圖(六)封包擷取可依介面與流量條件縮小觀察範圍

排錯時先用規則紀錄確認規則命中結果,再用狀態表確認既有連線。若路徑不清楚,最後使用封包擷取比較各介面。三種工具各自提供不同證據,排錯時應交叉使用。

每一條重要允許規則都要搭配負向測試。除了確認正確來源能連線,也要改用錯誤來源、錯誤目的地或錯誤連接埠,確認預設拒絕或明確的 Block 確實接住不符合條件的流量。

本次 Lab:建立別名、介面群組與共同規則

不同 VLAN 已經形成可路由的介面邊界,今天接著把重複使用的網段、主機與連接埠整理成 Alias,再將四個服務 VLAN 納入 LAB_INTERNAL 介面群組,建立共同的 DNS、NTP、內部網段阻擋與套件更新規則。

服務端點尚未全部建立,因此今天只驗證 Alias、群組成員與規則順序是否正確套用。跨 VLAN 成功結果與服務專屬規則、WAN Port Forward 留待服務端點建立後測試與設定。

GitHub 詳細實作文件:Day 14|從預設拒絕到最小權限:OPNsense 防火牆的別名與規則順序

本次實作摘要

  1. 建立內部網段、主機與服務連接埠 Alias。
  2. 將 SERVICE、DATABASE、BACKUP 與 BASTION 加入 LAB_INTERNAL。
  3. 在介面群組上建立四條共同規則。
  4. 核對 DNS、NTP、內部網段阻擋與外部更新規則的順序。
  5. 確認規則只套用於 LAB_INTERNAL,沒有誤建成較早比對的浮動規則。
  6. 下載完成 Alias 與規則後的 config.xml 備份。

驗證一:Alias 保存可重複引用的網路條件

到 Firewall → Aliases 建立 INTERNAL_NETWORKS,Type 選 Network(s),並將五個 CIDR 分別加入 Content:

10.77.10.0/24
10.77.20.0/24
10.77.30.0/24
10.77.40.0/24
10.77.50.0/24

INTERNAL_NETWORKS 使用 Network Alias 保存五個內部網段

圖(七)INTERNAL_NETWORKS 將五個內部網段集中成一個 Network Alias

接著建立已規劃主機使用的 Host Alias:

Alias Content
PROXY_NODES 10.77.20.21、10.77.20.22
APP_NODES 10.77.20.31、10.77.20.32
PG_NODES 10.77.30.11、10.77.30.12、10.77.30.13
CA_NODE 10.77.30.10
BACKUP_NODE 10.77.40.11
BASTION_HOST 10.77.50.11
WEB_VIP 10.77.20.10
DB_RW_VIP 10.77.20.11
DB_RO_VIP 10.77.20.12
BASTION_TARGETS 10.77.20.21、10.77.20.22、10.77.30.11~10.77.30.13、10.77.40.11

Port Alias 則保存規則會重複引用的目的連接埠:

Alias Content
WEB_PORTS 80、443
PGSQL_PORT 5432
PATRONI_API 8008
ETCD_PORTS 2379、2380
BASIC_OUTBOUND_TCP 80、443

OPNsense Alias 清單顯示已建立的部分 Host 與 Port Alias

圖(八)Alias 清單顯示已建立的部分 Host 與 Port Alias

Alias 只替條件命名,本身不會建立主機或放行流量。Port Alias 也只保存連接埠號碼。TCP 或 UDP 由引用它的規則決定。BASTION_TARGETS 則是跳板機在網路層可接近的主機上限,個別使用者由 OpenSSH 設定、目標帳號與公鑰繼續限制。

驗證二:介面群組只包含四個服務 VLAN

到 Firewall → Groups 建立 LAB_INTERNAL,Members 選擇 SERVICE、DATABASE、BACKUP 與 BASTION,不加入管理用 LAN。No GUI groups 保持未勾選,儲存後按下 Apply。

LAB_INTERNAL 群組包含 SERVICE、DATABASE、BACKUP 與 BASTION,並排除管理用 LAN

圖(九)LAB_INTERNAL 只包含四個服務 VLAN,不包含管理用 LAN

介面群組讓四個成員介面共用一組基礎規則。各 VLAN 保持獨立廣播域,跨 VLAN 流量依防火牆規則決定。

驗證三:共同規則依照範圍由窄到寬排列

到 Firewall → Rules,Interface 只選 LAB_INTERNAL,依序建立並排列以下四條規則:

順序 Action Protocol Source Destination Destination Port 用途
1 Pass TCP/UDP LAB_INTERNAL network This Firewall 53 使用防火牆提供的 DNS
2 Pass UDP LAB_INTERNAL network This Firewall 123 使用防火牆提供的 NTP
3 Block+Log any LAB_INTERNAL network INTERNAL_NETWORKS any 接住未明確允許的跨區流量
4 Pass TCP LAB_INTERNAL network any BASIC_OUTBOUND_TCP 允許 HTTP/HTTPS 對外更新

LAB_INTERNAL 的 DNS、NTP、內網阻擋與外部更新四條群組規則

圖(十)四條共同規則位於 LAB_INTERNAL 的 Group rules 區段

規則啟用 Quick 後,第一條符合條件的規則就會決定結果。內部網段 Block 必須位於外部 HTTP/HTTPS Pass 之前,否則目的為其他內部網段 TCP 80/443 的流量可能先被較寬的對外規則允許。後續若建立服務專屬的跨區 Pass,要使用明確的來源、目的與連接埠,並放在內部網段 Block 上方。

驗證四:規則位於正確的比對區段

在規則畫面以 LAB_INTERNAL 篩選,確認四條規則顯示在 Group rules,順序與上表一致。再開啟其中一條規則,確認 Interface 只有 LAB_INTERNAL。同時選取 SERVICE、DATABASE、BACKUP 與 BASTION 會讓規則進入較早處理的浮動規則區段,改變原本規劃的比對順序。

圖(七)至圖(十)可以證明設定結構與順序已建立。規則是否真的依條件允許或阻擋封包,還要從實際來源端送出流量,並配合用戶端結果與 OPNsense 規則紀錄交叉確認。

驗證五:允許與阻擋結果符合規則順序

以下畫面是在 app01 與 pg01 建立後補測,用來驗證本日規則的實際行為。從 SERVICE 網段的 app01 測試防火牆的 TCP 53 連線,再嘗試連向 DATABASE 網段未授權的 TCP 5433。前者應成功,後者應逾時:

nc -vz -w 3 10.77.20.1 53
nc -vz -w 3 10.77.30.11 5433

app01 連向 OPNsense TCP 53 成功,連向 pg01 TCP 5433 則逾時

圖(十一)從 SERVICE 網段驗證允許的 TCP 53 連線與未授權的跨 VLAN 連線

接著到 Firewall → Log Files → Live View,使用來源 10.77.20.31 與目的 10.77.30.11 篩選,再執行一次 TCP 5433 測試。畫面應顯示封包被 Block LAB_INTERNAL to internal networks 規則阻擋:

OPNsense Live View 顯示 app01 前往 pg01 TCP 5433 的封包遭到內網 Block 規則阻擋

圖(十二)Live View 確認未授權跨 VLAN 流量命中內部網段阻擋規則

成功連到 TCP 53 只驗證 TCP 路徑與監聽端點。完整 DNS 驗證應實際送出查詢。TCP 5433 逾時搭配 Live View 的 Block 紀錄後,可以確認未授權跨區流量確實被第三條規則接住。

Lab 驗證對照

驗證 主要證據 可以得到的結論
驗證一:Alias Alias 編輯畫面與清單 網段、主機與連接埠條件已建立並可供規則引用
驗證二:介面群組 LAB_INTERNAL 的 Members 四個服務 VLAN 共用基礎政策,管理用 LAN 不在群組內
驗證三:共同規則 LAB_INTERNAL 規則清單 DNS、NTP、內部網段阻擋與外部更新規則依序存在
驗證四:比對區段 Group rules 與規則的 Interface 規則套用於介面群組,沒有誤建成浮動規則
驗證五:規則行為 app01 連線結果與 Live View 允許的 TCP 53 連線可通過,未授權跨 VLAN 流量命中內網 Block

完成後到 System → Configuration → Backups 下載 config.xml。設定備份可能含有敏感資料,不應提交到 Git。

今天完成了什麼

  • 將內部網段、規劃主機與服務連接埠整理成可重複引用的 Alias。
  • 建立只包含 SERVICE、DATABASE、BACKUP 與 BASTION 的 LAB_INTERNAL 介面群組。
  • 建立共同的 DNS、NTP、內部網段阻擋與 HTTP/HTTPS 對外更新規則。
  • 將內部網段阻擋放在較寬的對外更新規則之前。
  • 確認共同規則位於介面群組規則區段,沒有誤建成浮動規則。
  • 從實際來源端交叉驗證允許的 TCP 53 連線與遭阻擋的跨 VLAN 流量。

下一篇預告

下一篇〈Day 15|SSH 跳板機的部署與權限設計(上):Linux 路由切換與建立安全入口〉會先替 PVE 建立必要的出口規則,再逐台將一般對外路徑切換到 OPNsense。確認管理路徑可用後,再部署並強化唯一公開的 SSH 跳板入口。


參考資料


上一篇
Day 13|從 VLAN 到安全區域:802.1Q、跨網段路由與 OPNsense 介面
下一篇
Day 15|SSH 跳板機的部署與權限設計(上):Linux 路由切換與建立安全入口
系列文
從裸機到叢集:以 Proxmox VE、Ceph、OPNsense 與 PostgreSQL HA 建立可驗證的安全私有雲 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言