FR-039 Agent 認證 v2 — Agent 端開發計劃(詳盡版)

repo:evidence-agent。依據 design-agent-auth.md v2 + 後端計劃 §1 契約。 範圍:agent 自我註冊 + 心跳 + 設備指紋 + 資料面認證 + TLS。資料面 /blob 既有,沿用。 依賴契約:BE 計劃 §1(register/heartbeat/cert/JWT/X-Agent-Fingerprint)。可對 mock 雲端先開發。 📋 進度回填:開工/完成/卡住都更新 TRACKER


§1

契約回顧(agent 視角)

  • 開機 → 算 device_uuid = sha256(product_uuid|machine_id|primary_mac)
  • POST <endpoint>/api/1.0/agents/register {token, device_uuid, base_url, hardware_info, agent_version, status, csr} → 拿 {agent_uid, certificate, ca_certificate, jwt_public_key, heartbeat_interval_sec}
  • heartbeat_interval_secPOST /api/1.0/agents/heartbeat {device_uuid, status}(mTLS,帶拿到的 cert)。
  • 資料面:收 Authorization: Bearer <JWT> → 驗;回應加 X-Agent-Fingerprint

§2

任務

G1 · device_uuid 模組 + config

  • config:讀 env REGISTRATION_TOKENCLOUD_ENDPOINT、cert 存放路徑(AGENT_CERT_DIR)、host 識別碼路徑(/host/product_uuid/host/machine-id/host/mac)。
  • core/fingerprint.py(新):
    product_uuid = read('/host/product_uuid')   # 缺則 ''
    machine_id   = read('/host/machine-id')
    mac          = read('/host/mac')            # 部署腳本寫入
    device_uuid  = sha256(f"{product_uuid}|{machine_id}|{mac}")
    開機算一次、快取。缺某來源 graceful(記 log,不崩)。
  • 驗收:算出穩定 device_uuid;手動改某來源 → device_uuid 變。依賴:BE A0 契約。

G2 · 自我註冊 + 心跳迴圈

  • core/enroll.py(新):
    1. 開機若無本地 cert → 產 keypair + CSR(SAN=base_url host/IP) → POST /agents/register(帶 token + device_uuid + csr) → 存回傳 cert/CA/jwt_public_key 到 AGENT_CERT_DIR
    2. 已有 cert → 略過註冊。
    3. 啟動背景 thread:每 heartbeat_interval_sec POST /agents/heartbeat(mTLS 帶 cert)。
  • 註冊失敗(token 錯/雲端不通)→ retry with backoff + 記 log,不崩。
  • app_factory 開機呼叫 enroll(在 init_db 後)。
  • 驗收:對(mock)雲端 register 成功拿 cert;定期 heartbeat;重啟不重複註冊(已有 cert)。依賴:G1 + BE B3/B4。

G3 · 資料面認證 + TLS

  • before_request(blob 路由):mode=full 時驗 Authorization JWT —— 用 jwt_public_key 驗簽 + exp + aud==agent_uid + bound_fp==本地 device_uuid;任一不過 → 401。
  • 回應加 header X-Agent-Fingerprint: <device_uuid>(after_request)。
  • GET /agent-info{device_uuid, agent_version, status}(供雲端/除錯)。
  • TLS / mTLS:compose 加 nginx sidecar 收 mTLS(驗雲端 client cert,proxy→Flask:8000);掛載 CA/agent cert(註冊後產生的)/host 識別碼;deploy/collect-host-id.sh(抓 host MAC 寫 host-id/mac)。
    • deploy/docker-compose.yml:file-agent 掛 /sys/.../product_uuid:ro/etc/machine-id:ro./host-id/mac:roAGENT_CERT_DIR volume;新增 nginx service。
    • AGENT_AUTH_MODE=none 時 before_request 略過(維持現 demo)。
  • 驗收:無/錯 JWT 被擋;指紋不符被擋;mTLS 握手成功;mode=none 時現狀不變。依賴:G1 + BE B1(JWT/CA)。

§3

紀律 / 注意

  • 不動 jedi-file-upload 套件(認證在 evidence-agent app + nginx)。
  • 憑證/金鑰不入版控(agent cert 是執行期產生 + 雲端簽回,存 volume)。
  • AGENT_AUTH_MODE 包覆,過程不破壞 121 demo;最後切 full。
  • MAC:bridge 網路容器讀不到 host MAC → 一律靠 collect-host-id.sh 寫檔掛入(見 design §2.2)。
  • 封裝(.msi/.deb)延後;現用 Docker + .env。
  • 依賴順序:G1 → G2、G3(G2 需雲端 B3/B4 才能整合測;可先對 mock 開發)。