一個防火牆政策是一份有序的規則清單。
本頁是一條規則能表達什麼的完整參考——
匹配語言、裁決,以及引擎如何評估它們。
規則在主控台的規則編輯器中撰寫,它會寫出結構化的
JSON 匹配物件。以下所有內容都描述了那套詞彙,讓你能
精確地閱讀、推理並驗證一條規則——無論你是在 UI 中建構它
還是透過 API 提交它。
1. 一條規則的剖析
| 欄位 | 型別 | 含義 |
|---|
priority | int | 較低者先執行。 同分時以規則 id 決定。 |
label | string | 人類可讀的名稱,顯示於 events 與 audit。 |
stage | enum | 介面——inbound / response / mcp / egress。空 = 所有介面。 |
tool_name_glob | string | 工具名稱上的 Glob。 |
skill_name_glob | string | 對擁有者技能的可選 glob。與工具 glob 進行 AND;空 = 任何技能。 |
verdict | enum | 動作——參見 §7。 |
args_match | object | 可選的引數判定式。 |
sanitize | object | 遮罩設定,當 verdict = sanitize 時使用。參見 §5。 |
egress | object | Host/CIDR 允許/拒絕清單,當 stage = egress 時使用。參見 §6。 |
cap_cost_cents | int | 執行成本上限,當 verdict = cap_cost 時使用。 |
sequence | object | 有序的多步驟匹配,以反應式強制執行。參見 §8。 |
notes | string | 作者的理由說明;會被引擎忽略。 |
當一條規則所宣告的條件全部成立時,它才匹配一次工具呼叫:
stage 匹配(或為空)、工具 glob 匹配、技能 glob
匹配(或為空)、引數子句匹配(或不存在),以及
egress 範圍匹配(僅限 egress 規則)。引擎按優先順序走訪規則,
第一個匹配者勝出。
2. 工具名稱 glob
一套刻意精簡、區分大小寫的文法——沒有正規表示式的意外、線性
時間,在中繼熱路徑上安全:
| 模式 | 匹配 |
|---|
"" 或 * | 每一個工具。 |
foo.* | 前綴——foo.bar、foo.exec(不含裸 foo)。 |
*.exec | 後綴——shell.exec、db.exec(不含裸 exec)。 |
*.shell.* | 中綴——local.shell.exec(每側都需要 ≥1 字元)。 |
| 其他任何內容 | 精確字串匹配(包括 foo.*.bar)。 |
工具依慣例以 server.tool 或 category.action 命名空間化,所以
shell.* 會捕捉一整個家族,而 *.delete 會跨伺服器捕捉一個動詞。
3. 技能名稱 glob
相同的 glob 文法,對照工具呼叫的擁有者技能進行匹配
(例如 community.*、builtin.send)。它與
tool_name_glob 進行 AND,所以:
tool_name_glob: http.fetch
skill_name_glob: community.*
只在 http.fetch 由一個 community.* 技能擁有時才匹配它——
信任來自內建技能的同一個工具,把關來自社群技能的它。
空的技能 glob 會匹配任何擁有者。一次工具呼叫如何歸因於一個
技能,在 技能 中說明。
4. 引數子句
工具名稱匹配回答的是哪個工具;引數子句回答的是帶著
什麼引數——這是「封鎖 shell.exec」與「只在命令為 rm -rf 時
封鎖 shell.exec」之間的差別。
args_match 是一組子句,全部以 AND 串接:
{
"clauses": [
{ "path": "$.command", "op": "regex", "value": "rm -rf|drop table" },
{ "path": "$.connection", "op": "in", "value": ["prod", "replica"] },
{ "path": "$.ip", "op": "cidr_match", "value": "10.0.0.0/8" }
]
}
一個空的/不存在的 args_match 為恆真——規則只憑
glob 就匹配。
運算子
| 運算子 | 何時匹配 |
|---|
eq | 純量相等(數字以數值方式比較;型別不符 → 不匹配)。 |
contains | 子字串(兩個運算元都必須是字串)。 |
regex | 一個 Go RE2 模式匹配該字串值(線性時間、無回溯參照)。 |
in | 該值是給定 JSON 陣列的一個元素。 |
cidr_match | 該字串 IP 落在給定的 CIDR 內。 |
gt / lt | 數值大於/小於(字串不會被強制轉型)。 |
Path 語法
對工具引數物件的一個小型 JSONPath 子集:
$.foo、$.foo.bar——欄位存取
$.foo[0]、$.arr[1].k——陣列索引
$——整個引數物件
沒有萬用字元、篩選器、切片或遞迴下降。
引數子句失敗關閉——關閉的是規則,不是請求。 如果某個 path
無法解析、引數格式不正確,或某個 regex/CIDR 無效,
該子句會評估為 false,規則就直接不觸發——呼叫會
落入下一條規則或預設裁決。一個損壞的子句
永不會自動拒絕,也永不會讓中繼崩潰。請把你那條「捕捉
一切危險」的規則寫成一個帶有自己 glob 的明確 deny,而不是
依賴某個子句以某種特定方式失敗。
主控台會在儲存時嚴格地驗證子句(未知運算子、錯誤的
path、非陣列的 in 值、無法編譯的 regex,以及無效的 CIDR 都
會被拒絕),因此一個格式不正確的子句從一開始就無法被持久化。
5. 淨化器
一個 sanitize 裁決會從工具引數中遮罩匹配到的子字串
並轉送清理後的呼叫——對於剝除代理放進工具引數中的密鑰或
PII 而不封鎖整個動作很有用。
{ "presets": ["email", "ssn_us"], "custom": ["foo-\\d+"] }
預設集的匹配會被替換為 [redacted:<preset>];自訂 regex
的匹配則替換為 [redacted:custom]。內建的預設集庫:
aws_access_key、aws_secret_key、openai_key、anthropic_key、
bearer_token、email、ssn_us、credit_card(帶 Luhn 檢查)。
一條 sanitize 規則必須宣告至少一個 preset 或 custom 模式——一個
空的淨化器在儲存時會被拒絕。在 inbound 介面上沒有
呼叫時引數可遮罩,所以那裡的 sanitize 裁決會升級為
封鎖。
6. egress 目的地清單
一條 egress 規則(stage egress)會對一個外送目的地匹配——
SSRF 與外洩介面:
{
"deny": ["169.254.169.254", "10.0.0.0/8"],
"allow": ["api.openai.com"]
}
各條目會以 CIDR、IP 字面值,或不分大小寫的主機名稱匹配;
主機名稱會盡力解析並重新對照 IP/CIDR 條目檢查。
極性遵循裁決:在 allow 裁決下,allow 清單
定義什麼在範圍內,而 deny 從中刻出例外;在一個
強制執行的裁決(deny)下,deny 清單定義什麼被封鎖,而
allow 刻出例外。
169.254.169.254(雲端中繼資料端點)與 RFC-1918 範圍是
最典型該拒絕的事物——block_ssrf_egress 預設集與
tight 自主等級
出貨的正是這個。
7. 裁決
| 裁決 | 效果 | 備註 |
|---|
allow | 讓其通過,會被記錄。 | |
audit | 允許 + 記錄以供審查。 | 通常的 default_verdict。 |
deny | 封鎖呼叫。 | 在 inbound 上為 HTTP 400;在 mcp 上為工具錯誤。 |
sanitize | 遮罩引數,轉送。 | 需要一個淨化器;在 inbound 上升級為 deny。 |
pending_approval | 為人類保留。 | 需要已設定的審批儲存;在 response/egress 上會被拒絕。 |
cap_cost | 超過花費上限後拒絕。 | 需要一個非負的 cap_cost_cents;在 response/egress 上無作用。 |
在影子模式下,每個強制執行的
裁決都會被降級為 audit,原因會被加上前綴
[shadow] would …。
8. 序列
有些風險只在數次呼叫之間才看得見——讀取 50 筆 CRM 記錄、
然後匯出、然後觸及一個外部主機。一條 sequence 規則會匹配一條
有序的鏈,而不是單一呼叫:
{
"window_seconds": 600,
"steps": [
{ "match": "crm.*", "min_count": 3 },
{ "match": "*.export" },
{ "match": "*", "egress": true }
]
}
每個 step 是一個工具 glob,帶有一個可選的 min_count(預設 1)與一個
可選的 egress: true(該 step 必須是一次 egress 呼叫)。各 step 必須
按順序發生——與其他呼叫交錯是可以的——而整條鏈
必須在 window_seconds(0 = 無限制)內完成。
序列由一個非同步匹配器反應式地強制執行,而不是
就地在每次呼叫上——否則一個帶有 * step 的序列會匹配
每一次單獨的工具呼叫。它們會點亮 events 動態並能觸發
後續動作,但它們不會即時封鎖那個完成該鏈的
單獨呼叫。
9. 內建預設集
從一個預設集開始,而不是一條空白規則。它們在伺服器端撰寫,
所以主控台與這些文件描述的是完全相同的行為:
| 預設集 | 作用 |
|---|
block_destructive_shell | 透過一組 deny-by-glob 規則拒絕破壞性 shell 命令(rm -rf、mkfs、dd、fork bomb,……)。 |
block_ssrf_egress | 稽核到中繼資料端點與 RFC-1918 範圍的 egress。 |
block_secrets_in_args | 面向偵測——標記出現在工具引數中的憑證。 |
block_pii_in_tool_results | 面向偵測——浮現工具結果中的 PII。 |
把預設集當作起點套用,然後自由編輯——預設集是一個起點,
不是一個鎖。
10. 評估、限制與安全
- 第一個匹配者勝出。 規則按
priority ASC, id ASC 順序執行;
第一條條件全部成立的規則決定裁決。無任何規則
匹配 → 政策的 default_verdict。
- 確定性且無依賴。 Glob 與子句匹配是純字串/JSON
運算,無網路呼叫,可安全地在每一次工具呼叫上執行。Regex 是
RE2——線性時間,無災難性回溯。
- 失敗關閉的子句。 一個無法被評估的子句會使其規則
不觸發,而不是自動拒絕(§4)。
- 嚴格的儲存時驗證。 裁決/stage 配對、淨化器
非空、
cap_cost_cents 存在、子句形狀,以及 ref
解析在你儲存時全都會被檢查——無效的規則無法被
持久化。
- 受稽核。 每一次規則建立/更新/刪除都會在變更提交之後
寫入一筆稽核列;規則 blob 與密鑰永不會被寫入
稽核日誌。
API 參考
規則存在於一個政策之下且為工作區層級;寫入需要
Developer+。
| 方法與路徑 | 角色 | 用途 |
|---|
POST /api/workspace/firewall/rules | Developer+ | 建立一條規則。 |
PUT /api/workspace/firewall/rules | Developer+ | 更新一條規則(id 在主體中)。 |
DELETE /api/workspace/firewall/rules/:id | Developer+ | 刪除一條規則。 |
GET /api/workspace/firewall/presets | Member | 列出內建預設集。 |
POST /api/workspace/firewall/test | Developer+ | 對一個樣本工具呼叫乾跑一個政策(含規則)。 |
若要在依賴一條規則之前預覽它,請使用 Test——它會傳回
裁決、匹配到的規則與原因,而不派發任何東西。
延伸閱讀
想更深入了解代理安全?**保護你的代理(零信任)**指南會將此功能放入零信任工作流程中。
建立防火牆政策
逐步撰寫一個零信任政策,並在強制執行前先以影子模式驗證。
規則綱要參考
每個規則欄位——萬用字元、引數判定式、外向流量與成本上限。