Secrets 管理

OpenClaw 支援累加式 SecretRef,讓支援的憑證不必以明文儲存在設定中。

明文仍然可以用。SecretRef 是按憑證欄位選用的。

目標與執行時期模型

Secrets 會解析成記憶體中的執行時期快照。

  • 解析在啟動時積極執行,不會延遲到請求路徑上。
  • 當有效活動的 SecretRef 無法解析時,啟動會立即失敗。
  • 重新載入採用原子交換:全部成功,否則保持上次已知良好的快照。
  • 執行時期請求只從活動中的記憶體快照讀取。
  • 對外發送路徑也從該活動快照讀取(例如 Discord 回覆/thread 發送和 Telegram 動作發送);它們不會在每次發送時重新解析 SecretRef。

這樣可以避免 secret provider 故障影響到請求處理的熱路徑。

活動介面過濾

SecretRef 只在有效活動的介面上進行驗證。

  • 已啟用的介面:未解析的 ref 會阻止啟動/重新載入。
  • 未啟用的介面:未解析的 ref 不會阻止啟動/重新載入。
  • 未啟用的 ref 會發出非致命的診斷訊息,代碼為 SECRETS_REF_IGNORED_INACTIVE_SURFACE

未啟用介面的範例:

  • 已停用的頻道/帳號條目。
  • 沒有任何已啟用帳號繼承的頂層頻道憑證。
  • 已停用的工具/功能介面。
  • 未被 tools.web.search.provider 選中的網頁搜尋 provider 專用金鑰。 在自動模式下(provider 未設定),金鑰會按優先順序逐一嘗試 provider 自動偵測,直到有一個成功解析。 選定後,未選中的 provider 金鑰在被選中之前視為未啟用。
  • gateway.remote.token / gateway.remote.password SecretRef 在以下任一條件成立時為活動狀態:
    • gateway.mode=remote
    • gateway.remote.url 已設定
    • gateway.tailscale.modeservefunnel
    • 在本機模式且無上述遠端介面時:
      • gateway.remote.token 在 token 認證可能勝出且沒有設定 env/auth token 時為活動狀態。
      • gateway.remote.password 只在 password 認證可能勝出且沒有設定 env/auth password 時為活動狀態。
  • OPENCLAW_GATEWAY_TOKEN(或 CLAWDBOT_GATEWAY_TOKEN)已設定時,gateway.auth.token SecretRef 對啟動認證解析來說是未啟用的,因為環境變數 token 在該執行時期中優先。

Gateway 認證介面診斷

gateway.auth.tokengateway.auth.passwordgateway.remote.tokengateway.remote.password 設定了 SecretRef 時,gateway 啟動/重新載入會明確記錄介面狀態:

  • active:SecretRef 是有效認證介面的一部分,必須解析成功。
  • inactive:該 SecretRef 被忽略,因為其他認證介面勝出,或遠端認證未啟用/不活動。

這些條目以 SECRETS_GATEWAY_AUTH_SURFACE 記錄,並包含活動介面策略使用的原因,讓你能看出為何某個憑證被視為活動或未啟用。

Onboarding 參考預檢

在互動式 onboarding 中選擇 SecretRef 儲存時,OpenClaw 會在儲存前執行預檢驗證:

  • Env ref:驗證環境變數名稱並確認 onboarding 期間可見到非空值。
  • Provider ref(fileexec):驗證 provider 選擇、解析 id,並檢查解析值的類型。
  • Quickstart 重用路徑:當 gateway.auth.token 已經是 SecretRef 時,onboarding 會在 probe/dashboard 引導前解析它(對 envfileexec ref),使用相同的快速失敗閘門。

如果驗證失敗,onboarding 會顯示錯誤讓你重試。

SecretRef 合約

到處使用同一種物件格式:

{ source: "env" | "file" | "exec", provider: "default", id: "..." }

source: "env"

{ source: "env", provider: "default", id: "OPENAI_API_KEY" }

驗證規則:

  • provider 必須符合 ^[a-z][a-z0-9_-]{0,63}$
  • id 必須符合 ^[A-Z][A-Z0-9_]{0,127}$

source: "file"

{ source: "file", provider: "filemain", id: "/providers/openai/apiKey" }

驗證規則:

  • provider 必須符合 ^[a-z][a-z0-9_-]{0,63}$
  • id 必須是絕對 JSON pointer(/...
  • RFC6901 段落中的跳脫:~ => ~0/ => ~1

source: "exec"

{ source: "exec", provider: "vault", id: "providers/openai/apiKey" }

驗證規則:

  • provider 必須符合 ^[a-z][a-z0-9_-]{0,63}$
  • id 必須符合 ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$
  • id 中不得包含以斜線分隔的 ... 路徑段落(例如 a/../b 會被拒絕)

Provider 設定

secrets.providers 下定義 provider:

{
  secrets: {
    providers: {
      default: { source: "env" },
      filemain: {
        source: "file",
        path: "~/.openclaw/secrets.json",
        mode: "json", // 或 "singleValue"
      },
      vault: {
        source: "exec",
        command: "/usr/local/bin/openclaw-vault-resolver",
        args: ["--profile", "prod"],
        passEnv: ["PATH", "VAULT_ADDR"],
        jsonOnly: true,
      },
    },
    defaults: {
      env: "default",
      file: "filemain",
      exec: "vault",
    },
    resolution: {
      maxProviderConcurrency: 4,
      maxRefsPerProvider: 512,
      maxBatchBytes: 262144,
    },
  },
}

Env provider

  • 可選的白名單透過 allowlist 設定。
  • 缺少或空的環境變數值會導致解析失敗。

File provider

  • path 讀取本機檔案。
  • mode: "json" 預期 JSON 物件 payload,用 id 作為 pointer 解析。
  • mode: "singleValue" 預期 ref id 為 "value",回傳檔案內容。
  • 路徑必須通過擁有權/權限檢查。
  • Windows 失敗關閉注意:如果某路徑的 ACL 驗證不可用,解析會失敗。對於受信任的路徑,可在該 provider 上設定 allowInsecurePath: true 以繞過路徑安全檢查。

Exec provider

  • 執行設定的絕對路徑二進位檔,不透過 shell。
  • 預設情況下,command 必須指向一般檔案(不是符號連結)。
  • 設定 allowSymlinkCommand: true 以允許符號連結的 command 路徑(例如 Homebrew shim)。OpenClaw 會驗證解析後的目標路徑。
  • 搭配 trustedDirs 用於套件管理器路徑(例如 ["/opt/homebrew"])。
  • 支援逾時、無輸出逾時、輸出位元組限制、環境變數白名單和受信任目錄。
  • Windows 失敗關閉注意:如果 command 路徑的 ACL 驗證不可用,解析會失敗。對於受信任的路徑,可在該 provider 上設定 allowInsecurePath: true 以繞過路徑安全檢查。

請求 payload(stdin):

{ "protocolVersion": 1, "provider": "vault", "ids": ["providers/openai/apiKey"] }

回應 payload(stdout):

{ "protocolVersion": 1, "values": { "providers/openai/apiKey": "<openai-api-key>" } } // pragma: allowlist secret

可選的逐 ID 錯誤:

{
  "protocolVersion": 1,
  "values": {},
  "errors": { "providers/openai/apiKey": { "message": "not found" } }
}

Exec 整合範例

1Password CLI

{
  secrets: {
    providers: {
      onepassword_openai: {
        source: "exec",
        command: "/opt/homebrew/bin/op",
        allowSymlinkCommand: true, // Homebrew 符號連結二進位檔需要
        trustedDirs: ["/opt/homebrew"],
        args: ["read", "op://Personal/OpenClaw QA API Key/password"],
        passEnv: ["HOME"],
        jsonOnly: false,
      },
    },
  },
  models: {
    providers: {
      openai: {
        baseUrl: "https://api.openai.com/v1",
        models: [{ id: "gpt-5", name: "gpt-5" }],
        apiKey: { source: "exec", provider: "onepassword_openai", id: "value" },
      },
    },
  },
}

HashiCorp Vault CLI

{
  secrets: {
    providers: {
      vault_openai: {
        source: "exec",
        command: "/opt/homebrew/bin/vault",
        allowSymlinkCommand: true, // Homebrew 符號連結二進位檔需要
        trustedDirs: ["/opt/homebrew"],
        args: ["kv", "get", "-field=OPENAI_API_KEY", "secret/openclaw"],
        passEnv: ["VAULT_ADDR", "VAULT_TOKEN"],
        jsonOnly: false,
      },
    },
  },
  models: {
    providers: {
      openai: {
        baseUrl: "https://api.openai.com/v1",
        models: [{ id: "gpt-5", name: "gpt-5" }],
        apiKey: { source: "exec", provider: "vault_openai", id: "value" },
      },
    },
  },
}

sops

{
  secrets: {
    providers: {
      sops_openai: {
        source: "exec",
        command: "/opt/homebrew/bin/sops",
        allowSymlinkCommand: true, // Homebrew 符號連結二進位檔需要
        trustedDirs: ["/opt/homebrew"],
        args: ["-d", "--extract", '["providers"]["openai"]["apiKey"]', "/path/to/secrets.enc.json"],
        passEnv: ["SOPS_AGE_KEY_FILE"],
        jsonOnly: false,
      },
    },
  },
  models: {
    providers: {
      openai: {
        baseUrl: "https://api.openai.com/v1",
        models: [{ id: "gpt-5", name: "gpt-5" }],
        apiKey: { source: "exec", provider: "sops_openai", id: "value" },
      },
    },
  },
}

支援的憑證涵蓋範圍

支援和不支援的憑證完整列表請見:

執行時期生成或輪替的憑證以及 OAuth refresh 相關材料,被刻意排除在唯讀 SecretRef 解析之外。

必要行為與優先順序

  • 沒有 ref 的欄位:不變。
  • 有 ref 的欄位:在啟動的活動介面上為必要。
  • 如果同時存在明文和 ref,ref 在支援的優先順序路徑上優先。

警告和稽核信號:

  • SECRETS_REF_OVERRIDES_PLAINTEXT(執行時期警告)
  • REF_SHADOWED(當 auth-profiles.json 憑證優先於 openclaw.json ref 時的稽核發現)

Google Chat 相容行為:

  • serviceAccountRef 優先於明文 serviceAccount
  • 當同層 ref 已設定時,明文值會被忽略。

啟動觸發點

Secret 啟動在以下時機執行:

  • 啟動時(預檢加上最終啟動)
  • 設定重新載入的熱套用路徑
  • 設定重新載入的重啟檢查路徑
  • 透過 secrets.reload 手動重新載入

啟動合約:

  • 成功時原子交換快照。
  • 啟動失敗會中止 gateway 啟動。
  • 執行時期重新載入失敗會保持上次已知良好的快照。
  • 在對外的 helper/工具呼叫中提供明確的每次呼叫頻道 token 不會觸發 SecretRef 啟動;啟動點仍僅限於啟動、重新載入和明確的 secrets.reload

降級與恢復信號

當重新載入時的啟動在健康狀態之後失敗,OpenClaw 會進入 secrets 降級狀態。

一次性系統事件和日誌代碼:

  • SECRETS_RELOADER_DEGRADED
  • SECRETS_RELOADER_RECOVERED

行為:

  • 降級:執行時期保持上次已知良好的快照。
  • 恢復:在下次成功啟動後發出一次。
  • 已處於降級狀態時的重複失敗會記錄警告但不會重複發送事件。
  • 啟動時的快速失敗不會發出降級事件,因為執行時期從未進入活動狀態。

指令路徑解析

指令路徑可以透過 gateway 快照 RPC 選擇使用支援的 SecretRef 解析。

有兩種主要行為:

  • 嚴格指令路徑(例如 openclaw memory 遠端記憶體路徑和 openclaw qr --remote)從活動快照讀取,當必要的 SecretRef 不可用時會快速失敗。
  • 唯讀指令路徑(例如 openclaw statusopenclaw status --allopenclaw channels statusopenclaw channels resolve 和唯讀的 doctor/config 修復流程)也優先使用活動快照,但在目標 SecretRef 不可用時會降級而非中止。

唯讀行為:

  • 當 gateway 正在執行時,這些指令先從活動快照讀取。
  • 如果 gateway 解析不完整或 gateway 不可用,它們會嘗試針對特定指令介面的本機 fallback。
  • 如果目標 SecretRef 仍然不可用,指令會以降級的唯讀輸出繼續,並附帶明確的診斷訊息如「configured but unavailable in this command path」。
  • 這個降級行為僅限於指令本身。它不會弱化執行時期的啟動、重新載入或發送/認證路徑。

其他注意事項:

  • 後端 secret 輪替後的快照重新整理透過 openclaw secrets reload 處理。
  • 這些指令路徑使用的 Gateway RPC 方法:secrets.resolve

稽核和設定流程

預設操作者流程:

openclaw secrets audit --check
openclaw secrets configure
openclaw secrets audit --check

secrets audit

發現項目包括:

  • 靜態存在的明文值(openclaw.jsonauth-profiles.json.env,以及產生的 agents/*/agent/models.json
  • 產生的 models.json 條目中的明文敏感 provider header 殘留
  • 未解析的 ref
  • 優先順序遮蔽(auth-profiles.json 優先於 openclaw.json ref)
  • 舊版殘留(auth.json、OAuth 提醒)

Header 殘留注意事項:

  • 敏感 provider header 偵測基於名稱啟發式(常見的認證/憑證 header 名稱和片段,如 authorizationx-api-keytokensecretpasswordcredential)。

secrets configure

互動式輔助工具:

  • 先設定 secrets.providersenv/file/exec,新增/編輯/移除)
  • 讓你選擇 openclaw.json 中支援的 secret 欄位,加上一個代理範圍的 auth-profiles.json
  • 可以直接在目標選擇器中建立新的 auth-profiles.json 對應
  • 擷取 SecretRef 詳細資訊(sourceproviderid
  • 執行預檢解析
  • 可以立即套用

實用模式:

  • openclaw secrets configure --providers-only
  • openclaw secrets configure --skip-provider-setup
  • openclaw secrets configure --agent <id>

configure 套用預設行為:

  • 清除 auth-profiles.json 中目標 provider 的匹配靜態憑證
  • 清除 auth.json 中的舊版靜態 api_key 條目
  • 清除 <config-dir>/.env 中匹配的已知 secret 行

secrets apply

套用已儲存的計畫:

openclaw secrets apply --from /tmp/openclaw-secrets-plan.json
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run

嚴格的目標/路徑合約細節和確切的拒絕規則,請見:

單向安全策略

OpenClaw 刻意不寫入包含歷史明文 secret 值的回復備份。

安全模型:

  • 預檢必須成功才進入寫入模式
  • 執行時期啟動在 commit 前完成驗證
  • apply 使用原子檔案替換來更新檔案,失敗時盡力還原

舊版認證相容注意事項

對靜態憑證而言,執行時期不再依賴明文的舊版認證儲存。

  • 執行時期的憑證來源是已解析的記憶體快照。
  • 舊版靜態 api_key 條目在被發現時會被清除。
  • OAuth 相關的相容行為維持獨立處理。

Web UI 注意事項

部分 SecretInput union 在原始編輯器模式中比表單模式更容易設定。

相關文件