那台筆電是他自己買的。公司沒有 MDM、沒有端點管理系統,IT 連 managed-settings.json 該塞到哪個路徑都推不動。可是他一開 Claude Code,Read(./.env) 就是擋著的。

這份政策是從哪裡來的?更精確一點問:它在啟動流程的哪一步到達,在它到達之前的那幾百毫秒,Claude Code 照誰的規矩在跑?

「Owner 在 claude.ai 填了一份 JSON」這句先擱著,那講的是誰按了按鈕。從 client 這一側看只有兩個動作:向 api.anthropic.com 要一份 payload,存進 ~/.claude/remote-settings.json。啟動時抓一次,session 開著的話每小時再抓一次。

骨架就這麼大。難的全在時序。

那份政策在你開機的第幾毫秒到達

抓東西要時間,而 Claude Code 不能為了等一份設定讓你盯著空畫面。文件把取捨切成兩種。

開發者在啟動時登入(第一次跑,或者剛 /logout 過),Claude Code 最多等 5 秒讓 fetch 跑完才開 session。政策及時送到,就從第一個畫面開始執行,companyAnnouncements 也會顯示在上面。

其他啟動情境,以及那 5 秒等完還沒回來,Claude Code 會先把 session 開給你,讓 fetch 在背景繼續跑。這句要讀清楚:有一小段時間,你的限制還沒生效。

fetch 失敗的話,它繼續跑、不套 server-managed settings,並在互動式 session 裡警告你沒有遠端政策。endpoint-managed settings 照樣生效,那是另一條通道。

第二次以後就有快取。快取設定在啟動時立刻生效,這是它能撐過網路失敗的原因。但有三樣不吃這一套:modelPricingmanagedMcpServers,還有「等伺服器確認才放行的環境變數」。

前兩樣的後果很具體。modelPricing 確認回來之前,/usage 跟狀態列上的成本數字是定價表價格;managedMcpServers 則讓 Claude Code 最多等 30 秒才去連 MCP server(需 v2.1.259 或更新)。

第三樣才真正有意思。

為什麼有些值要等伺服器點頭才准用

快取裡有一批環境變數,啟動時一律不套用,文件叫它 withheld(需 v2.1.198 或更新;在那之前整個快取 env 區塊都是啟動就套下去)。清單長這樣:

類別 被扣住的變數
Proxy 與 TLS HTTPS_PROXYNODE_EXTRA_CA_CERTS、mTLS 用戶端憑證變數 CLAUDE_CODE_CLIENT_CERTCLAUDE_CODE_CLIENT_KEY
API 路由與供應商選擇 ANTHROPIC_BASE_URLCLAUDE_CODE_USE_BEDROCKCLAUDE_CODE_USE_VERTEX 等供應商選擇變數、ANTHROPIC_BEDROCK_BASE_URL 等供應商端點 URL
驗證憑證 ANTHROPIC_API_KEYANTHROPIC_AUTH_TOKENCLAUDE_CODE_OAUTH_TOKEN
設定目錄選擇器 CLAUDE_CONFIG_DIR

v2.1.223 之後又追加一批:Workload Identity Federation 變數如 ANTHROPIC_FEDERATION_RULE_IDANTHROPIC_PROFILEANTHROPIC_CONFIG_DIR,以及 HOMEXDG_CONFIG_HOMEAPPDATAUSERPROFILE 這些作業系統目錄變數。

這批變數有個共同點:每一個都有能力改變「下一次 fetch 會打到哪裡、帶什麼憑證、讀哪個目錄」。它們如果從快取直接生效,就有機會重導、攔截、或重新驗證那個用來確認 payload 的 fetch 本身。

一個很乾淨的自我指涉問題。你請警衛照一份名單放行,名單是從門外送進來的;名單上如果寫著「以後改從側門收名單」,那送名單的路就被名單自己改掉了。從此警衛拿到的名單都是側門那邊的人給的,你再也沒辦法從正門糾正。

所以那批值要等伺服器確認過 payload(需要核准的話,等你核准過),才會在這個 session 剩下的時間套用,其餘 env 鍵照常在啟動時生效。另有三類更新連套用都要等重啟:OpenTelemetry exporter 設定、model 鍵,以及「從 env 區塊移除某個變數」。移除比新增難,設定系統裡向來如此。

要不要跳對話框,看的不一定是變數名

有些下發的設定會在互動式 session 裡要使用者明確核准,拒絕就退出。文件列了五類:

  • 會執行 shell 指令的設定:apiKeyHelperstatusLineotelHeadersHelper
  • 沙箱執行檔設定:sandbox.bwrapPathsandbox.socatPathsandbox.ripgrep
  • 沙箱網路與隔離設定:sandbox.network.tlsTerminatesandbox.credentialssandbox.filesystem.disabled 那一長串,只含 deny 規則的 sandbox.credentials 除外
  • 需要核准的自訂環境變數
  • 任何 hook 定義

v2.1.251 之前,沙箱那一類不經核准直接套用。

claudeMd 鍵下發的 managed CLAUDE.md 不需要核准,因為那是給 Claude 讀的指示文字,不是 Claude Code 去執行的指令(v2.1.260 之前需要)。強制啟動器那個 processWrapper 鍵推下去時,也會並列在同一個對話框上。

到這裡都還算直覺。會讓人愣一下的是環境變數那一類:要不要問,有時候比對的是值,不是變數名。

這一類的規則攤開長這樣:

變數 不用核准的值 其他非空值
四個隱私開關:CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFICDISABLE_ERROR_REPORTINGDISABLE_TELEMETRYDO_NOT_TRACK truthy(1true),只會把追蹤關掉 跳對話框
API_FORCE_IDLE_TIMEOUT truthy,只是把 body idle timeout 打開 要核准(v2.1.248 之前任何非空值都會跳)
ENABLE_BETA_TRACING_DETAILEDOTEL_LOG_RAW_API_BODIES falsy(0false 要核准

最後那一列是反過來的。

最狠的是 ANTHROPIC_CUSTOM_HEADERS。只做標記用途的標頭(像 Accept-Language)不用核准,點名憑證、org/tenant 選擇器、路由或 host 覆寫、API 行為標頭(AuthorizationX-Api-KeyHostanthropic-betaX-Amzn-Bedrock-*)則要核准。比對看的是標頭名稱裡出現了哪些字,所以 X-Client-Version 含了 clientversion,照樣要你按一次。v2.1.251 之前,這個變數不管給什麼值都不用核准。

代價是誤報。但這個位置擋的是「誰在冒充誰發請求」,寧可誤報。

拆到這裡,才輪到它能拿來幹嘛

機制清楚了,用途自己浮出來。

三個前置條件:Claude for Teams 或 Claude for Enterprise 方案、Owner 或 Primary Owner 角色(Admin 與其他非 Owner 角色看不到也改不了)、能連到 api.anthropic.com 的網路。進 Admin Settings > Claude Code > Managed settingshttps://claude.ai/admin-settings/claude-code)。連結會導到別的 Admin Settings 頁面,就代表這個帳號沒有那個角色。

settings.json 裡所有設定都支援,除了限定走 OS 層政策下發的那幾個。hooks 可以、環境變數可以、allowManagedPermissionRulesOnly 這類 managed-only 設定也可以。權限封鎖大概長這樣:

1
2
3
4
5
6
7
8
9
10
11
12
{
"permissions": {
"deny": [
"Bash(curl *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
],
"disableBypassPermissionsMode": "disable"
},
"allowManagedPermissionRulesOnly": true
}

全公司 hook 也在同一份 JSON 裡,官方範例是一個 PostToolUsematcherEdit|Writecommand 打到 /usr/local/bin/audit-edit.sh。存檔之後,client 會在下一次啟動或每小時輪詢週期收到更新。

驗收看 claude doctor 的「Managed settings (remote)」那一行(需 v2.1.248 或更新),四種結果:設定已載入、組織沒設定、fetch 失敗(含原因與「快取政策是否仍生效」)、Claude Code 跳過了 fetch(含原因),還在抓就顯示進行中。/permissions 看實際生效的權限規則;/status 在 fetch 失敗與某些 skip 原因(第三方供應商變數、shell 裡 export 的自訂 ANTHROPIC_BASE_URL)時顯示同一行。

要更細就 claude --debug-file <path> 然後搜 "Remote settings"。整包 payload 救不回來時,log 會寫 Remote settings: Settings validation failed - no fields could be salvaged

推給全組織之前,先在測試機上跑一次 claude doctor

限制有三條。設定一律套用到組織裡所有使用者,還不支援分群。不能用它發 managed-mcp.json 檔,要改用 allowedMcpServersdeniedMcpServers 政策鍵(v2.1.259 或更新版可以用 managedMcpServers 提供遠端 server,但只吃 httpsse,也不像那個檔取得排他控制權)。限定 OS 層政策來源的設定不被採納,文件點名 policyHelperwslInheritsWindowsSettings,得走 MDM 或系統 managed-settings.json

那條 deny 規則沒有你想的那麼硬

文件自己在上面那個權限範例底下附了警告,值得抄過來。Bash(curl *) 比對的是 Claude 寫出來的那個字面指令,它比對不到 /usr/bin/curl,也比對不到 sh -c 'curl …'。要做不依賴指令文字的網路管制,得改加 sandbox 區塊配 allowManagedDomainsOnly

這個形狀在權限規則的五種漏擋形態那篇拆過,不重述,要記的只有一句:換了下發通道,規則本身的脆弱程度一點都沒變,你只是讓同一條脆弱的規則出現在更多台機器上。

更難的一條:使用者可以把你的 fetch 整條拆掉

文件的定性很直白:

they operate as a client-side control, not a security boundary. On unmanaged devices, a user doesn’t need admin or sudo access to bypass them.

繞過的方式文件列了八種,最值得知道兩條。

第一條是改快取檔。~/.claude/remote-settings.json 被竄改之後,改過的內容會在啟動時套用(withheld 那批除外)。下次 fetch 會修正回來,但那些只在下次啟動才套用的鍵(model、新加進 env 的變數)會一直錯到重啟為止。

第二條最該記住。使用者只要設一個第三方模型供應商,整件事就直接繞過去。文件點名 CLAUDE_CODE_USE_BEDROCKCLAUDE_CODE_USE_MANTLECLAUDE_CODE_USE_VERTEXCLAUDE_CODE_USE_FOUNDRYCLAUDE_CODE_USE_ANTHROPIC_AWS,或一個非預設的 ANTHROPIC_BASE_URL

麻煩在於你補不回來。

想用 server-managed 的 env 區塊去清掉那個 export?那個區塊正是走「被這個 export 擋掉的 fetch」送來的,根本到不了這台機器。改用 endpoint-managed 的 env 區塊?也救不回來,Claude Code 在套用 managed env 之前就先檢查資格了。

跟前面 withheld 那段是同一個形狀,攻守顛倒而已。原廠先把「能改變 fetch 去向」的值扣住,免得被自己下發的東西反咬一口;使用者那個 export 動的是同一個把手,只是它在 fetch 發生之前就已經存在,所以扣不住。

文件給的兩條解法都不在 server-managed 這一層:把 export 從 shell 移掉,或者在使用者的 user settings env 區塊把該變數設成 ""(這個會在資格檢查之前生效)。兩條都要有人碰到那台機器。

繞回最前面那台沒裝 MDM 的筆電。它確實能被管到,前提是使用者沒有主動反抗。我的立場是,這東西買到的是一致性,不是強制力。拿來鋪預設值、鋪稽核 hook、鋪「大家都該有但沒人想自己設」的那些東西,它很好用,而且是目前唯一能覆蓋雲端 session 的路:endpoint-managed settings 到不了 Anthropic 託管環境,session 跑在 Anthropic 管的 VM 上,所以就算有 MDM,只要開發者會用 cloud session,你還是得再配一份。拿它當唯一那道防線,就是把稽核報表當成事實。

會讓我改口的條件很具體:哪天資格檢查搬到套用 managed env 之後,或者未帶政策的 client 在伺服器端就直接被拒絕發模型請求,上面那段就不成立了。

想讓它硬一點:fail-closed 那個開關

預設是 fail-open,fetch 失敗就吃快取。要反過來,加這個鍵:

1
{ "forceRemoteSettingsRefresh": true }

設了之後,CLI 啟動時會擋住,直到成功抓到新政策;抓不到就退出,不會不帶政策繼續跑。

這個鍵會自我延續。一旦從伺服器下發過,它自己也進了本機快取,所以之後每次啟動,即使在首次成功 fetch 之前,都是這個行為。

好在有一個豁免:claude auth 系列子指令(例如 claude auth login)不受這項檢查管。憑證過期常常就是 fetch 失敗的原因,連登入都被擋住的話,使用者會卡死在沒有出口的迴圈裡。

打開這個鍵之前,先確認網路政策允許連到 api.anthropic.com,否則 CLI 會在啟動時退出,使用者完全開不起來。

這篇我只讀了文件,沒有實際跑過。 我手上沒有 Enterprise 方案的 Owner 權限,也沒有能拿來實驗的組織帳號,上面每個版本號、每個鍵名、每條行為都是文件明寫的。文件沒講清楚的地方我就留著,例如那個「每小時輪詢」有沒有可調的參數,我不知道。

這個形狀到處都是

抽掉 Claude Code 這個殼,剩下的長這樣:一條用來下發控制的通道,而通道的走向由被下發的內容決定。

DNS server 位址由 DHCP 下發,DHCP 要不要被信任又看網路怎麼接。設定管理工具管全機器的設定,包括它自己那個 agent 的設定。VPN 的路由規則從 VPN 裡面推下來。同一個洞:有人在通道建立之前就動了那個把手,你後面推的東西全部到不了。

判準也就清楚了。拿到任何一套遠端下發的控制,先攤開兩張清單:這條通道自己依賴哪些值,這套機制又能下發哪些值。交集就是你補不回來的部分。原廠會自己扣住一部分,withheld 清單就是為此存在;剩下的要嘛靠實體接觸那台機器,要嘛把控制點往伺服器端搬。

那張交集清單,多數系統的文件不會幫你列。這份列了。

原文來源:Server-managed settings - Claude Docs