沙盒原則、客體沙盒與核心哨兵
每台機器本來就在傳輸邊界之後執行:代理程式手上只有替身憑證,它送出的一切都會經過 Mac 上 Bromure 的代理伺服器與虛擬交換器(見憑證與傳輸邊界)。沙盒原則決定一台機器還能做什麼——它的 VM 可以連到哪裡,以及(如果你願意)它的代理程式在 VM 裡可以碰什麼。一台機器(在設定編輯器中即工作區)在設定 › 沙盒原則中從兩種沙盒引擎擇一:
| Bromure Firewall | OpenShell + Sentry | |
|---|---|---|
| 你要寫的 | 一張有順序的允許/拒絕規則表(pf 風格),可選擇預設拒絕 | 一份 NVIDIA OpenShell 沙盒政策(YAML,結構描述 v1) |
| 未匹配流量的預設 | 允許(或拒絕) | 拒絕 |
| 請求檢查 | 每台主機的 HTTP 方法(web 規則) | REST、WebSocket、GraphQL、MCP 與 JSON-RPC,逐一請求,採 enforce 或 audit |
| VM 內部 | 無 | 客體沙盒(檔案系統、處理程序、二進位檔)、核心哨兵、沒有 root 的套件 |
| 解除封鎖 | 限時規則、安全性時間軸快速動作、Sandbox 抽屜 | Sandbox 抽屜、位於 http://policy.local 的政策顧問 |
| 最適合 | 在不改變機器運作方式的前提下收窄它的網路 | 你想從頭到尾都受限、受監看且可稽核的機器 |
新機器一開始使用 Bromure 防火牆。兩種引擎都在代理程式碰不到的 Mac 上執行,每一項判定都是安全性時間軸中的一列。
有五項防護在任一引擎下都有效,位於防護欄 › 防護:
- 政策擋下時告知代理程式;
- 代理程式看門狗;
- 憑證嚴格模式;
- 透明攔截;
- 逐請求的不安全繞道。
Bromure 防火牆
防火牆是一份規則清單,涵蓋 VM 開啟的每一條連線:主機、IP/CIDR、協定、連接埠,以及網頁流量的 HTTP 方法。規則自上而下比對,第一個命中者說話,規則也可以關閉,或限時開啟。它在虛擬交換器上檢查(依目的地位址,以及 VM 查詢的名稱),並在代理伺服器中再檢查一次(依 TLS 伺服器名稱,web 規則還依方法)。VM 的 80 與 443 埠會被轉進代理伺服器,所以裡面的任何東西都無法自行退出。規則語法與編輯器記載於沙盒原則 › Bromure 防火牆。
OpenShell 政策
NVIDIA OpenShell 是一種把 AI 代理程式放進沙盒的開放格式:用一份 YAML 政策說明代理程式可以連到哪些端點、它的請求如何被檢查、它可以碰哪些檔案,以及哪些程式可以這麼做。Bromure 原生執行 OpenShell 政策。你可以帶來一份為 OpenShell 撰寫的政策,或從 Bromure 的入門政策開始,得到相同的判定。Bromure 的評估器已在超過 125,000 個差異測試案例中與 OpenShell 自己的評估器比對,沒有任何不一致。
在機器設定中選擇 OpenShell + Sentry,會載入你組織的預設政策,或入門政策(GitHub、唯讀的 npm 與 PyPI、Ubuntu 的套件鏡像站),並開啟核心哨兵。從此之後,除非有 network_policies 規則允許,否則一律拒絕。
政策在哪裡執行
| 在哪裡 | 決定什麼 |
|---|---|
| 虛擬交換器 | 每一條連線,依位址與連接埠(所有協定),並在開啟 Enforce binaries 時依開啟它的程式。 |
TLS 伺服器名稱/HTTP Host | 一條連線屬於哪個端點,包括略過代理設定的連線。 |
| 代理伺服器 | 經由 HTTPS_PROXY 建立的連線。 |
| 每個請求 | 帶有 protocol(rest、websocket、graphql、mcp、json-rpc)的端點會逐一請求檢查:方法與路徑(access: read-only、read-write、full,或明確的規則與 deny_rules)、查詢參數、GraphQL 操作、MCP 工具與 JSON-RPC 方法。enforcement: enforce 會封鎖;audit 會記錄並放行。 |
有些目的地不論政策怎麼寫都會被拒絕:
- 迴路、鏈路本機與雲端中繼資料位址;
- Kubernetes 控制平面的連接埠(2379、2380、6443、10250、10255)。
私有範圍(10/8、172.16/12、192.168/16、100.64/10)只能透過精確的主機名稱或 allowed_ips 連到。網路規則會立即套用到執行中的機器。檔案系統、處理程序與哨兵的設定在下次 VM 啟動時生效。
被拒絕的請求會收到帶有 OpenShell 自己 policy_denied 內文的 HTTP 403,所以懂 OpenShell 的工具與代理程式會有同樣的反應。
Bromure 自動加入的規則
機器仍然必須連得到它的代理程式的模型提供者、它的憑證所屬的主機、它的 Kubernetes 叢集、AWS,以及它的本機模型。如同 OpenShell 的提供者規則,Bromure 會為這些加入 _provider_… 規則。它們列在 Governance 卡片的 Rules Bromure adds automatically 之下,且不包含在輸出的政策中。
OpenShell 下的憑證
Bromure 的憑證保護沒有改變:VM 持有的是替身,真正的值在傳輸上換入,而且只針對該憑證自己的主機。OpenShell 機器的憑證窗格中多了兩項:
- OpenShell 提供者設定檔——匯入一份設定檔(
openshell profile export),輸入它的值,每個值都會成為綁定到設定檔主機與路徑的機器憑證,設定檔的端點則以規則的形式加入。 - Use OpenShell credential placeholders——代理程式看到的是
openshell:resolve:env:NAME,而不是 Bromure 那種以假亂真的權杖,就像在 OpenShell 下一樣。
政策自己的憑證欄位(credential_binding、credential_signing 等)會被忽略並附上警告:Bromure 會把每個憑證綁定到它的主機,並自行簽署 AWS 請求。
與 OpenShell 的差異
Bromure 遵循 OpenShell 的語意,但有幾處刻意的差異:
- **沒有
filesystem_policy,就沒有檔案系統沙盒。**少了這個區段的政策不會限制 VM 的檔案;OpenShell 則會把代理程式限制在它的工作資料夾中。 - **
binaries需要 Enforce binaries。**沒有它時,binaries只是參考,編輯器也會如此警告:代理程式在 VM 中持有 root,所以處理程序的身分不可信。 - **中介軟體。**只有內建的
openshell/regex中介軟體在redact模式下會執行。外部中介軟體會依它的fail_open/fail_closed被放行或封鎖。 - **提供者設定檔。**會
refresh或使用token_grant的憑證,會被當成靜態值使用。 - **Seccomp。**過濾器經過調整,讓 VM 的終端機中可以使用工作控制。
客體沙盒
網路政策限制 VM 可以連到哪裡。客體沙盒則限制代理程式在 VM 裡可以做什麼。它來自政策的三個部分:
| 政策區段 | Bromure 套用什麼 |
|---|---|
filesystem_policy(+ landlock) | 代理程式只能讀寫政策列出的路徑,以 Linux Landlock 執行——連 VM 中的 root 都無法解除。landlock.compatibility: best_effort 在路徑無法使用時會降級;hard_requirement 則失敗即關閉。 |
process(run_as_user、run_as_group) | 代理程式以那個帳號執行,沒有 sudo 或 Docker。它仍把 /home/ubuntu 當成家目錄,所以它的設定照樣適用。 |
| Enforce binaries(嚴格沙盒) | VM 中一個屬於 root 的證明程式會把每條連線歸屬到建立它的程式,而規則的 binaries 必須點名它。每個程式的雜湊值在首次使用時固定下來,被改動過的二進位檔會被拒絕。為了讓這份回報可信,代理程式會失去每一條通往 root 的路:沒有 sudo、沒有 Docker,所有流量都經過透明攔截。 |
每個部分只有在存在時才會套用。沒有 filesystem_policy 也沒有 process 區段的政策,在 VM 中什麼也不限制。有 process 區段就會自動開啟 Enforce binaries。
| 設定組合 | 你得到什麼 |
|---|---|
| 只有網路政策 | 網路受限;VM 不受限。 |
有 filesystem_policy,二進位檔未強制 | 檔案受限,即使面對 root 也一樣。sudo 仍可使用,所以代理程式可能停掉 Bromure 在 VM 中的輔助程式——Sandbox 卡片會對此發出警告。 |
Enforce binaries,或有 process 區段 | 檔案、系統呼叫與權限都受限。代理程式無法成為 root,也無法干擾 Bromure 的處理程序。 |
Bromure 會加入它自己的管線所需的少數路徑,除非必須寫入,否則都是唯讀,並列在 Sandbox 卡片上(Added for Bromure: …):
- 終端機的 socket;
- meta 共用資料夾;
/proc;- DNS 設定;
- 位於
/usr之外的代理程式安裝資料夾(Grok 在/opt/grok,Oh My Pi 的執行環境在/opt/bun)。
它們永遠不會被併入你自己的清單。
失敗即關閉
沙盒永遠不會悄悄退回到不受限的執行:
- 如果嚴格沙盒沒有完全套用,就不會啟動任何工作階段,二進位檔規則會拒絕一切,Sandbox 卡片也會以紅色說明。重新啟動 VM 會再試一次。
- Bromure 替你在機器中執行的指令——終端機、
vm exec、檔案操作、git、規劃器——會等沙盒就緒(單純的指令等 90 秒)。若沙盒沒有就緒,指令會以sandbox unavailable: …失敗。 - Bromure 自己在機器中呼叫的 git 一律在受限狀態下執行,因為儲存庫可以讓 git 指向它所選的任何程式。
沒有 root 的套件
受限的代理程式沒有 root,所以全系統的安裝行不通。Sandbox 卡片上的兩個開關(預設都開啟)讓安裝仍能運作:
-
Packages in the home folder——
pip install會裝到~/.local(npm 本來就全域安裝到~/.npm-global)。Bromure 自己在 VM 中的處理程序會忽略家目錄中的套件,所以代理程式無法在其中植入程式碼。 -
System packages on request——當代理程式執行
apt-get install(不論有沒有sudo),請求會等你決定,而不是失敗。代理程式看到:bromure: this sandbox has no root. Asked the user to approve installing: libpq-dev bromure: waiting for their decision (Sandbox drawer › Proposals)…打開 Sandbox 抽屜的 Proposals 分頁,選擇Install或 Reject。核准的套件由 VM 的 root 監督程式從 Ubuntu 鏡像站安裝,而且只依精確名稱:不接受選項、檔案路徑、
.deb檔,也不接受 apt 會解讀成樣式或移除的名稱。被拒絕的請求會告訴代理程式不要重試。每個請求及其結果都是安全性時間軸中的一列 Guest sandbox。
核心哨兵
核心哨兵是一個小型的 Linux 核心模組,從 VM 的核心內部回報那裡發生了什麼。它透過一條私有通道回報給 Mac,代理程式無法靠終止某個處理程序讓它噤聲:
- 程式啟動;
- 連線,以及每條連線背後的處理程序鏈;
- 權限變更;
- 模組與 BPF 載入;
- 客體沙盒拒絕的一切。
哨兵啟動之後,核心會被鎖定,連 VM 中的 root 都無法載入程式碼來干擾。
有了哨兵,以下這些才得以實現:
- 網路溯源鏈——每條連線是由哪個提示、哪個工具呼叫、哪個處理程序建立的。
- 時間軸與 Sandbox 抽屜 Files 分頁中的沙盒拒絕。
- 竄改偵測——哨兵編號串流中的缺口、被解除的探針、偽造的重新連線、未簽署模組的載入,或被調低的 lockdown,都會以紅色標為 tampering suspected,並送進代理程式看門狗。
- Enforce binaries 所需的二進位檔身分。
它有兩種模式,在 Kernel sentry 卡片中設定:
| 模式 | 開機時 | 哨兵無法載入時 |
|---|---|---|
| Best effort | 哨兵在背景載入;工作階段不會等它。 | 機器在沒有哨兵的情況下執行,卡片會說明原因。 |
| Required | 在哨兵就定位之前,VM 中什麼都不會執行。核心會被進一步鎖定,因此也排除了 bpftrace 與 perf 這類核心追蹤工具。 | 如果 VM 說明了原因(例如它的核心沒有對應的模組),機器會在沒有哨兵的情況下啟動,並附上警告。始終沒有連上、也沒有說明的哨兵會被視為竄改。 |
你的組織可以要求最低模式。機器會以兩者中較嚴格的那個執行。
隨需提供的模組
核心模組只能載入到它所編譯的那個確切核心,而機器隨時都可能透過 apt upgrade 換到新的 Ubuntu 核心。所以模組不隨應用程式一起提供。Bromure 每天為每個 Ubuntu 核心編譯模組,並發布在 dl.bromure.io。目錄與每個模組都有簽章,Bromure 會驗證簽章、總和檢查碼,以及目錄不比它已有的版本舊。
- 啟動時,Bromure 會抓取你的機器已知會執行的核心所需的模組,並在每次開機前準備好。
- 當 VM 以 Bromure 沒見過的核心開機時,VM 會提出請求,Bromure 會抓取模組並在幾秒內交給它。
- 若該核心還沒有任何模組,VM 會立刻得知,卡片會顯示 Couldn't start: no module published for 核心 yet。請一天後再試,或以前一個核心開機。
下載的模組保存在 ~/Library/Application Support/BromureAC/sentry-modules/。
Sandbox 抽屜
每台機器的視窗在工具列上都有一個盾牌按鈕(「Sandbox: what it blocked, ready to allow」)。它會在舞台上方打開 Sandbox 抽屜。你也可以按 ⌃⌘N,或選擇顯示方式 › Toggle Sandbox Drawer。按鈕上的紅色標記會計算自你上次查看以來被封鎖的目的地數量。抽屜會列出機器的沙盒在過去兩小時內拒絕的東西,隨時可以允許:
| 分頁 | 引擎 | 內容 |
|---|---|---|
| Network(防火牆下為 Blocked) | 兩者 | 每個被封鎖的目的地,附嘗試連線的程式(若已知)、次數與時間。Allow 會為該主機與連接埠加入一條規則。在防火牆下,它提供永遠、15 分鐘、1 小時或直到工作區停止。在開啟 Enforce binaries 的 OpenShell 下,規則會點名嘗試連線的程式。 |
| Files | OpenShell,且有 filesystem_policy | 檔案系統沙盒拒絕的東西,依資料夾分組,附操作與檔案。Allow 會以唯讀、Read and write,或只針對那個檔案加入該資料夾。檔案存取在下次啟動時才改變:會出現一張重新啟動卡片。 |
| Proposals | OpenShell | 套件請求(Install / Reject),以及政策顧問正等你決定的規則(Approve / Reject)。 |
| Temporary | 防火牆 | 限時開啟的規則,附結束時間,以及 End。 |
從抽屜加入的規則會儲存到機器並立即生效。它們和其他任何編輯一樣,會與你的組織邊界比對。底部的 Sandbox Policy… 會打開機器的設定。
政策顧問
碰壁的代理程式通常很清楚自己需要什麼。在 OpenShell 下,它可以開口要求:當請求被擋下時,代理程式可以向 OpenShell 的顧問 API http://policy.local 提出能允許該請求的最窄規則,並等待你的決定。它收到的 403 會告訴它怎麼做。你在沙盒原則 › Policy advisor › Agent proposals 中選擇它能做到什麼程度:
| 模式 | 會發生什麼 |
|---|---|
| Off(預設) | 代理程式不能提出規則。被封鎖的連線仍會為你草擬成提案。 |
| Ask me | 每個提案都會在 Sandbox 抽屜與 Policy advisor 卡片中等候,直到你 Approve 或 Reject。拒絕的理由會送回給代理程式。 |
| Approve if risk-free | 沒有風險發現的提案會立即核准。連到機器持有憑證的主機、在那裡增加方法,或使用萬用字元、私有位址、資料庫連接埠或高號連接埠的提案,一律等你決定。會超出你組織邊界的提案也一樣。 |
代理程式只能提出 rest 或 websocket 規則,而且永遠不能提出 tls: skip。核准的規則會加入政策、即時生效,並保留在政策的修訂歷史中。每個提案與每項決定都是安全性時間軸中的一列 Firewall。
告知代理程式:政策引導
只看到「connection refused」或「permission denied」的代理程式,往往會重試,接著另找門路。從外面看,這就像一個失控的代理程式。開啟 Tell the agent when policy blocks it(位於防護欄 › 防護,OpenShell 機器預設開啟)時,代理程式會在它的對話中被告知擋下了什麼、為什麼,例如:
[Bromure policy] This workspace's network policy blocked connecting to
api.stripe.com:443— no network policy allowsapi.stripe.com:443. … This is a deliberate restriction, not a fault: don't retry it or reach the same thing another way … If your task needs it, stop and tell the user what you need and why so they can decide.
- Claude Code 會在碰到封鎖的那條指令之後立刻收到通知,就在回合進行中。
- Codex、Grok、Kimi 與 Oh My Pi 會在它們的回合結束後收到輸入的通知。
- 通知會利用核心哨兵的處理程序鏈,送給建立了被封鎖連線或檔案存取的那個代理程式。
- 當 Bromure 無法判斷是哪個代理程式時,網路封鎖會告知機器中的所有代理程式,檔案封鎖則只告知唯一的代理程式。
- 同一個封鎖每五分鐘只告知一次,一個代理程式每分鐘最多收到五則通知。代理程式自己的背景流量,以及常見的遙測主機,永遠不會被回報。
通知中來自 VM 的值(主機、路徑)會以資料的形式引用,所以程式無法利用封鎖來替代理程式「代言」。
代理程式看門狗
看門狗從 VM 外部,把工作階段當成一個整體來看:
- 一連串的封鎖;
- 不屬於這裡的憑證;
- 哨兵遭竄改的跡象;
- 失敗的沙盒;
- 提示注入;
- 工作階段穩定之後出現的新目的地;
- 遠高於基準的出向流量。
一分鐘內超過門檻時,它會記錄一項發現(Alert),或切斷 VM 的網路、將它暫停並詢問你要怎麼做(Quarantine)。見防護欄 › 代理程式看門狗。它預設關閉;沒有它時,竄改警報仍會記錄在安全性時間軸與 OCSF 日誌中。
組織邊界
組織可以設定一道邊界:任何機器的 OpenShell 政策所能允許的上限。在已註冊的 Mac 上它來自 bromure.io(每十分鐘更新一次,並快取供離線使用),或來自這台 Mac 上的一個檔案(沙盒原則 › Governance › Organization boundary)。每次變更政策的儲存,不論來自設定、Sandbox 抽屜、政策顧問或 API,都會與它比對。裝有 NVIDIA 的 openshell-prover 時 Bromure 會用它,否則用自己的檢查。
- 在編輯器中,輸入時會顯示綠色或紅色的判定(「within boundary」,或附上它會允許之事例的「exceeds boundary: …」),而儲存會等到政策符合為止。
- 在其他地方,超出邊界的儲存會以「outside the organization boundary — …」被拒絕。
- 先前儲存、如今已不符合的政策會失敗即關閉:只有 Bromure 自己加入的規則仍連得到。
透過同一條通道,組織還可以:
- 設定新 OpenShell 機器的預設政策;
- 要求 Enforce binaries 或嚴格憑證;
- 設定核心哨兵的最低模式;
- 為政策顧問的模式設上限;
- 要求把代理程式的推理連同網路溯源鏈一起上傳。
請見企業版。
每次變更政策的儲存,也都會連同變更來源保留在政策的 Revision history 中;還原 可以取回任何版本。