Skip to Content
概念Worker 機密

Worker 機密

部門 Worker 可以在不可變 bundle 之外保存具名、僅可寫入的 Worker 機密 — 第三方 API 金鑰、token、憑證 — 存放在與持久儲存、執行期設定相同的 Durable Object 裡。部門管理者透過 TeamSync API 寫入;handler 程式碼用 await context.secrets.get(name) 依名稱讀取。沒有任何路由會回傳機密值,而且變更在下一次呼叫就會生效:不需重建,也不需重新部署。Worker 機密最早隨後端 v5.13.0 發布;以下皆為後端 5.21.0 的狀態。

管理者的操作步驟:管理 Worker 機密。非機密的設定請用執行期設定。

規則與限制

項目規則
誰能管理Worker 所屬部門的部門管理者(JWT、管理者閘門 — 驗證與角色)。沒有公司層級的機密路由,服務帳號的 JWT 會被拒絕,回 403 Insufficient permissions.(服務帳號建立時不具管理者角色)
名稱^[A-Z][A-Z0-9_]{0,63}$:1–64 個字元,大寫 ASCII 字母、數字與 _,第一個字元必須是字母。以 TEAMSYNC_ 開頭的名稱為保留字
值非空字串、不得含 NUL 字元、格式正確的 Unicode,最多 65 536 個 UTF-8 位元組(64 KiB)
數量每個 Worker 最多 256 個機密;取代既有名稱不會多占一個名額
總大小所有值合計最多 16 MiB(16 777 216 個 UTF-8 位元組)
寫入請求PUT body 最多 409 600 位元組(413 Worker secret request exceeds limit,在驗證之前、解析 body 之前檢查)

相關:限制一覽與錯誤;機密路由的錯誤回應列在管理 Worker 機密。

值存放在哪裡

  • 只存在 Worker 的 Durable Object 裡。 值位於該 Worker 自己的 Durable Object 內的一張平台資料表,與 context.storage 所存取的 user: 鍵分開。機密屬於 Worker 而不是某個 release,所以同一個 Worker 的新部署會保留它們(下方的清除規則是例外)。
  • 後端從不儲存機密值。 一次寫入分兩步:後端先提交一筆耐久的控制意圖,裡面只有名稱與加鹽摘要(salted digest)sha256(salt || value),每次寫入都用新的隨機 32 位元組 salt;接著才把值與 salt 在即時的簽章控制請求中送給 Worker 一次。後端與 Durable Object 都不保存 salt,所以稽核事實裡的摘要無法用來驗證猜測的值。
  • 沒有任何路由會回傳機密值。 GET /worker/secrets 只回傳名稱與 updated_at;寫入與刪除的回應都不含值;後端的請求日誌對機密 PUT 的 body 只留下遮蔽標記;機密 PUT 的 422 也絕不回顯值。
  • 變更在下一次呼叫生效。 handler 在呼叫 get 時才讀取 Durable Object,所以 PUT 或 DELETE 不需部署就會被下一個請求看到。

在 handler 程式碼裡讀取機密

export async function callPartner({ secrets }: HandlerInput<"callPartner">) { const apiKey = await secrets.get("PARTNER_API_KEY") // string, or undefined if not set if (apiKey === undefined) { return Response.json({ code: "not_configured" }, { status: 503 }) } const upstream = await fetch("https://partner.example/v1/items", { headers: { authorization: `Bearer ${apiKey}` }, }) return new Response(upstream.body, { status: upstream.status }) }
  • handler 的 context 是凍結的物件 {request, params, query, operationId, storage, config, secrets, teamsync};context.secrets 是只有一個方法 get(name) 的凍結物件(teamsync 見服務帳號)。teamsync-worker generate 會在 HandlerInput.secrets 上把它標成 WorkerSecrets { get(name: string): Promise<string | undefined> }。
  • get 回傳目前的字串值;沒有該名稱的機密時回傳 undefined。每次呼叫都在當下讀取 Durable Object — 和 context.config 不同,沒有每個請求一份的快照。
  • get 只接受恰好一個引數。它是 async 函式,所以錯誤以 rejected 的 promise 形式出現:引數個數不是一個時丟出 TypeError TeamSync secret name must be a string;名稱不是字串、不符合名稱格式或以 TEAMSYNC_ 開頭時丟出 TypeError secret name is invalid or reserved。
  • handler 程式碼不能列出、設定或刪除機密;那是只有管理者能用的 API 操作。Worker 的所有操作看到的是同一組機密。
  • 部署到 Worker 的任何程式碼都能讀取每一個機密。 沒有逐操作或逐機密的範圍限制,所以只存放專用的低權限憑證,並且絕不回傳或記錄機密值。起始範本的 README 也有同樣的警告。

哪些 release 能使用機密

能力最低 builder policy
GET /worker/secrets(列出名稱)與 handler 程式碼中的 context.secrets.getdepartment-worker-project-v2.6
PUT /worker/secrets/{name}(寫入帶有加鹽摘要)department-worker-project-v2.7
DELETE /worker/secrets/{name}任何 release

runtime 在建置時就生成進 bundle,所以只有以 v2.6 或更新版本建置的修訂版才有 context.secrets;後端 5.22.0 建置的每一份提交都使用 department-worker-project-v2.10。API 接受什麼由目前上線(已部署)的 release 決定:它比最低要求舊時,GET 與 PUT 回 409 worker_secrets_unsupported,解法是重新提交專案並部署新的修訂版(提交版本)。在 v2.6 之前的 release 上 DELETE 回 200 且 deleted: false,並寫入一筆稽核事實,因為這樣的 bundle 本來就無法持有機密。同一條 policy 階梯上較晚的能力(操作設定 v2.8、服務帳號憑證 v2.9)列在提交管線的能力表。

清除規則

除了管理者的 DELETE,平台會在兩種情況下移除 Worker 機密:

  1. 在 v2.6 或更新的上線 release 上,部署一份早於 v2.6 建置的 release。 Worker 為這次部署暫停之後、上傳任何東西之前,平台會透過上線中的 release 清除所有 Worker 機密 — 一律執行,不檢查是否存在 — 並寫入稽核事實 secrets.purged_before_legacy_deploy。如果清除無法確認,票證以 failed 結束(deployment_internal_error;若期間 Worker 或其上線 release 已改變,則為 artifact_integrity_failed),而且不會上傳任何東西。一旦以 v2.8 或更新版本建置的 release 上線,早於 v2.8 的 release 一律被拒絕,所以實際上這項清除只會發生在上線 release 為 v2.6 或 v2.7 的部署之前。之後再部署較新的修訂版時,機密不會被還原:請重新寫入。
  2. 刪除部門。 退役會先嘗試鎖定 Worker 的進站許可,並清除它的使用者機密與服務帳號憑證(在雲端 provider 上限制在 8 秒預算內),然後用墓碑取代腳本,墓碑也會讓 Worker 的 Durable Object 連同裡面剩下的一切被刪除;地端的清除則必須成功,並會刪掉機密資料表,之後主機才將腳本退役(退役)。

重新部署以 v2.6 或更新版本建置的修訂版,或在這類修訂版之間切換,都不會動到機密。

稽核

每一次寫入與刪除都是稽核事實;沒有任何一筆帶有機密值。

actionresource_type行為者digest
secrets.putedge_worker_secretprincipalsha256(salt || value) — 加鹽,salt 從不儲存
secrets.deletededge_worker_secretprincipalsha256("delete:<NAME>")
secrets.delete_noopedge_worker_secretprincipal相同的刪除摘要 — 該名稱未設定,或上線 release 早於機密功能
secrets.purged_before_legacy_deployedge_workersystem—

寫入與刪除走與存取政策、執行期設定變更相同的耐久控制面稽核 outbox:意圖在聯絡 Worker 之前就已提交,事實則依 Worker 的回執完成,即使請求路徑無法結算也一樣。進入 outbox 的只有名稱與加鹽摘要。

Last updated on