Skip to Content
概念稽核與控制面稽核

稽核與控制面稽核

稽核寫入器

同交易、有界、只追加。每筆事實在 edge_worker_audit_logs 一列;永不記錄原始碼、bundle、API 金鑰、Worker 機密值或服務帳號密碼 — 只有摘要(機密值與服務帳號憑證使用加鹽摘要)。寫入器把 actor_type(32)、auth_method(32)、action(128)、resource_type(64)、result(32)、reason_code(64)、digest(64)截斷到欄位長度,flush 但永不 commit(交易由 route/task 擁有)。

冪等性在應用層:帶明確的 audit_id,寫入器在所有正規化欄位吻合時回傳既有列,漂移時丟出 "audit id is already bound to different facts"。帶明確 id 的寫入在 SAVEPOINT 內插入,所以兩個行程對同一個 id 競爭時,由主鍵決定誰勝出,落敗的一方以加鎖讀取重新讀取該列,而不是讓自己的交易失敗。控制面稽核通道利用這點,把 outbox 列 id 當 audit id,讓復原重放冪等;退役確認基於同樣的理由使用確定性 id。表本身沒有唯一約束。

記錄的事實

actor_type/auth_method 是 principal 的值(例如 user/jwt),任務寫入的事實則為 system/system。result ∈ success(預設)/ failed / uncertain。所有資料列都帶有部門的 company_id 與 department_id。

提交與部署

actionresource_type行為者digest
submission.creatededge_worker_versionprincipalmanifest 摘要
deployment.submittededge_worker_versionprincipalmanifest 摘要
deployment.reconciliation_submittededge_worker_versionprincipal(公司管理者修復)manifest 摘要
deployment.completededge_worker_versionsystembundle 摘要
deployment.failededge_worker_versionsystem、result="failed"、reason_code = 錯誤代碼(dispatch_not_accepted、retry_exhausted、retry_transport_unavailable、department_deleted…)manifest 或 bundle 摘要
deployment.uncertainedge_worker_versionsystem、result="uncertain"、reason_code = 錯誤代碼bundle(退回 manifest)摘要
secrets.purged_before_legacy_deployedge_workersystem(resource_id = Worker id)—

存取政策與執行期設定

actionresource_type行為者digest
access_policy.replacededge_worker_access_policyprincipal正規 {ip_allowlist, mode} 的 sha256
access_policy.api_key.rotatededge_worker_access_policyprincipal金鑰的 SHA-256 摘要(永遠不是金鑰本身)
access_policy.api_key.revoked / access_policy.api_key.revoke_noopedge_worker_access_policyprincipalsha256("revoked")
runtime_config.replacededge_worker_runtime_configprincipal正規值 JSON 的 sha256
runtime_config.deletededge_worker_runtime_configprincipalsha256("null")

操作設定、Worker 機密與服務帳號憑證

這些全都走下方的控制面稽核通道(行為者 = 發出請求的 principal;resource_id = Worker id)。唯一例外:存活的 release 早於 Worker 機密支援時,刪除機密會由請求自己的交易直接寫入 secrets.delete_noop。

actionresource_typedigest
operation_settings.replacededge_worker_operation_settings正規 {api_base, default_service_account_id, operations} 的 sha256
operation_settings.stagededge_worker_operation_settings相同的摘要形式;部署為目標 release 暫存設定表時,改寫此動作而非 replaced(指令帶有 liveReleaseGeneration)
operation_settings.api_key.rotatededge_worker_operation_settings金鑰的 SHA-256 摘要(永遠不是金鑰本身)
operation_settings.api_key.revoked / operation_settings.api_key.revoke_noopedge_worker_operation_settingssha256("operation-key-revoked:<operation_id>")
secrets.putedge_worker_secret加鹽的值摘要 sha256(salt || value);salt 從不儲存
secrets.deleted / secrets.delete_noopedge_worker_secretsha256("delete:<NAME>")
service_accounts.credentials.putedge_worker_service_account憑證的加鹽 SHA-256(passwordDigest)
service_accounts.credentials.deleted / service_accounts.credentials.delete_noopedge_worker_service_accountsha256("delete-service-account:<id>")

服務帳號(直接資料列)

與變更寫在同一個資料庫交易內,不經過 outbox;resource_type 為 service_account,resource_id 為服務帳號 id,digest 為所示變更集合之正規 JSON(鍵排序、無空格)的 SHA-256。

action時機雜湊的變更集合
service_account.created建立{"department_id":"<id>","username":"<name>"}
service_account.credential_reset重設,不論結果{"delivery":"<delivered, not_deployed, unsupported_release, not_bound or failed>"}
service_account.deleted刪除路由{"deleted":true}
service_account.deleted部門刪除,每個服務帳號一列;auth_method="department_delete",行為者為 user(執行刪除的管理者)或 system{"deleted":true,"reason":"department_deleted","service_account_id":"<id>"}
service_account.chatrooms_changed每個處理過的聊天室一列{"operation":"<add or remove>","room_id":"<id>","status":"<status>"}

見服務帳號。

退役確認

系統資料列(actor_type="system"、actor_id=""、auth_method="system"、resource_type="edge_worker"、resource_id = Worker id),使用確定性 id,立即提交;沒有任何 API 公開它們。詳見退役。

actionreason_code意義
department.worker_retired—provider 已完成 Worker script 的退役
department.worker_script_neutralized被處理的 dispatch namespace(共用位置的 namespace,或該環境自己舊有位置的 namespace)該 namespace 的雲端墓碑已結清
department.worker_script_deleted被處理的 dispatch namespace(同上)每次嘗試處理該 script 之前(不一定接著上傳)寫入的標記;記錄已對該 namespace 採取過動作
department.worker_tombstone_deleted被處理的 dispatch namespace(同上)已退役 Worker 的墓碑 script 從該 namespace 移除之後寫入

僅限地端的 edge_worker.resync 系統資料列(resource_type 為 edge_worker_version 或 edge_worker,result 為 success 或 failed)記錄 resync 的結算與變更。reason_code 為 promoted(被攔下的部署已完成)、settled_failed(被攔下的部署失敗)、edge_worker_deleted(被攔下的部署因其 Worker 已刪除而失敗)、cleared、retired、unretired、rolled_back、edge_data_held 或 edge_data_mismatch_accepted;resync CLI 見地端。

控制面稽核:變更必須以回執背書的事實收尾

存取政策、執行期設定、操作設定(取代、部署暫存、金鑰輪替/撤銷)、Worker 機密(寫入/刪除)與服務帳號憑證(寫入/刪除)的變更,走耐久的 control_audit outbox 意圖,且在 provider I/O 之前提交:

  1. 請求路徑:入列意圖(寬限 300 秒)→ 把簽章的 purpose=control 指令送到 Durable Object → 成功時盡力結算(寫稽核+完成)。本地結算失敗被刻意吞掉 — provider 回執才是耐久的重放權威;絕不毀掉成功的控制結果,尤其是一次性的 API 金鑰。provider 的 revision 衝突把意圖結算為 failed revision_conflict(HTTP 409);Durable Object 回傳的有型別拒絕(例如 secret_limit_exceeded)則以該代碼把意圖結算為 failed;結果未知則排 15 秒重試(provider_outcome_unknown,HTTP 503)。
  2. 復原(60 秒迴圈):讀取 Durable Object 回執(control.receipt.get)— 永不重送變更 — 依下方的稽核契約、預期 revision 與預期摘要驗證精確的操作結果 — 然後在單一交易內寫下確定性稽核列並完成意圖。回執不存在 → failed control_receipt_not_found;回執連續三次無效 → uncertain control_receipt_invalid(需維運人員關注);不帶已記錄服務位置、且無法對應到 Worker 目前服務位置的回執列 → failed legacy_serving_target_unavailable(自後端 5.22.0 起)。
  3. 確認輪:完成後以 control.receipt.ack 告知 Durable Object 可丟棄回執;必須恰好回 {"acknowledged": true},失敗按 15 秒 → 3600 秒階梯重試;上述 legacy_serving_target_unavailable 的情況則改為停止重試。
指令 operation稽核 action(no-op 動作)
access_policy.replaceaccess_policy.replaced
access_policy.api_key.rotateaccess_policy.api_key.rotated
access_policy.api_key.revokeaccess_policy.api_key.revoked(access_policy.api_key.revoke_noop)
runtime_config.replaceruntime_config.replaced
runtime_config.deleteruntime_config.deleted
operation_settings.replaceoperation_settings.replaced,部署暫存時為 operation_settings.staged
operation_settings.api_key.rotateoperation_settings.api_key.rotated
operation_settings.api_key.revokeoperation_settings.api_key.revoked(operation_settings.api_key.revoke_noop)
secrets.putsecrets.put
secrets.deletesecrets.deleted(secrets.delete_noop)
service_accounts.credentials.putservice_accounts.credentials.put
service_accounts.credentials.deleteservice_accounts.credentials.deleted(service_accounts.credentials.delete_noop)

回執規則:

  • 結果的鍵集合必須恰為 {conflict, current},兩個 API 金鑰撤銷另加 revoked,secrets.delete 與 service_accounts.credentials.delete 另加 deleted;conflict 必須為 false。
  • 存取政策與執行期設定:revision 為 base+1(no-op 撤銷為 base+0),另須與指令的模式、允許清單、後四碼或值摘要一致。
  • 操作設定:current.state == "reconciled" 且 current.revision 等於 baseRevision + 1(什麼都沒撤銷的撤銷為 + 0);replace 另外要求 current.releaseGeneration 等於指令的值。
  • 機密:put 要求 current 鍵恰為 {name, sha256, updated_at},且名稱與值摘要須與指令相同;delete 要求 {name, deleted, updated_at},且 current.deleted 等於 result.deleted(false 時採用 no-op 動作)。
  • 服務帳號憑證:put 要求 {serviceAccountId, username, passwordDigest, updated_at} 且與指令相同;delete 要求 {serviceAccountId, deleted, updated_at}(false 時採用 no-op 動作)。
  • updated_at 必須是有效時間戳。無 revision 的操作(secrets.*、service_accounts.credentials.*)不帶 baseRevision。

已退役的 Worker。 讀取回執之前,兩個輪次都先詢問該 Worker 是否已退役:它的部門已軟刪除且存在 department.worker_retired 事實,或它的公司已被硬刪除(沒有任何公司有該 id 的部門資料列,也沒有 Worker 資料列)。若是,則不呼叫 provider。復原輪取消 outbox 列(cancelled,last_error_code="worker_retired",last_error="Worker retired before its control receipt was read"),且不寫稽核列,因為該次變更的回執隨 Worker 的 Durable Object 一起消失了。確認輪停止重試已完成的列(next_attempt_at 清空,last_error_code="worker_retired",last_error="provider receipt retired with its Worker")。兩者都以 INFO 記錄 Edge Worker control receipt settled: its Worker is retired — 絕不當成錯誤、絕不重試 — 而 60 秒迴圈的彙總行把它們計為 retired 與 ack_retired。

明文機密永遠進不了 outbox — 入列驗證會拒絕 Worker 層級金鑰指令上的 api_key/apiKey 欄位、操作金鑰指令上的 key/apiKey 欄位、機密指令上的 value 欄位,以及服務帳號憑證指令上的 password/salt 欄位;流動的只有摘要(API 金鑰的 SHA-256 與後四碼;機密值或憑證的加鹽 SHA-256,salt 只會加進即時的 provider 指令)。

完整任務機制:背景任務。表結構:資料庫模型。

Last updated on