From aaaa55e211f6344f8955702891352d239475e969 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 12 Nov 2026 19:37:04 -0500 Subject: [PATCH] docs(#891): vd03 worker isolation + box-wide ApiInstall deny + backup lockdown Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi --- .../deploy/vd03-upgrade-b8b4c18f-to-master.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/deploy/vd03-upgrade-b8b4c18f-to-master.md b/docs/deploy/vd03-upgrade-b8b4c18f-to-master.md index 15aa8fee7..e03f408e3 100644 --- a/docs/deploy/vd03-upgrade-b8b4c18f-to-master.md +++ b/docs/deploy/vd03-upgrade-b8b4c18f-to-master.md @@ -379,3 +379,31 @@ Run over WinRM (owner-authorised for this upgrade) with staged scripts; the buil been re-pointed in the AdminUI and deployed as `9adc5590` (11:06:43 UTC, `/fleet` Applied, chip "In sync"). Client CLI reads: `…/Spindle/S1/MotorSpeedPct` Good (0, spindle idle), `…/Spindle/S1/Load` Good, `…/Spindle/S1/MaxRpm` `BadNodeIdUnknown` as expected, and the UNS `parts-count`/`parts-required` still present. + +## Worker isolation and box-wide denies (lmxopcua#891, 2026-11-12, owner-requested) + +The vd03 layout differs from QA. The install root is `E:\ApiInstall\OtOpcUa`, with no `app\` folder, and data lives in `E:\ApiInstall\OtOpcUa-data`. Copies containing secrets are spread across `E:\ApiInstall`: env/registry backups, `kek.key` files, and old `pki\own\private` copies in about a dozen `OtOpcUa.bak*` folders. So the deny covers **all of `E:\ApiInstall`** instead of listing each app folder. + +**Installer:** `E:\psrem-stage\otopcua-891-f47891ff\install`, master `f47891ff`. SHA256: `.ps1` `e0c11aea…41a3`, `.psm1` `f9425e4c…dfde`. + +```powershell +.\Install-ScriptWorkerIsolation.ps1 -InstallRoot E:\ApiInstall\OtOpcUa -HostServiceAccount LocalSystem ` + -DenyPaths E:\ApiInstall,E:\ApiInstall\OtOpcUa\pki,E:\ApiInstall\OtOpcUa-data,C:\ProgramData\ZB\kek,E:\psrem-stage +``` + +- **Order:** `-WhatIf`, then apply (12 steps changed), then a re-apply (12 steps unchanged). +- **What the record holds:** the folders in `-DenyPaths` (the installer drops the install root, because `InstallRootDeny` already covers it), the PE cache, worker read+execute on `script-worker\`, and the outbound firewall block. +- **`script-worker\` stays usable:** its explicit `(RX)` comes before the deny inherited from `E:\ApiInstall`. +- **`-ConfigureHostService` deliberately left out.** The vd03 runner is still `InProcess` (the default), so the host service environment is unchanged and no restart was needed. When the vd03 runner flip is scheduled, re-run with the same `-DenyPaths` **plus** `-ConfigureHostService`, then set `Scripting__Runner` and restart. + +**Backups locked down:** 39 files under `E:\ApiInstall` and `E:\psrem-stage` now have a protected DACL that allows only SYSTEM and Administrators: `*.reg`, `*envbak*.txt` and `*envnames*.txt`. That covers OtOpcUa, HG, mxgw and the ScadaBridge deploy backups. None were deleted. + +**Installer warnings checked:** +- The locked backups have protected DACLs by design. +- `kek.key` in `HistorianGateway\data`, `MxGateway\data`, `OtOpcUa-data` and `ScadaBridge` allows only SYSTEM (Read) and Administrators. + +None of them grants anything to Everyone, Users or RESTRICTED. + +**After:** `/health/ready` returns 200 for OtOpcUa `:9000`, Overview `:5320`, ScadaBridge `:8085`, mxgw `:5130` and HG `:5220`. + +**Rollback:** `-Uninstall`, which removes the recorded denies, the anchor service, the firewall rule and the PE cache ACLs. To undo the lockdown on a backup file, run `icacls /reset`.