在可能遭受入侵的 DMZ 環境中採用「不信任 Agent」前提的設計
1. 前言 —— DMZ 在安全監控上存在「盲點」 #
對雲端服務供應商與代管服務供應商而言,DMZ(非軍事區)中的公開網頁伺服器與反向代理伺服器是最容易成為攻擊目標的位置。
即使在這樣的位置,透過 syslog 轉送來彙整日誌的架構也並不少見。然而,這裡有一個重要的前提:
BASTION 的 DMZ Agent 是以「Agent 本身可能已遭入侵」為前提所設計的。本文將說明支撐此設計的「Agent 不信任模型」以及其背後的驗證引擎設計。
2. 為何既有的 EDR 與 SIEM Agent 並不足夠 #
EDR(端點偵測與回應)與 SIEM 產品的 Agent 功能雖然能夠偵測端點異常,但這類產品大多以下列前提為基礎:
- Agent 是可信任的(=由伺服器端簽署發行的二進位檔)
- 從 Agent 送出的事件是正確的(=已在 Agent 內部完成事前驗證)
- 若 Agent 保持沈默,代表伺服器是安全的(=異常時 Agent 應會通知)
這些前提在平時是成立的,但在已遭入侵的 DMZ 伺服器上將會完全失效:
- 即使是經過簽署的二進位檔,只要取得 root 權限,Agent 程序本身就能被竄改
- 若攻擊者理解 Agent 內部的事件驗證邏輯,便能製造出能通過驗證的「偽造事件」
- 透過終止 Agent 並啟動偽造的 Agent,便能偽裝出「正常的沈默」
BASTION 的設計目標,即是要堵住這些所有的漏洞。
3. Agent 不信任模型 —— 三種職責分離 #
BASTION 的 Agent 與中央伺服器(AI-SLOG)之間的關係,被明確地分離為三種職責。
| 職責 | 負責方 | 理由 |
|---|---|---|
| 日誌收集與初步事件產生 | Agent(DMZ 端) | 低延遲與即時反應能力十分重要 |
| 事件驗證與判斷 | AI-SLOG(內部端) | 必須在不可能遭到入侵的位置執行 |
| 防禦行動(封鎖) | Agent(DMZ 端) | 只能在相關伺服器上執行封鎖 |
關鍵在於「偵測」與「驗證」在物理上是分離的。即使 Agent 通知「偵測到攻擊」,AI-SLOG 也不會照單全收,而是始終會透過另一條路徑,直接從同一台伺服器取得原始日誌來進行獨立驗證。
DMZ Server AI-SLOG (Internal)
┌──────────────┐ ┌──────────────┐
│ Agent │── WebSocket ──→│ Receive │
│ ・Log Monitor│ (Events) │ │
│ ・Primary │ │ ↓ │
│ Detection │ │ Validation │←─ Raw logs
│ │ │ Engine │ (via rsyslog)
│ ・Block │←── WebSocket ──│ ↓ │
│ Execution │ (block cmd) │ Send Command │
│ Only │ │ │
└──────────────┘ └──────────────┘
↑ ↑
Agent cannot do more Cross-reference with
than blocking even if lying raw logs; discard event
if mismatch4. 驗證引擎 —— 將 Agent 事件與原始日誌交叉比對 #
驗證引擎是一套機制,用來獨立驗證從 Agent 送達的事件是否為「事實」。
來自 Agent 的事件範例(攻擊偵測通知):
{
"agent_id": "dmz-web-01",
"event_type": "vuln_scan_detected",
"src_ip": "203.0.113.42",
"target": "/.env",
"timestamp": "2026-05-13T10:23:45+09:00",
"evidence_lines": [
"203.0.113.42 GET /.env HTTP/1.1 404",
"203.0.113.42 GET /.git/config HTTP/1.1 404",
"203.0.113.42 GET /wp-admin HTTP/1.1 404"
]
}接收到此事件後,AI-SLOG 會透過以下步驟進行驗證:
- 取得原始日誌:來自相關 DMZ 伺服器的 Apache/Nginx 日誌,早已透過 rsyslog 另行取得
- 搜尋相關時間戳附近:在事件時間戳前後 ±30 秒的範圍內,搜尋來自同一 IP 的請求
- 與 evidence_lines 交叉比對:驗證 Agent 所聲稱的三行內容是否確實存在於真實日誌中
- 不符則捨棄:只要有一行不吻合,該事件即會被視為「可能為偽造」而遭捨棄,並發出警告
若 Agent 誠實運作,evidence_lines 便會與實際日誌相符,順利通過驗證。即使 Agent 遭攻擊者入侵並送出偽造事件,透過與原始日誌交叉比對,也能輕易將其過濾掉。
重點在於原始日誌的取得路徑與 Agent 事件的傳送路徑是完全分離的。透過 rsyslog 的日誌轉送,是在與 Agent 程序不同的獨立路徑上運作,即使攻擊者掌控了 Agent,也無法竄改內部端的 rsyslog 接收機制。
5. Agent 權限設計 —— 將可執行能力最小化 #
賦予 Agent 本身的權限,同樣被縮減至絕對必要的最小限度。
| 操作 | 權限 | 備註 |
|---|---|---|
| IP 封鎖(ufw deny 等) | 允許 | 伺服器防禦所必需 |
| 解除 IP 封鎖(ufw delete 等) | 禁止 | 防止攻擊者自行解除封鎖 |
| 設定檔編輯 | 禁止 | 防止 config.yaml 遭改寫的攻擊 |
| 執行外部 shell 命令 | 禁止 | 依 config.yaml 中的白名單 allowed_commands 限制 |
| 存取其他伺服器 | 禁止 | 防止橫向移動 |
特別重要的是「Agent 無法自行解除封鎖」這項設計。即使攻擊者掌控了 Agent,也無法解除自己 IP 的封鎖以再次進入。
那麼,若正當使用者遭到誤判,又該如何解除封鎖呢?這是透過兩條路徑來解決:後文將說明的「24 小時後自動失效」,以及來自 AI-SLOG 端的手動解除封鎖指令。
6. 心跳凍結機制 —— 靜止不動時的安全裝置 #
前文提到不能信任「Agent 若保持沈默即代表安全」這個前提。那麼 BASTION 實際上是如何處理 Agent 停止運作的情況呢?
每個 Agent 會定期向 AI-SLOG 發送心跳(heartbeat)。當此心跳中斷達一定時間後,BASTION 會執行以下動作:
- 凍結來自該 Agent 的所有新事件(不加以處理直接捨棄)
- 透過 Slack 通知維運人員
- 在 Agent 重新啟動且心跳恢復之前,停止接受事件
這是針對「Agent 靜默的同時持續發送偽造資訊」這類情境的對策。可以想像攻擊者或許會只持續發送心跳,同時停止實際的日誌轉送,但在這種情況下,另一條獨立的 rsyslog 路徑便能偵測到「日誌突然中斷」的異常。
換言之,我們刻意準備了多條路徑來判斷 Agent 的狀態。
7. 24 小時自動失效機制 —— 防止封鎖永久化 #
由 Agent 執行的封鎖動作(ufw deny 等)被設計成會在經過 24 小時後自動失效。
# Agent-side cron.hourly
/opt/bastion-agent/bastion-ufw-prune.sh
# → Judge elapsed time from timestamp embedded in ufw comments
# → Delete entries exceeding 24 hours with ufw delete
# → Do not wait for unblock instruction from AI-SLOG (autonomous local operation)此設計背後有三個用意:
- 防止誤判持續存在:即使因誤判而暫時遭到封鎖,也會在 24 小時後自行恢復
- Agent 不需要解除封鎖的權限:透過自動失效機制,便不必授予 Agent 解除封鎖的權限
- 降低對 AI-SLOG 的依賴:失效處理是在 Agent 端本地完成,即使 AI-SLOG 停機也不會有問題
若同一名攻擊者在 24 小時後再次來襲,也會自然而然地再度被偵測並封鎖。只要攻擊者持續活動,封鎖便會持續發揮作用。
8. 實作決策 —— 為何選擇 WebSocket #
Agent 與 AI-SLOG 之間的通訊是以 WebSocket 實作。以下分享其中的理由。
| 選項 | BASTION 的決策 |
|---|---|
| HTTP POST(Agent → AI-SLOG) | 未採用。需要另一條路徑來回傳指令 |
| MQTT | 未採用。新增 broker 會增加維運負擔;在封閉網路中屬於過度設計 |
| gRPC | 未採用。協定定義的維運負擔較大,除錯也較困難 |
| WebSocket(雙向) | 已採用。可在單一連線中進行雙向通訊,支援 TLS,與 HTTP 相容 |
特別重要的是,「Agent → AI-SLOG 的事件傳送」與「AI-SLOG → Agent 的封鎖指令」能夠在單一連線中處理。這簡化了跨越防火牆的通訊,大幅降低了維運負擔。
此外,由於能以 HAProxy 等標準的反向代理伺服器終止連線(與 HTTP 的語意相同),因此 TLS 終止與身分驗證整合都能沿用既有資產。
9. 設計上的取捨與限制 #
坦白說,這套機制也存在其限制。
1. 驗證引擎的運算成本:由於每個 Agent 事件都需要與原始日誌進行交叉比對,處理時間會隨事件量增加而上升。BASTION 將 evidence_lines 限制在 3-5 行,並以時間窗縮小搜尋範圍,以控制成本。
2. 原始日誌取得路徑的冗餘性:驗證引擎使用透過 rsyslog 取得的日誌,但若 rsyslog 本身停止運作,便無法進行驗證。為因應此問題,另外實作了 rsyslog 的健康監控機制,一旦停止便會立即發出警報。
3. 驗證邏輯的透明度:若公開詳細的驗證邏輯,攻擊者便可能藉此設計出能規避驗證的偽造事件。因此,具體的驗證演算法細節並未公開(本文僅說明其概念)。
4. 解除封鎖的維運負擔:由於 Agent 不具備解除封鎖的權限,若要立即解除誤封鎖,就必須由 AI-SLOG 端進行操作。這意味著只能「忍受 24 小時,或由維運人員手動介入」。
這些都是源自於「不信任已遭入侵的 Agent」這個根本前提,不可避免的取捨。此設計刻意將天平傾向安全性,而非便利性。
10. 實際維運中的效果 —— 我方環境中的驗證結果 #
BASTION 的 DMZ Agent 目前已在三台公開網頁伺服器上正式上線運作。截至本文撰寫時:
- Agent 遭拒絕的事件數:0(因驗證而遭捨棄的事件=所有事件皆為合法事件)
- Agent 心跳異常次數:0(心跳中斷次數為零)
- 誤封鎖事件數:0(未曾封鎖過公司 IP/合作夥伴 IP)
- 因 24 小時失效機制而發生的非預期解除封鎖:0(一切皆如預期運作)
這是「Agent 誠實運作,因此驗證得以通過」的狀態,而不信任模型真正的價值,唯有在遭到入侵時才會顯現。它在平時默默運作,並在事件發生時保護維運人員。
11. 未來展望 #
Agent 與驗證引擎目前雖已投入實際運作,但仍有改善的空間。
- 移植至 Go 語言:將目前以 Python 實作的 Agent 移植至 Go,實現單一二進位檔部署(簡化在客戶環境中的部署作業)
- 簽章驗證:新增 Agent 二進位檔的簽章驗證,以及啟動時的自我驗證邏輯
- 稽核日誌區塊鏈化:實作驗證引擎判斷歷程的防竄改記錄機制(供客戶稽核之用)
- 多重驗證路徑:不僅限於 rsyslog,也結合 SNMP 與網路流量資訊,實現多層次驗證
這些項目將依序逐步實作。
12. 相關文章 #
- 多層關聯式行動偵測機制 —— 由 Agent 偵測出的初步事件,如何被判斷為整體攻擊行動
- 將 BASTION 從「資安產品」推向「AI 維運平台」 —— BASTION 整體的演進歷程
- 即將推出 使用本地 LLM 進行基礎設施日誌自動分析
- 即將推出 LLM 幻覺稽核機制的實作
13. 聯絡我們 #
若貴公司正考慮導入 BASTION,或對共同驗證計畫有興趣,歡迎透過聯絡表單與我們聯繫。
對於擁有 DMZ 或隔離環境的客戶而言,本文所介紹的 Agent 不信任模型,將成為重要的競爭優勢。我們將依貴公司的需求範圍,提供個別報價的提案。