FR-066.7 T-7.1 · Windows 探路實測 · 2026-08-22

160 Windows 真機探路實測紀錄

在 192.168.50.160(Windows Server 2025 + Docker Desktop 29.7.2)手動走通 agent 全鏈,把四項 Windows 專屬問號查成答案。全鏈兩輪皆通(重置前後各派一單檢測任務、報告回雲端);四項查證各有結論,其中查證①(指紋)與新識別的自起缺口都推翻或修正了 T-4.3 評估文件的預測,是 T-7.2 install.ps1 的硬規格輸入。

實測紀錄・非設計文件 對應卡:CM-1337(T-7.1) 全鏈兩輪通・四項查證完成

🔴 本文件記錄「探路怎麼走通的」,不是「客戶要這樣裝」。 探路階段允許權宜手段 (手改 compose 檔、SSH 遠端下指令、手寫 .env);正式交付一律不要求客戶開 Linux 終端、不要求客戶手改檔案(D15/D17 受眾邏輯)。權宜處一律標示 ⚠️探路權宜, 與「結論」分開寫。

對應:design.md D17(Docker Desktop 路線裁示)、windows-feasibility.md §2 (docker 過渡模式評估——本次實測即在驗證/推翻該節結論)。

0. 結論總表(30 秒版)

# 查證項 實測結論 對 T-4.3 評估的關係 卡點等級
指紋 compose 原檔在 Windows 起不來(不是「起得來但值不對」)。/sys/class/dmi/id/product_uuid 掛載讓 docker 直接報 operation not permitted;拿掉該行後 agent 正常啟動,指紋退化成 machine-id 單源、且該 machine-id 是 Docker Desktop VM 的(非 Windows 主機) 修正(評估推測「docker 建空目錄→graceful 回空」,實際是硬失敗) 中(T-7.2 必處理,處理方式明確)
網路 8443 有正常映射到 0.0.0.0(Docker Desktop 自動做),但 Windows 防火牆預設擋住入站、Docker Desktop 不會自動開規則。加一條 inbound allow 後雲端 mTLS 打通(HTTP 200) 補充(評估只提到「要靠 portproxy 或 mirrored networking」,實測顯示映射本身沒問題,缺的只是防火牆規則) 低(一行指令解決)
IP 偵測 Find-NetRoute -RemoteIPAddress <雲端IP>192.168.50.160(正確的 Windows 主機網段 IP),與 Linux ip route get 語意等價 證實(評估預判可移植,實測確認)
重置重開通 分層結論:重啟/wsl --shutdown/RDP 斷線 → 指紋不變、容器自起;factory reset → 指紋漂移9e382ac8…8e579991…),雲端多一筆同名 agent。重開通僅需 docker compose up -d(.env 與 compose 檔不在 volume 內,存活) 證實並量化(評估說「reset 即變」,實測給出確切邊界與新舊值) 低(符合 D17「可接受維運事件」)
🆕 自起(新識別,評估文件未涵蓋) 使用者登出後 Docker Desktop 全滅、engine 消失、agent 離線。Docker Desktop 自起只掛在 HKCU\...\Run(需登入);SYSTEM 排程與 com.docker.service 兩條無登入路徑實測皆無法起 engine 新增(T-4.3 未談及;這是 Docker Desktop 路線的結構性限制) 高(P0,T-7.2 必須有答案)

全鏈驗收:兩輪端到端皆通——重置前(agent id=6,任務 id=13)與重置後(agent id=7, 任務 id=14)各派一單 nmap 檢測,皆 succeeded,報告 Nmap掃描報告_192.168.50.123_20260823.html 回到雲端、證據檔落在 160 本機 SeaweedFS。


1. 環境實況(與卡片記載的差異先講)

項目 卡片/STATE 記載 實測 說明
OS Win11 Windows Server 2025 Standard(10.0.26100) 機器名 JEDI-WIN2025-01-AD,網域 jedicogy.com不影響本次結論(Docker Desktop 行為一致),但 T-7.2 的環境檢查文案不應寫死「Windows 11」
Docker 29.7.2 已裝 ✅ 29.7.2,Docker Desktop(WSL2 backend) context desktop-linux;kernel 6.18.33.2-microsoft-standard-WSL2
規格 8 vCPU / 24GB RAM / C: 剩 202GB docker VM 配 12GB
WSL distro Ubuntu(Stopped)、docker-desktop(Stopped) 詳見 §4 為何 install.sh 仍不能用
既有角色 WinRM 掃描受測機 ✅ 確認(compliance.agent_tasks id=12 即以 160 為 GCB/WinRM 目標) agent 安裝與受測角色並存,本次未觀察到衝突

雲端側:188 DEV(CLOUD_ENDPOINT=https://192.168.50.188,自簽憑證走 TOFU)。 🔴 全程未觸碰 STG/POC。DEV 側的寫入僅限:兩筆測試任務 insert(compliance.agent_tasks id=13/14)+ agent 自行 enroll 產生的兩筆 compliance.remote_agents(id=6/7);其餘皆唯讀。


2. 交付包搬運與解包(無擋路項)

步驟 實測 耗時
188 → 160 傳輸 scp 1375323973 bytes,sha256 0b5d47f0… 完全相符 約 12 分鐘
解包 Windows 內建 tar.exe(bsdtar 3.7.7)直接解 .tar.gz 45 秒
image tar 校驗 兩顆皆與 image-manifest.sha256 相符(agent a4ac9ecf…/seaweedfs 31f47e9b…
docker load 兩顆成功,agent image 3.32GB(載入後顯示 6.79GB) 約 6 分鐘

✅ 結論(T-7.2 規格輸入)

  1. 不需要求客戶另裝解壓工具——Windows 10/11/Server 2019+ 內建 tar.exe 可解 .tar.gz。 install.ps1 可直接呼叫,或(若包已解開)省略此步。
  2. image-manifest.sha256 的校驗邏輯可原樣移植——Get-FileHash -Algorithm SHA256 輸出大寫 hex,比對前 .ToLower() 即可。
  3. ⚠️ docker load 的 3.3GB 是安裝流程最慢的一步(約 6 分鐘),install.ps1 要有進度 提示,不能靜默等待(客戶會以為當掉)。

2.1 ⚠️ 已知雷:非互動 session 下 registry pull 會失敗

docker pull(任何 registry 拉取)在 SSH/非互動 session 下報:

error getting credentials - err: exit status 1,
out: `A specified logon session does not exist. It may already have been terminated.`

成因是 credsStore: "desktop" 的 credential helper 依賴 DPAPI 使用者 session。 DOCKER_CONFIG 指向空 config、docker --config無法繞過(實測三種寫法皆失敗)。

對 install.ps1 的意義流程中不可有任何 registry pull。所幸現行設計本就是 docker load 本地 tar(不碰 registry),此雷不會踩到——但若未來為了省體積改成 「seaweedfs 從 registry 拉」,Windows 版會在這裡壞掉,且錯誤訊息完全不指向根因。


3. 查證①:指紋(本卡最重的技術發現)

3.1 實測:compose 原檔在 Windows 起不來

直接 docker compose up -d(一個字未改的交付包原檔):

Container guidant-ai-agent Starting
Error response from daemon: error while creating mount source path
'/sys/class/dmi/id/product_uuid': mkdir /sys/class/dmi: operation not permitted

docker compose config --quiet 通過(語法沒問題),失敗發生在啟動階段。 seaweedfs 正常起來,只有 agent 這個服務起不來。

3.2 🔴 這推翻了 T-4.3 評估 §2.2 的預測

windows-feasibility.md §2.2 的後果鏈寫:

product_uuid 缺 → compose 對不存在的來源做檔案掛載時 docker 會自動建一個空目錄 頂在掛載點上 → agent _read_source() 對目錄 open 失敗 → graceful 回空字串 → 指紋退化成只剩 machine-id 單源

實際上「docker 自動建空目錄」這一步不會發生,因為 Docker Desktop 的 Linux VM 內 /sys 是唯讀(實測:/sys/class/dmi/id/ 整個目錄不存在,且 docker 連 mkdir /sys/class/dmi 都被拒)。所以症狀不是「安靜地算錯指紋」,而是大聲地起不來

這對我們是好消息:硬失敗比靜默算錯好得多——不會出現「客戶裝好了、雲端多一台 陌生 agent、沒人發現」的壞法。但 T-7.2 必須處理,否則 Windows 客戶第一步就卡死。

3.3 拿掉該行後的實測值

⚠️探路權宜:手動把 docker-compose.yml 的 product_uuid 掛載那行註解掉 (正式做法見 §3.5)。之後:

WARNING:agent:device fingerprint source unreadable (/host/product_uuid):
        [Errno 2] No such file or directory: '/host/product_uuid'
INFO:agent:device_uuid computed: 9e382ac8c3ffb8e4e943a12e1b1329d20e7dcb04d58ee9cceb01cd6657fee970
INFO:agent:agent enrolled: agent_uid=fa38de1a-9ac0-4beb-bbb0-53306af707d7 heartbeat=300s
INFO:agent:data-plane mTLS listening on 0.0.0.0:8443 (client certificate required)

agent 的 graceful 行為與設計完全相符core/fingerprint.py _read_source() 記 WARNING 後回空字串),指紋算得出來、雲端註冊正常。獨立驗算確認: sha256("" + "|" + "650cb79deaff4f5c964103fa4d064271") = 9e382ac8…,與 agent log 一致。

3.4 machine-id 到底是誰的——完整溯源

這是本次最花工夫查清的一條鏈,記下來避免下次重查:

說明
Windows 主機 WMI Win32_ComputerSystemProduct.UUID 18AC7619-82E9-41BF-876C-BE6BA6C865AA 容器讀不到(原生 Windows 版才能用)
Windows 主機 registry MachineGuid 94c8473c-e394-48d8-8e87-fb4c3c54e8dc 容器讀不到
docker-desktop WSL distro 的 /etc/machine-id 不存在 從 WSL 側看是沒有的
docker VM(nsenter 進 PID 1 namespace) /etc/machine-id 650cb79deaff4f5c964103fa4d064271 ← 容器實際掛到的就是這個。是 symlink → /var/lib/machine-id
該檔所在檔案系統 /dev/sdd ext4docker_data.vhdx,1007G) 不是 tmpfs——這決定了它在什麼操作下存活(見查證④)

結論:Windows/Docker Desktop 形態下,agent 的身分實質綁在 docker_data.vhdx 這顆虛擬磁碟,而非 Windows 主機硬體或 OS 安裝。

3.5 T-7.2 規格:怎麼處理這條掛載

建議做法(不做 workaround,符合 D9/D11/D17 立場): 出貨 Windows 專用的 compose 檔docker-compose.windows.yml),內容與 Linux 版 唯一差異就是沒有 product_uuid 那行掛載,並在該處留註解說明「此來源在 Docker Desktop 不存在,非遺漏」。install.ps1 直接用它。

為什麼不是「install.ps1 動態改 compose 檔」:客戶機上被腳本改過的 compose 檔 與出貨版不一致,日後升級/除錯要先分辨「這行是我們改的還是客戶改的」。出兩份檔、 各自完整,比一份檔加改寫邏輯清楚。

為什麼不做 host 值注入:把 Windows 的 MachineGuid 寫成檔案掛進容器,即是 D9 廢除的 collect-host-id.sh 的 Windows 復刻(D11 排除方案②的理由原文適用), 且 D17 已明示「指紋漂移=可接受維運事件,不做 workaround」。

⚠️ 附帶效應(須寫進 T-7.3 指引的已知限制):同一台 Windows 機,若日後改用 原生 Windows 版(若解凍)或換成 Linux,指紋必然不同、需重新綁定——因為兩者的 身分來源根本不是同一個東西。


4. install.sh 為什麼在 Windows 上不能用(T-7.2 的存在理由)

160 上 bash.exe 存在C:\WINDOWS\system32\bash.exe)——但那是 WSL 啟動器, 不是原生 shell。即使進 WSL 跑,install.sh 仍過不了:

  1. 第①步環境檢查硬擋check_environment() 對指紋二源做 [[ ! -e "$fp_src" ]] && check_fail——WSL2 沒有 /sys/class/dmi/id/product_uuid, 直接 fail ... 2 中止(退出碼 2)。這不是繞過檢查就好的問題,因為……
  2. docker context 不同:WSL distro 內的 docker CLI 與 Windows 側 Docker Desktop engine 是不同 context,掛載路徑語意也不同(WSL 路徑 vs Windows 路徑)。
  3. ip route get 必錯:WSL2 NAT 網路下偵測到的是 WSL 內部 IP(172.x), 不是 Windows 主機的 192.168.50.160
  4. install.sh 另有 require_rootEUID -eq 0)、/usr/local/bin 維運入口複製、 /etc/guidant-agent-compose/install.conf 安裝紀錄——三者在 Windows 都無對應語意。

✅ 結論:T-7.2 出 install.ps1 是必要的,不是「比較好看」的選擇。且現有 install.sh 不需為 Windows 做任何相容性修改(兩條路線各自完整,見 §3.5 同理)。


5. 查證②:網路與 8443

5.1 實測序列

步驟 結果
容器起來後,160 本機 netstat 0.0.0.0:8443 LISTENING(PID=com.docker.backend)✅ Docker Desktop 的 port 映射預設就綁全介面
160 本機 Test-NetConnection 192.168.50.160:8443 True
從 188 連 160:8443 不通(TCP 層即失敗)
查防火牆 三個 profile 全 Enabled;Get-NetFirewallPortFilter 查 8443 → 無任何規則;查 Docker 相關 inbound 規則 → 一條都沒有
加一條 inbound allow TCP 8443 ✅ 188 → TCP 通、TLS 握手成功
雲端帶真 client cert 打 /health HTTP 200 {"status": "ok"}

5.2 兩個容易誤判的點

  • curl -kHTTP=000 不代表壞掉:8443 是 mTLS,不帶 client cert 本來就被拒。 診斷要用 openssl s_client 看握手(實測可見憑證 CN=本機指紋、issuer= CN = Guidant Agent CA (onprem-188)),或直接帶雲端的 client cert 測。
  • Docker Desktop 不會自動開防火牆:這點與 Linux 不同(Linux 版 docker 直接改 iptables)。實測 160 上沒有任何 Docker 建立的 inbound 規則。

5.3 T-7.2 規格

install.ps1 必須內建這一步(不能只寫在文件裡靠客戶手動做):

New-NetFirewallRule -DisplayName 'Guidant AI Agent data plane (8443)' `
  -Direction Inbound -Action Allow -Protocol TCP -LocalPort $DataPlanePort -Profile Any

建議:① 先查有無同名規則(重裝時 idempotent);② 埠號跟著 AGENT_DATA_PLANE_PORT 走,不寫死 8443(與 install.sh 集中一處的作法一致);③ 解除安裝時移除該規則。

⚠️ 未實測-Profile Any 在客戶的網域群組原則(GPO)環境下可能被覆蓋或禁止建立。 企業環境要留「規則建立失敗時明確報錯並給出手動指令」的退路。


6. 查證③:本機對外位址自動偵測

✅ 可用,語意等價

(Find-NetRoute -RemoteIPAddress 192.168.50.188 | Select-Object -First 1).IPAddress
# → 192.168.50.160

與 Linux ip route get <雲端IP> 取 src 欄的語意完全相同(都是問核心「往這個目的地 會從哪個來源位址出去」)。

T-7.2 規格

  1. 沿用 install.sh 的既有邏輯——偵測值只當預設值,仍要讓客戶確認/覆寫 (_detect_local_ip 的註解已說明:偵測是猜測不是事實,NAT/反向代理環境會錯)。
  2. 偵測失敗回空、不中止(互動模式改問客戶;非互動模式才 fail)。
  3. 組出的值要是 https://<IP>:<埠>,埠跟著 $DataPlanePort
  4. ⚠️ 不可在 WSL 內偵測(會得到 172.x)——這是 PowerShell 原生做的理由之一。

7. 查證④:重置與重新開通

7.1 分層實測(成本遞增,找出指紋在哪一層才漂移)

層級 操作 machine-id 容器 結論
1 wsl --shutdown(等同重開機/Docker Desktop Restart) 650cb79d… 不變 自動回來、healthy ✅ 指紋存活,雲端仍是同一筆 agent(id=6,指紋 9e382ac8…),心跳續傳
1b RDP 斷線(session 變 Disc 不變 續跑 ✅ engine 存活
2 Factory reset 等效:關閉 Docker Desktop → 刪 %LOCALAPPDATA%\Docker\wsl\disk\docker_data.vhdx → 重啟 650cb79d…83ca785e… ⚠️ image 與 volume 全清空 ⚠️ 指紋漂移9e382ac8…8e579991…
3 使用者登出 全滅 🔴 見 §8(新識別的自起缺口)

為什麼刪 vhdx 等於 factory resetDockerCli.exe 沒有 reset 子命令 (實測 -h 只有 SharedDrivesShutdownSwitchDaemonSwitchLinuxEngineSwitchWindowsEngineVerbose),GUI Settings→Reset 的資料層效果即是重建 docker_data 磁碟。實測後 image 與 volume 確實全空,與 GUI reset 行為一致。

7.2 重置後重新開通 SOP(實測驗證過)

前提:交付包目錄(含 .envdocker-compose.ymlcerts-in/factory/) 在 C:\onepack\... 這種宿主檔案系統路徑,不在 docker volume 內——所以 reset 不會動到它們。實測確認 reset 後 .env 與 compose 檔都還在。

# ① 重新載入 image(reset 清掉了)
docker load -i .\guidant-ai-agent-<版本>.image.tar
docker load -i .\chrislusf-seaweedfs-3.99.image.tar

# ② 重新啟動(設定完全不用重填)
docker compose up -d

實測結果:兩容器 47 秒內 healthy,agent 自動重新註冊。

⚠️ 但雲端會多一筆

 id |  name              | fp(前16碼)     | status |  last_seen_at
  6 | JEDI-WIN2025-01-AD | 9e382ac8c3ffb8e4 | active | 13:43:40   ← 舊的,不再心跳
  7 | JEDI-WIN2025-01-AD | 8e579991102671d0 | active | 14:02:23   ← 新的,活著

兩筆同名status 都是 active(舊的沒有自動轉成 inactive/offline), 差別只在 last_seen_at 停在重置前。

⚠️ 資料損失:reset 清掉三個關鍵 volume——agent-db(SQLite,upload_files 對照表)、agent-certs(mTLS 憑證)、seaweed-data證據檔本體)。 即「reset 前上傳的證據檔全部消失,且雲端那些 upload_uid 變成取不回的孤兒」。 這比指紋漂移嚴重得多,必須寫進 T-7.3 指引的警告

7.3 T-7.3 指引須寫入的 SOP 與警告

  1. 重置前:Docker Desktop 的 Reset 會刪除全部證據檔,不是只重置設定。 若需保留,先做 volume 匯出(工具未實作,屬缺口)。
  2. 重置後:兩行指令重開通(見 §7.2),設定不用重填
  3. 雲端側善後:舊的那筆 agent 需人工處理(停用/刪除),否則清單裡兩筆同名。 ⚠️ 未查證:雲端是否有「停用舊 agent」的 UI 操作、以及舊筆是否會自動轉 inactive——這屬 BE/FE 既有功能範圍,建議 T-7.3 前確認。
  4. 哪些操作安全:重開機、Docker Desktop Restart、wsl --shutdown、RDP 斷線 ——皆不會動到指紋與資料。只有 Settings→Reset(及等效的刪 vhdx/重灌 Docker Desktop)才會。

8. 🆕 新識別的擋路項:使用者登出 → agent 全滅(P0)

T-4.3 評估文件完全未涵蓋此項,但它是 Docker Desktop 路線最重的結構性限制。

8.1 實測

logoff <session>
→ quser: No User exists for *
→ Get-Process 'Docker Desktop','com.docker.backend' → 0 個
→ docker version → 連不上 npipe
→ 雲端 curl https://192.168.50.160:8443/health → HTTP=000(agent 離線)

容器的 restart: unless-stopped 在此毫無作用——不是容器掛了,是整個 docker engine 不存在了

8.2 兩條「無登入自起」路徑實測皆失敗

候選 實測結果
com.docker.serviceAutomatic 並啟動 服務 Running,但 docker version 仍連不上。該服務只是特權 helper,真正的 engine 在使用者態的 com.docker.backend
SYSTEM 身分的 AtStartup 排程跑 Docker Desktop.exe 進程起得來(SessionId=0)但 WSL distro 起不來wsl -l --running 為空),engine 永不就緒
Interactive 身分排程(無登入 session 時) 排程回報成功(LastTaskResult=0)但進程數 0——Interactive 排程在沒有互動 session 時無處可跑

8.3 為什麼這是 P0

落地版 agent 的部署想定是「裝在客戶的一台伺服器上、長期無人值守跑」。若前提變成 「必須有一個使用者始終保持登入狀態」,則:

  • 伺服器重開機後(更新、停電)agent 不會自己回來,要有人登入才活
  • 資安政策常要求閒置自動登出——那等於定期讓 agent 死一次
  • 這與 systemd 版「開機自起、無人值守」的產品體驗有實質落差

8.4 可能解法(皆未實測,供 T-7.2 決策)

  1. 自動登入專用帳號autologon + 該帳號 HKCU\Run 保留 Docker Desktop) ——最貼近「一直有 session」的做法,但要求機器保持一個常駐登入 session, 資安上要客戶接受(等同該帳號的桌面永遠開著)。
  2. 改用 Docker Engine on WSL2(不用 Docker Desktop)+WSL 的 systemd 支援+wsl.exe --exec 由排程觸發——繞開 Desktop 的 session 綁定, 但違背 D17「承載選 Docker Desktop、客戶不碰 Linux 層」的裁示
  3. 接受此限制,在 T-7.3 指引寫明「本形態需保持一個登入 session」, 並提供「重開機後如何恢復」的 SOP。
  4. Windows 原生版(D17 已裁示暫不討論)——此限制正是原生路線的價值之一。

🔴 這是需要決策者裁示的項目,不是 runner 可自行選擇的實作細節。建議在 T-7.2 開工前拍板,因為選 1 或 2 會實質改變 install.ps1 的形狀。


8A. 🆕 第二個新識別擋路項:宿主時鐘偏差 → 資料面全掛(2026-08-23 補記)

本節是 T-7.1 收工後、決策者實際操作雲端上傳時撞到的問題,當場查到根因,補記於此。

8A.1 症狀與根因

症狀:雲端「上傳檔案到 agent」失敗,UI 無明確錯誤。agent log:

WARNING:agent:data-plane JWT rejected on /blob: Signature has expired
ERROR:error_handler:Error in UnauthorizedError: 授權憑證無效
INFO:werkzeug:172.18.0.1 - - "POST /blob HTTP/1.1" 401 -

根因:160 的 Windows 時鐘與雲端相差 +16 小時(時區設在 Pacific Standard Time +CMOS 時鐘本身也快)。而資料面 JWT 的有效期是 exp ≈ now + 60score/agent_auth.py:8),且 pyjwt.decode() 未設 leewaycore/agent_auth.py:99-105,零容忍)。

⚠️ 所以:宿主時鐘與雲端相差超過 60 秒,資料面(/blob/detection)就 100% 失效。 控制面(enroll、heartbeat、任務 ack/result)不受影響——那些是 agent 主動撥出、 用 mTLS 憑證,不驗 JWT exp。這造成一個很難查的表象: agent 在雲端顯示 active、心跳正常、檢測任務跑得完,唯獨上傳/下載檔案壞掉。

8A.2 為什麼 Windows 特別容易踩到

Linux 版部署在客戶伺服器上,NTP 通常已由系統管理員配好。Windows 這台的實況:

  • 時區預設值錯(Pacific Standard Time)——重灌/新機常見
  • 這台是網域控制站(DomainRole=5,DC 預設不對外找時間伺服器, 時間來源是 Local CMOS Clock(自己的主機板電池)。所以 GUI 按「立即同步」 會顯示成功,但那是「跟自己同步」,時間永遠不會被修正——這是最誤導人的一點。
  • 偏差達 16 小時時,w32tm /resync 會回 「電腦並未 resync,因為沒有可用的時間資料」——訊息完全不指向真正原因 (實際是 NTP 取得成功、但偏差超過內建上限而拒絕套用)。 用 w32tm /stripchart /computer:<ntp> /samples:2 /dataonly 可證明 NTP 其實通、 並讀出精確偏差(本次量到 -57596.2s)。

8A.2b 診斷軌跡(錯誤訊息會隨偏差方向改變,這是判定根因的關鍵線索)

階段 log 錯誤 偏差
發現時 Signature has expired 160 16 小時
修時區+硬設時間後 The token is not yet valid (iat) 修過頭,160 1.7 秒
精準對齊後 無錯誤,上傳成功 容器雲端 0.7 秒

兩個方向都會 401,且訊息不同——expired 是本機太快、not yet valid (iat) 是本機太慢。 看到這兩句其中任一句,都可直接判定是時鐘問題,不必往憑證/網路/儲存設定查。

⚠️ 容差極小iatexpleeway=0,實測慢 1.7 秒就被拒。 最終停在「容器略快於雲端 0.7 秒」——刻意讓本機稍快,因為快一點只會少用掉一點 exp 的 60 秒額度,慢一點卻會直接撞 iat

8A.3 修法(實測有效)

# ① 時區
Set-TimeZone -Id "Taipei Standard Time"

# ② 時鐘(偏差過大時 w32tm 拒絕自動跳,直接設最快)
Set-Date -Date (Get-Date "<正確的當地時間>")

⚠️ 還有第三步,容易漏:Docker Desktop 的 Linux VM 有自己的時鐘, 宿主時間跳動後不會自動跟上。實測本次 VM 時鐘反而是對的(Aug 22 15:09 UTC), 但若 VM 也偏了,需:

docker run --rm --privileged --pid=host --entrypoint /usr/bin/bash <agent-image> `
  -c "nsenter -t 1 -m -u -i -n -- date -u -s '<正確 UTC>'"

🔴 不要用 hwclock -s——那是「從硬體時鐘讀回系統」,宿主 CMOS 本身錯的時候 會把 VM 的正確時間覆蓋成錯的(本次實測踩到,需再手動設回)。

⚠️ VM 時鐘要單獨對:本次實測宿主校到 +57ms 之後,容器內仍慢 602ms (VM 與宿主是兩個獨立時鐘,宿主 Set-Date 不會傳遞下去)。必須對 VM 再做一次 date -u -s,容器才會跟上。install.ps1 的時鐘檢查若只驗宿主,會漏掉這一層。

✅ 修完驗證:容器快雲端 0.7 秒,決策者實際操作雲端上傳成功(2026-08-23)。

8A.4 T-7.2 規格輸入(建議列為必做)

  1. 環境檢查加一項時鐘偏差檢查:install.ps1 向 CLOUD_ENDPOINT 取 HTTP Date 標頭(或呼叫一個雲端端點),與本機 UTC 比對; 偏差 > 30 秒即擋下並明確說明(不是警告,是擋——因為裝完也不能用)。 這比讓客戶事後撞到「上傳壞掉」再回頭查時鐘,成本低太多。
  2. 錯誤訊息要指名道姓:「本機時間與雲端相差 X 小時 Y 分,資料面認證會全部失敗。 請先校時:Set-TimeZone -Id "Taipei Standard Time"w32tm /resync」。
  3. T-7.3 指引加一節「校時」,並註明 DC 的特殊情況(不對外同步、GUI 按同步無效)。
  4. 考慮向雲端端反映exp = now + 60sleeway=0 對落地部署過於嚴苛 (客戶機時鐘漂移是常態)。這屬雲端側設計,不在本卡 scope,僅記錄供決策者評估 ——若要放寬,leeway 給 30~60 秒即可大幅降低此類客訴,安全性影響很小。

8A.5 對「未實測假設」的更新

本節同時實測到了原 §11 第 6 條列為未查證的一項: 雲端不會自動把離線 agent 轉狀態——重置後遺留的舊 agent(id=6) 在離線 9 小時後仍顯示 active。決策者已手動刪除該筆。


9. 全鏈驗收證據

9.1 重置前(agent id=6,指紋 9e382ac8…

POST /api/1.0/agents/tasks/5f0e3e63-…/ack    → 200
POST /api/1.0/agents/tasks/5f0e3e63-…/result → 200
INFO:agent:task 5f0e3e63-… 執行成功,上傳 1/1 份報告

雲端 compliance.agent_tasks id=13:succeededresult_refNmap掃描報告_192.168.50.123_20260823.html

9.2 重置後(agent id=7,指紋 8e579991…

雲端 compliance.agent_tasks id=14:succeeded,同樣產出報告。

9.3 證據落點確認

  • SeaweedFS 容器內 /dataguidant-evidence_10.idx 等 volume 檔
  • agent SQLite 在 /data/db/agent.db
  • 證據檔存在 160 本機,未上傳雲端(符合設計)

9.4 顯示名稱

AGENT_HOSTNAME=JEDI-WIN2025-01-AD → 雲端 remote_agents.name 正確顯示機器名 (非容器 ID)。compose 的 hostname: 設計在 Windows 同樣生效。


10. T-7.2 規格輸入彙總(本卡的主要交付)

# 規格 來源
1 Windows 專用 compose 檔(無 product_uuid 掛載),不動態改寫客戶的檔 §3.5
2 環境檢查不可照抄 install.sh 的指紋二源硬擋;改查「Docker Desktop 裝了沒/engine 通不通/版本」 §3.1、§4
3 內建防火牆規則建立(idempotent、跟著埠號、解安裝時移除、失敗要明確報錯) §5.3
4 第三題預設值用 Find-NetRoute,偵測值只當預設仍需確認 §6
5 解包用內建 tar.exe;sha256 用 Get-FileHash.ToLower() 比對 §2
6 docker load 要有進度提示(約 6 分鐘) §2
7 流程中不可有任何 registry pull(credential helper 在非互動 session 會炸) §2.1
8 自起策略需決策者裁示後才能定案 §8
9 維運子命令(status/logs/restart/fingerprint/configure-storage…)在 Windows 的載體 T-4.3 §3 建議 binary 子命令化;本卡未實測
10 TOFU 憑證確認的 PowerShell 實作(本卡走預先放 certs-in/cloud-ca.pem 的權宜路徑,未實測互動式指紋確認 ⚠️ 未實測

11. 未實測假設(逐條列出,不當成已驗)

  1. TOFU 互動式憑證確認流程——本卡直接把 cloud-ca.pem 放進 certs-in/ (⚠️探路權宜),未實測 PowerShell 抓憑證→印 SHA-256 指紋→人工確認→存錨的流程。
  2. upgrade 換版路徑——未測。同一顆 onepack 在 Windows 的升級行為(資料存活)未驗。
  3. configure-storage 恢復循環——未測(內建→自有→恢復內建)。
  4. 維運子命令(status/logs/fingerprint 等經 docker compose exec 轉呼叫)——未測。
  5. 防火牆規則在 GPO 網域環境能否建立成功——160 在網域內但未測 GPO 限制情境。
  6. 雲端側舊 agent 的善後——重置後舊筆是否會自動轉 inactive、UI 有無停用操作,未查。
  7. §8.4 的四個自起解法——皆未實測,僅列為候選。
  8. docker_data.vhdx 以外的 reset 路徑(GUI Settings→Reset 本尊、重灌 Docker Desktop) ——未實測,推定行為一致(同樣重建該磁碟)。
  9. Windows 11 上的行為——本機是 Server 2025。推定一致(同一個 Docker Desktop),未驗。
  10. agent 與 WinRM 受測角色長期並存——本次短時間並存無異狀,未做長時間觀察。

12. 160 機上的探路殘留物(請決策者裁示是否清除)

項目 位置 用途 建議
交付包與解開的目錄 C:\onepack\ 安裝來源+現行安裝目錄 保留(T-7.2 要繼續用)。.tar.gz(1.4GB)可刪
執行中的 agent 兩個容器 現正註冊在 DEV 雲端(agent id=7) 依 T-7.2 排程決定
防火牆規則 Guidant AI Agent data plane (8443) 查證② 建立 保留(T-7.2 要用)
排程工作 T71-StartDockerDesktop 探路時從 SSH 起 Docker Desktop 用 可刪(探路權宜,非產品的一部分)
188 的 SSH 公鑰 C:\ProgramData\ssh\administrators_authorized_keys 讓 188 免密 scp 傳包 依安全政策決定;T-7.2 若還要傳檔則保留
探路用小腳本 C:\onepack\probe.shcalc.shnsprobe.shnsprobe2.sh 指紋溯源用 可刪
DEV 雲端測試資料 agent_tasks id=13/14、remote_agents id=6/7 全鏈驗收證據 建議保留至 T-7.3 驗收後一併清

⚠️ 目前狀態:本次探路結束時 Docker Desktop 因無登入 session 而未運行 (見 §8),agent 目前離線。要恢復需有人登入 160,或由 SSH 起 Docker Desktop.exe -Autostart(但該進程會隨 SSH session 結束而死)。


13. 對 T-4.3 評估文件的修正建議

windows-feasibility.md評估、本文件是實測,兩者衝突處以本文件為準。 建議在 T-4.3 文件 §2.2 加一行指向本文件的註記(不改寫原文——那是當時的推理紀錄, 有保留價值),指出:

  1. §2.2 的「docker 自動建空目錄 → 靜默算錯」後果鏈未發生,實際是啟動硬失敗(§3.2)。
  2. §0 結論總表「④docker 過渡模式:卡點等級高(指紋)」——實測後,指紋本身的 卡點等級應下修為中(硬失敗、可預期、處理方式明確),但新增一項「自起」 為高(§8)。
  3. §2.3 的「待實測項:ip route get 在 WSL2 必錯」——正確,但正式路線根本不進 WSL, 改用 PowerShell Find-NetRoute 即無此問題(§6)。