沙盒原則、客體沙盒與核心哨兵

每台機器本來就在傳輸邊界之後執行:代理程式手上只有替身憑證,它送出的一切都會經過 Mac 上 Bromure 的代理伺服器與虛擬交換器(見憑證與傳輸邊界)。沙盒原則決定一台機器還能做什麼——它的 VM 可以連到哪裡,以及(如果你願意)它的代理程式在 VM 裡可以碰什麼。一台機器(在設定編輯器中即工作區)在設定 › 沙盒原則中從兩種沙盒引擎擇一:

Bromure FirewallOpenShell + 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 抽屜:標題 Sandbox、Web app · OpenShell + Sentry、Network、Files 與 Proposals 分頁、api.stripe.com:443 與 pypi.org:443 等被封鎖的目的地(各附次數與時間、一個 Allow 按鈕與一個關閉叉號),以及底部的 Sandbox Policy… 按鈕。

每台機器的視窗在工具列上都有一個盾牌按鈕(「Sandbox: what it blocked, ready to allow」)。它會在舞台上方打開 Sandbox 抽屜。你也可以按 ⌃⌘N,或選擇顯示方式 › Toggle Sandbox Drawer。按鈕上的紅色標記會計算自你上次查看以來被封鎖的目的地數量。抽屜會列出機器的沙盒在過去兩小時內拒絕的東西,隨時可以允許:

分頁引擎內容
Network(防火牆下為 Blocked)兩者每個被封鎖的目的地,附嘗試連線的程式(若已知)、次數與時間。Allow 會為該主機與連接埠加入一條規則。在防火牆下,它提供永遠、15 分鐘、1 小時或直到工作區停止。在開啟 Enforce binaries 的 OpenShell 下,規則會點名嘗試連線的程式。
FilesOpenShell,且有 filesystem_policy檔案系統沙盒拒絕的東西,依資料夾分組,附操作與檔案。Allow 會以唯讀、Read and write,或只針對那個檔案加入該資料夾。檔案存取在下次啟動時才改變:會出現一張重新啟動卡片。
ProposalsOpenShell套件請求(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 allows api.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 中;還原 可以取回任何版本。

相關章節