今天開始進入主線二:受控的網路與管理入口。接下來會從防火牆原理與部署位置開始,逐步建立 OPNsense、WAN 與 VLAN 網路分段,再加入最小權限規則、跳板機、OpenVPN 及 IDS/IPS,讓本地與遠端管理流量都經過可控、可記錄的安全入口。
防火牆不是只限制幾個連接埠(Port)的出入,也不是安裝後放在網際網路(Internet)前面就會自動保護所有服務。它必須位於封包真正經過的位置,再依照來源、目的、協定與既有連線狀態,決定流量能不能跨越安全邊界。
因此,在安裝 OPNsense 前,要先建立一套描述流量的方法。否則後面即使會操作每一個 GUI 欄位,也可能把規則放在錯誤的介面(Interface),或開放了比服務真正需要的範圍更大的權限。
今天先處理:
本文閱讀方式
- 完整理解技術與底層原理:依序閱讀全文。
- 掌握完成部署所需的基本概念:優先閱讀標有「⭐」的章節。
- 快速了解當天的部署內容:閱讀文末的 Lab/實作章節。
- 跟著系列建立完整系統:依照 GitHub 詳細部署文件 的天數順序操作。
NIST(美國國家標準暨技術研究院)將防火牆(Firewall)定義為控制不同網路或主機之間流量的裝置或程式。它可以是實體設備、虛擬機,也可以是安裝在單一主機上的軟體。
如果網路只負責把封包送到目的地,路由器只要知道下一站在哪裡,交換器只要知道該把資料框(Frame)送到哪個連接埠,就已經完成任務。但這條路徑卻沒辦法檢查哪個來源有權限進出。當內部主機開始連上其他網路、網際網路與更多服務後,管理者便需要一個能集中執行安全政策的控制點:哪些來源能進來、能前往哪裡、能使用哪些服務,其餘流量如何處理。這就是防火牆要解決的問題。
防火牆能用來判斷流量的資訊並不是一開始就很完整。接下來會從封包本身開始,逐步看到它為什麼需要記住連線,又為什麼只知道 IP 與連接埠依然不夠。
無論防火牆能檢查多少層資訊,第一個條件都是封包必須真的經過它。只有位於資料路徑上的防火牆,才有機會套用安全政策。

圖(一)防火牆必須位於封包實際經過的路徑
如果兩台主機位於同一個 VLAN/子網路(Subnet),它們可能只經過 PVE Linux Bridge 或實體交換器,完全不需要把流量交給預設閘道(Default Gateway)。此時不論 OPNsense 規則寫得多完整,都看不到這筆流量。

圖(二)跨 VLAN 流量由防火牆與路由器轉送
所以設計防火牆的第一個重點是這筆流量會經過哪一個控制點。
應用程式資料送上網路時,會逐層加上不同用途的標頭(Header)。可表示為:

圖(三)應用程式資料依序加入 TCP/UDP 與 IP 標頭
資料來源:Ace Networker|Packet Header - Where Do We Go From Here? And WHY?
乙太網路(Ethernet)負責同一個 Layer 2 範圍內的傳遞。IP 提供來源與目的位址,讓路由器判斷跨網段的下一站。TCP/UDP 則以連接埠將資料交給正確的應用程式。
早期常見的做法是封包過濾(Packet Filtering)。設備逐一查看封包的來源 IP、目的 IP、協定與連接埠,再決定允許或拒絕。這種方式直接而有效,也成為許多路由器 ACL(存取控制清單)與網路防火牆的基礎。
Layer 3/Layer 4(第 3 層/第 4 層)防火牆常以五元組(Five-tuple)識別一筆 TCP/UDP 流量:
例如 VPN 用戶端連線到 PVE 網頁管理介面:
10.77.60.3:53142 → 10.77.10.11:8006 / TCP
53142 是用戶端暫時選出的臨時連接埠(Ephemeral Port),8006 才是 PVE 正在監聽的服務連接埠。因此一般服務規則會限制目的連接埠,來源連接埠通常維持 any。
連接埠不是所有 IP 協定都有的欄位:
需求文件若只寫開放 8006,但缺少來源、目的、協定與路徑會使得理解歧異或者設定錯誤。完整語意應該是允許 VPN 管理群組以 TCP 連到 PVE 節點的 8006。這一點在後面設定防火牆時會常常看到。
封包過濾能辨認一個封包長什麼樣子,卻不知道它是不是某段正常對話的一部分。對無狀態封包過濾(Stateless Packet Filter)來說,每個封包都像單獨出現的一張紙條,只能再次套用相同規則判斷。
狀態檢查(Stateful Inspection)因此加入了狀態表(State Table)。狀態式防火牆不只判斷第一個封包,還會記住這筆連線的方向與狀態,讓合法的回程封包沿著既有狀態返回,並阻擋不符合連線進度的封包。OPNsense 的防火牆預設採用這種處理方式。
以 HTTPS 為例:

圖(四)狀態式防火牆允許符合既有狀態的回程封包
這代表用戶端主動連線到伺服器時,不需要另外建立一條伺服器從 443 回到用戶端任意臨時連接埠的寬鬆規則。UDP 沒有 TCP 三向交握,但狀態式防火牆可依流量與逾時時間建立暫時狀態。
狀態表補上了連線上下文,但 IP 與連接埠只能說明封包要去什麼位置,不能完整解釋裡面正在進行什麼操作。不同應用可能使用相同連接埠,應用資料本身也可能違反安全政策,因此又發展出應用程式代理(Application Proxy)與應用感知檢查(Application-aware Inspection)。
應用程式代理是一種處理流量的方式:代理服務先終止用戶端連線,解析應用層內容,再另外建立一條連線前往後端。它可以是 Nginx 這類獨立服務,也可以是安全閘道或防火牆內建的功能。應用感知檢查則是一種檢查能力,表示設備能辨識 HTTP、DNS 等應用協定及其內容。這些功能能看見什麼,會在下一篇介紹防火牆種類時再比較。
狀態只代表封包屬於某筆已允許的網路連線,不能證明使用者是誰,也不會判斷 SQL 是否越權或 HTTP 內容是否惡意。OpenVPN 憑證、SSH 金鑰、Nginx 政策、pg_hba.conf 與 PostgreSQL 角色要在各自層級完成驗證與授權。
後來的產品還會整合 VPN、IDS/IPS、惡意內容檢查與集中管理等功能,這些能力也常出現在下一代防火牆(Next-Generation Firewall,NGFW)與整合式威脅管理(Unified Threat Management,UTM)產品中。NGFW、UTM 與其他防火牆類型的差異,會留到下一篇完整比較。
修改防火牆規則後,既有連線也可能暫時沿用原本的狀態。所以修改規則後還要檢查狀態表。實際查看與清除狀態則留到建立規則時操作。
進站(Inbound)與出站(Outbound)是相對於某一台設備、某一個介面的方向。介面就相當於設備的入口與出口,同一筆流量站在不同設備上觀察,方向也會不同。
OPNsense 一般將規則套用在封包進入防火牆的介面:

圖(五)流量從不同介面進入 OPNsense
同一筆 HTTPS 請求對用戶端而言是出站,到防火牆 WAN 介面時卻是進站。若文件只寫允許進站 443,卻沒有設備、進入介面、來源與目的,實作者無法知道規則應放在哪裡。
OPNsense 還有浮動規則(Floating Rule)、介面群組(Interface Group)與一般介面規則,不同類型有各自的處理順序。等實作的時候會詳細說明。
OPNsense 可以同時擔任路由器、NAT 閘道與防火牆,但三者不能互相取代:
來源 NAT 常用於讓多台私有網路主機共用或轉換成 WAN 位址對外連線。多條連線共用同一個公網 IPv4 時,設備通常還會改寫來源通訊埠,稱為通訊埠轉換(Port Address Translation,PAT)。目的 NAT 則會改寫封包的目的位址或通訊埠,通訊埠轉送(Port Forward)就是常見例子。NAT 只負責轉換位址與通訊埠,轉換後必須由防火牆規則決定能否通過。
傳統的邊界防護常把 LAN(區域網路)視為信任區,把 WAN 視為非信任區。這種劃分容易理解,但只要內部電腦中毒、訪客裝置接入,或 VPN 帳號遭竊,攻擊者就可能已經位於所謂的信任區。因此現代網路不能只用內部或外部判斷信任程度,還要依系統用途與實際通訊需求進一步分區。
VLAN 與子網路是網路分段技術,安全區域則是依用途、信任程度與通訊需求形成的政策範圍。一個區域可以包含一個或多個介面或網路。OPNsense 官方的安全區域範例也是先把相近信任等級的介面分組,再建立區域之間的政策。
信任邊界是安全條件發生改變的位置,例如:

圖(六)同一台 OPNsense 隔離外部、DMZ 與內部區域
圖中兩個 OPNsense 圖示代表同一台防火牆的不同流量檢查位置,不是部署兩台 OPNsense。外部流量進入 DMZ,以及 DMZ 存取內部服務時,都會由同一台 OPNsense 依不同介面上的防火牆規則重新判斷。
當跨越邊界時,應重新判斷來源身分、目的服務、必要權限與紀錄方式。DMZ(網路安全隔離區)位於外部非信任區與內部區域之間。它用來承載可能被較低信任來源接觸的服務,所以更不能任意存取內部高價值資源。
DMZ 的重點是把不同信任程度的服務分區,讓流量跨越區域時必須重新接受安全政策判斷,降低外部入口失守後直接影響內部高價值資產的可能性。
南北向流量(North-South Traffic)通常指外部與內部之間的通訊,例如網際網路用戶端連到公開入口。東西向流量(East-West Traffic)則是內部工作負載之間的通訊,例如代理伺服器連到應用程式,或應用程式連到資料庫。
只防守南北向流量,會讓取得某台內部虛擬機的攻擊者自由橫向移動。管理平面(Management Plane)也不能和一般服務流量混在一起:PVE 網頁管理介面、OPNsense 網頁管理介面與 SSH 能直接改變系統狀態,應比一般 HTTP 請求使用更嚴格的來源與身分限制。
網路位置只能提供判斷條件,不能直接等同於使用者可信。數位發展部的零信任架構說明同樣指出,存取決策還要納入使用者身分、設備鑑別與設備健康狀態等條件。
攻擊面(Attack Surface)可以白話理解成攻擊者可能嘗試進入、利用或取得權限的所有入口。以一台公開 SSH 的主機為例,攻擊面不只包含 TCP 22,還包括 SSH 服務版本與設定、可登入的帳號、密碼或金鑰,以及保管金鑰的管理者電腦。
盤點時可以先分成三類:
ss -lntup 可以列出主機正在監聽的通訊端(Socket),連接埠掃描可以確認測試端實際碰得到哪些服務,但兩者找不到過期帳號、遺失的私鑰或錯誤的資料庫權限。因此盤點結果還要記錄用途、負責人、驗證方式與停用方法。
如果只維護阻擋清單,總會有尚未列入的新來源或新手法。防火牆較穩定的基準是先拒絕未被允許的流量,再只為已知且必要的通訊建立允許規則。這是最小權限原則在網路層的實作方式。
預設拒絕(Default Deny)先阻擋沒有明確符合的流量,再為必要需求加入允許規則。
但說起來簡單。若不知道 DNS、NTP、套件更新、健康檢查、資料複寫與管理流量從哪裡到哪裡,直接封鎖只會造成既有服務中斷,因此設定前要先寫規則矩陣(Rule Matrix)。每一列至少回答:
也就是要先了解現有服務需要哪些通訊,才有辦法進一步規劃。這份矩陣會在建立防火牆規則時直接轉成來源、目的、協定、連接埠與驗證條件。
今天不安裝 OPNsense,先把正文中的封包路徑、信任邊界與最小權限轉成可以實作及驗收的資料。盤點結果要能回答目前有哪些網路路徑、主機正在監聽哪些服務,以及後續哪些來源確實需要跨越安全區域。
完整命令、盤點欄位與操作順序請依照:
GitHub 詳細部署文件:Day 09|信任邊界與流量盤點
這次 lab 中的圖片是在後續部署完成後補拍。但是不影響盤點方法的介紹與證明。
在 PVE 節點執行:
ip -br address
ip route
ss -lntup
介面位址說明節點連接哪些網段,路由表則指出不同目的網段會從哪個介面送出。圖(七)中,預設路由經過管理網路的 OPNsense。Ceph 與 Corosync 網段則使用直接連線路由。這表示一般對外流量可以經過 OPNsense,而兩個叢集專用網路不會因為建立了防火牆規則就自動改走 OPNsense。

圖(七)PVE 節點的介面與路由表指出一般對外流量、Ceph 與 Corosync 使用不同路徑,ss 則列出本機正在監聽的 Socket。
ss -lntup 顯示本機監聽位址、協定與連接埠。以足夠權限執行時也會顯示所屬程序。systemctl 則用來確認相關服務是否正在執行。監聽於 127.0.0.1 的服務只接受本機連線,監聽於特定位址或 0.0.0.0 的服務要配合路由與防火牆測試,才能判斷其他主機是否真的可以連入。
systemctl --type=service --state=running

圖(八)PVE 節點的執行中服務可與監聽連接埠交叉比對,找出需要管理或限制的服務入口。
在既有 Debian 測試 VM 執行相同盤點:
ip -br address
ip route
ss -lntup
systemctl --type=service --state=running

圖(九)測試 VM 的介面、路由、監聽 Socket 與執行中服務提供另一份主機暴露面紀錄。
再以足夠權限執行 ss,確認監聽 Socket 所屬程序:
sudo ss -lntup

圖(十)以足夠權限執行 ss 後,可以確認監聽 Socket 所屬程序。
這項盤點只能確認服務在本機的監聽狀態,不能單獨證明遠端一定可以連入。防火牆規則與對應服務完成後,要從實際來源端執行允許與拒絕測試。
先記錄預計使用的安全區域:
| 區域 | 網段 | 主要用途 | 是否經 OPNsense |
|---|---|---|---|
| 管理區(Management) | 10.77.10.0/24 |
OPNsense 與 PVE 管理 | 是 |
| 服務區(Service) | 10.77.20.0/24 |
代理、應用程式、測試用戶端與監控 | 是 |
| 資料庫區(Database) | 10.77.30.0/24 |
PostgreSQL、Patroni、etcd | 是 |
| 備份區(Backup) | 10.77.40.0/24 |
pgBackRest 備份儲存庫 | 是 |
| 跳板機網路安全隔離區(Bastion DMZ) | 10.77.50.0/24 |
jump01 | 是 |
| OpenVPN | 10.77.60.0/24 |
遠端使用者 Tunnel IP | 由 OPNsense 終結 |
| Ceph | 10.77.70.0/24 |
PVE 儲存流量 | 否 |
| Corosync | 10.77.80.0/24 |
PVE 叢集通訊 | 否 |
Ceph 與 Corosync 使用沒有 Default Gateway 的專用網路,因此不把這兩類流量誤寫成經過 OPNsense。接著將服務需求整理成第一版矩陣。此時只定義政策,不先開放連接埠:
| 來源 | 目的 | 協定/連接埠 | 預期 | 理由 |
|---|---|---|---|---|
| Cloudflare 節點 | 公開 WAN 入口(DNAT 至 Web VIP 10.77.20.10) |
TCP 443 | 允許 | 公開 Web 入口 |
| 網際網路 | DB VIP/pg01~03 | TCP 5432 | 拒絕 | 資料庫不公開 WAN |
| jump01 | 授權內部主機 | TCP 22 | 允許 | 受控 SSH 管理入口 |
| proxy01/02 | pg01~03 | TCP 5432、8008 | 允許 | SQL 與 Patroni 健康檢查 |
| pg01~03 | pg01~03 | TCP 5432、2379、2380 | 允許 | 資料複寫與 etcd 用戶端/同儕連線 |
| monitor01 | 受監控主機 | 指定匯出器連接埠 | 允許 | 擷取監控指標 |
| VPN 管理員 | pve01~03 | TCP 8006 | 允許 | PVE 網頁管理介面 |
| VPN 一般使用者 | pg01~03 | TCP 5432、8008、2379 | 拒絕 | 不繞過 VIP 與管理邊界 |
矩陣中的每一列都包含來源、目的、協定、目的連接埠與理由,後續才能轉成防火牆規則。允許條件還應配對一項負向測試,例如允許 proxy01 連到 PostgreSQL TCP 5432,同時確認 jump01 不能直接連入相同服務。
| 項目 | 方法 | 結論 |
|---|---|---|
| 證明一:流量控制點 | ip -br address 與 ip route |
不同目的網段使用的介面與下一跳可以被明確辨識 |
| 證明二:主機網路暴露面 | ss -lntup 與執行中服務清單 |
可以找出本機正在提供的網路入口及其程序 |
| 驗證三:規則輸入 | 安全區域表與流量需求矩陣 | 必要流量已具備轉成規則及後續驗收的基本欄位 |
正式環境還要記錄服務擁有者、用途、核准狀態與重新檢查日期,並定期核對監聽清單與實際可達性。這些主機、服務、監聽連接埠與網路路徑的紀錄,屬於資產盤點(Asset Inventory)中的網路與服務盤點。規則矩陣則是依據盤點結果建立的存取政策,還要由實際來源網段執行遠端連線測試,避免服務變更後留下未管理的入口。
下一篇是 Day 10|防火牆種類與部署位置:封包過濾、Proxy、WAF、IDS/IPS 與 NGFW。流量需求已經整理成規則矩陣,接著要比較網路防火牆、主機防火牆、WAF 與虛擬防火牆各自能看見什麼、適合放在哪裡,以及不同部署方式的故障域與維運差異。