防護欄
防護欄是 Bromure Agentic Coding 在主機端對工作區憑證使用方式的控管機制。正如此窗格本身所述:防護欄用於管控此工作區所設定憑證的使用方式。使用前詢問會在某憑證於工作階段中首次被使用時,於主機端彈出確認對話框。寫入政策則會在傳輸過程中剝除或封鎖破壞性操作——由代理伺服器強制執行,因此 VM 內遭入侵的代理程式無法繞過它。此處只會顯示你已設定的憑證。
此窗格每個已設定的憑證顯示一列,順序與憑證窗格列出的順序相同。每一列會顯示該憑證的標題與主機,並附有兩項控制項:
- 一個使用前詢問核取方塊(在控制項本身標示為需經核准才能使用)——各憑證專屬的同意閘門,已從憑證窗格移至此處。
- 一個內嵌的寫入政策選擇器,僅在該憑證的服務支援時顯示。
若工作區沒有任何憑證,此窗格會顯示空白狀態——沒有可防護的憑證——引導你回到憑證窗格。強制執行細節、錯誤格式與稽核軌跡,請見提示注入與防護欄深入解析。
使用前詢問
每一列都有一個使用前詢問核取方塊,預設為關閉。啟用後,該憑證於工作階段中首次被使用時,代理伺服器會暫停並彈出同意對話框,提供有時限的授權——5 分鐘、1 小時,或本工作階段剩餘時間——或選擇不允許。授權僅存於記憶體中,並在工作階段視窗關閉時清除,而每一項即時決定都會列於 Window → Credential Approvals…。同意模型、並行提示的合併,以及核准視窗,皆於憑證與傳輸邊界中說明。
此核取方塊適用於任何憑證,包括純 API 金鑰、SSH 金鑰與手動權杖——沒有寫入政策的列只會顯示這一項控制項。
寫入政策
當某憑證的服務能夠分類自身流量時,該列還會顯示寫入政策選擇器。它會在下列情況出現:
- Git 託管服務——GitHub、GitLab、Bitbucket 權杖。
- AWS 憑證。
- DigitalOcean 權杖。
- 容器登錄檔(Docker Hub、ghcr.io 等)。
- Kubernetes 環境。
- 資料庫端點(MongoDB、ClickHouse、Elasticsearch)。
每個寫入政策都提供相同的四種模式:
| 模式 | 行為 |
|---|---|
| 關閉 | 不進行過濾。 |
| 寫入前詢問 | 讀取直接放行。每次寫入都會暫停,彈出主機端同意對話框顯示確切的操作,並提供有時限的授權(見下文)。 |
| 封鎖破壞性操作 | 刪除、drop 與終止操作會遭封鎖;建立與更新則放行。 |
| 唯讀 | 每一項變更都會遭封鎖;只有讀取放行。 |
新工作區在所有支援政策的服務上皆預設為寫入前詢問(透過偏好設定範本)。在防護欄功能出現之前建立的工作區——或 JSON 中省略此欄位的設定檔——會解讀為關閉。
附註: 寫入政策是各服務專屬,而非各憑證專屬。同一服務的兩個憑證——例如兩個 GitHub 權杖——共用同一項政策,因此在任一列變更選擇器都會同時影響兩者。
附註: 防護欄會分類操作;它並不會隱藏憑證。憑證本身仍會依憑證下的設定,由代理伺服器注入與替換。將唯讀寫入政策與同一列的使用前詢問核取方塊結合使用,可達到縱深防禦。
各服務如何分類呼叫
| 服務 | 範圍 | 分類方式 |
|---|---|---|
| Kubernetes | 此工作區各 kubeconfig 中的 Kubernetes API 伺服器 | GET/HEAD/OPTIONS = 讀取;DELETE = 破壞性(含 deletecollection);其他動詞 = 寫入。遭封鎖的呼叫會回傳 Kubernetes Status 403 JSON,kubectl 可以清楚呈現。 |
| AWS | 所有 *.amazonaws.com 主機 | 取自 X-Amz-Target 標頭的動作名稱(JSON 協定服務,如 DynamoDB 與 Lambda)或 Action= 表單參數(查詢協定服務,如 EC2、IAM、SQS),依前綴分類:Delete*/Terminate*/Remove*/Purge*/Destroy*/Deregister*/Revoke* = 破壞性;Get*/List*/Describe* 及類似者 = 讀取。對 S3 與 REST 樣式的請求則回退至 HTTP 方法判斷。遭封鎖的呼叫會回傳 AccessDeniedException 主體。 |
| DigitalOcean | api.digitalocean.com 與 *.digitalocean.com | HTTP 方法:DELETE = 破壞性;GET/HEAD = 讀取。 |
| 容器登錄檔 | 在憑證下設定的登錄檔,以及 Docker Hub 端點 | 拉取(GET)= 讀取;推送(PUT/POST)= 寫入;DELETE = 破壞性。遭封鎖的呼叫會回傳登錄檔樣式的 DENIED 錯誤主體。 |
| GitHub | github.com REST API 及透過 HTTPS 的 git | REST 依方法判斷。git push(git-receive-pack)算作寫入——在唯讀下遭封鎖,在寫入前詢問下會提示;git fetch(git-upload-pack)一律為讀取。 |
| GitLab | gitlab.com REST API 及透過 HTTPS 的 git | 分類邏輯與 GitHub 相同。 |
| Bitbucket | bitbucket.org REST API 及透過 HTTPS 的 git | 分類邏輯與 GitHub 相同。 |
資料庫端點依引擎分類:
| 引擎 | 讀取 | 寫入 | 破壞性 |
|---|---|---|---|
| MongoDB(Atlas Data API) | find、findOne、aggregate | insert、update、replace | deleteOne、deleteMany |
| ClickHouse | 前導關鍵字為 SELECT、SHOW、DESCRIBE、EXPLAIN、WITH … 的 SQL | INSERT、CREATE、ALTER、… | DROP、TRUNCATE、DELETE,以及 ALTER … DELETE / DROP COLUMN / DROP PARTITION / CLEAR |
| Elasticsearch | _search、_msearch、_count、_mget、_sql 及其他查詢端點(即使透過 POST) | _bulk、_update、文件索引 | DELETE 與 _delete_by_query |
當政策已設定但沒有可套用的範圍時——某 Kubernetes 環境沒有 kubeconfig、某資料庫端點沒有設定主機——會顯示橘色內嵌警告,因為此時防護沒有可套用的主機。
附註: 對於 ClickHouse,若請求中看不到 SQL 文字,唯讀會封鎖該請求(Bromure 無法證明它是讀取),而封鎖破壞性操作則會放行(採寬鬆放行原則)。
同意對話框(寫入前詢問)
在寫入前詢問模式下,讀取會靜默放行,而每次寫入都會暫停,彈出標題為 Allow write on "<scope>" from workspace "<name>"? 的主機對話框。對話框內容會逐字顯示確切的操作——資料庫的字面 SQL 陳述式,或 REST 呼叫的 METHOD /path——因此你核准的是實際將執行的內容,而非摘要。按鈕包括:
- 允許 15 分鐘(預設按鈕)
- 允許一次——刻意不建立任何授權,因此下一次寫入會再次提示。適合用來逐次稽核一個頻繁寫入的代理程式。
- 允許本工作階段剩餘時間
- 不允許——代理程式會收到與封鎖模式相同的硬性錯誤。此拒絕會記憶 60 秒,如此一來反覆重試同一寫入的代理程式便不會每秒重新提示一次。
授權的範圍以各工作區與各協定範圍界定:單一 Kubernetes API 主機、整個 AWS、單一容器登錄檔、整個各 git 託管服務,或單一資料庫主機。在某主機上允許 ClickHouse 寫入,不會授權其他任何地方。並行的相同寫入會合併至單一對話框,且所有決定僅存於記憶體中——工作階段範圍的授權會在工作階段拆除時清除。
當工作區透過 SSH 或 CLI 以無頭方式驅動時,會在工作區的 tmux 內以文字提示形式提供相同的四個選項;不作答即視為拒絕。
附註: 防護欄的寫入授權不會列於任何視窗中。Credential Approvals 視窗(Window 選單 → Credential Approvals…)僅顯示憑證同意決定——即使用前詢問授權;寫入政策授權會依其自身時鐘或在工作階段拆除時到期。
連外防火牆
在憑證各列的下方,此窗格容納了工作區的 Outbound connections 防火牆:一份有序的規則表格,管控 VM 究竟可以開啟哪些連線——任何通訊協定、任何目的地,而不只是防護欄會分類的那些服務。規則由上而下比對,第一個相符者勝出;一個分段式的 Unmatched traffic 控制項則為所有未被任何規則相符的流量選定預設行為:Allow(新工作區的預設值),或 Deny 以採取鎖定式的允許清單姿態。
每條規則有五個部分:
| 欄位 | 值 | 意義 |
|---|---|---|
| Action | allow / deny | 相符的流量會發生什麼事。 |
| Proto | tcp / udp / web / any | web 指的是 TCP 上的 HTTP(S)——唯一其規則還能限制請求方法的通訊協定。 |
| Host / CIDR | any、一個主機名稱,或一個 IPv4 CIDR | 主機名稱以後綴比對:example.com 涵蓋頂點網域與所有子網域;*.example.com 只涵蓋子網域。單獨一個 IP 視為 /32。 |
| Ports | any、單一連接埠、範圍(8000-8999)或清單 | 留空代表任意連接埠。 |
| Methods | HTTP 動詞,僅限 web 規則 | 搭配 allow 時是允許清單(GET,POST——只有這些動詞能通過);搭配 deny 時是封鎖清單(PUT,DELETE——這些動詞被拒絕,其餘皆通過)。read-only 是 GET/HEAD/OPTIONS 的簡寫。 |
底部的可展開區塊會以正規的 pf 格式 顯示同一組規則——每行一條規則,並以 default allow 或 default deny 結尾——這正是規則的儲存方式,也是 CLI 與受管理設定檔所攜帶的形式:
allow tcp api.github.com:443
allow web api.example.com GET,POST # 只有這些動詞能抵達該網站
deny web api.internal PUT,DELETE # 封鎖這些動詞,其餘放行
deny udp any:53
deny any 10.0.0.0/8
default deny
強制執行位於主機端且分層進行,因此遭入侵的代理程式無法繞過它:虛擬網路交換器依目的地 IP 與 DNS 側錄取得的主機名稱,對每一條流量套用規則(涵蓋所有通訊協定,包括純 TCP 與 UDP);而 MiTM 代理伺服器則依 TLS 伺服器名稱、以及針對 web 規則依個別 HTTP 方法,再套用一次。正是這個方法維度,讓工作區能夠讀取一個它無權寫入的 API:allow web api.example.com GET,POST 在傳輸層給予代理程式查詢能力而無變更能力,無論 VM 內是哪個工具發出該請求。
規則的變更會 立即套用至執行中的工作階段——儲存工作區即可更新即時政策而無須重新開機,無頭工作階段亦然。每一項判定都會記錄為 Security Timeline 視窗中的一列 Firewall 紀錄;在已註冊的安裝上,則會成為組織串流中的一個 egress.firewall 事件。
附註: 本機推論在設計上即為豁免:針對主機上推論端點(
bromure.llm)的一條allow規則會被前置到你的規則之前,因此即使是default deny也無法切斷代理程式與本機模型的連線。該流量絕不會離開你的 Mac。
透明攔截
若 VM 可以直接忽略代理伺服器,防火牆便只具建議性質;因此它現在無法再這麼做:虛擬交換器會 透明地將 VM 的連接埠 80 與 443 流量導入主機代理伺服器——不需要任何環境變數,客體也沒有任何東西可以取消設定。連接埠 80 上的純 HTTP 會與 HTTPS 一樣被攔截並檢查。此功能對每個工作區皆預設啟用。
逃生出口是規則表格下方的 Disable transparent interception 切換。開啟它會讓交換器停止導流 :80/:443,於是防護欄與防火牆的 web 規則就只看得到那些自願使用代理環境變數的流量——請僅在某個工作區確實會因攔截而故障時使用(例如內建放行清單未涵蓋的大量憑證釘選),並在其開啟期間把防火牆視為僅具建議性質。
呼叫遭封鎖時代理程式看到的內容
遭封鎖的呼叫會回傳與協定相符的 403 樣式錯誤主體——Kubernetes Status JSON、AWS AccessDeniedException、登錄檔 DENIED 酬載——其訊息結尾為「blocked by Bromure Guardrails」。代理程式看到的是一個乾淨、普通、可回報的 API 失敗,而非懸而未決的連線。(供應鏈封鎖改用 HTTP 451,正是為了讓兩者能一眼區分——見供應鏈。)