From 106fb8b149474efd205b3d02b881c93142e33d42 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 4 Jun 2026 15:26:32 -0400 Subject: [PATCH] docs(glauth): shared GLAuth standardization design (dev/test consolidation onto 10.100.0.35) Approved design: consolidate OtOpcUa, MxAccessGateway, ScadaBridge dev/test auth onto one shared GLAuth at 10.100.0.35:3893 (dc=zb,dc=local, plaintext). App-neutral source of truth in scadaproj/infra/glauth/; merged directory with gid families partitioned 55xx/56xx/57xx + multi-role/admin/serviceaccount; per-app Server repoints; incremental rollout keeping old glauths until verified. --- ...04-shared-glauth-standardization-design.md | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 docs/plans/2026-06-04-shared-glauth-standardization-design.md diff --git a/docs/plans/2026-06-04-shared-glauth-standardization-design.md b/docs/plans/2026-06-04-shared-glauth-standardization-design.md new file mode 100644 index 0000000..4a24211 --- /dev/null +++ b/docs/plans/2026-06-04-shared-glauth-standardization-design.md @@ -0,0 +1,140 @@ +# Shared GLAuth Standardization — Design + +> **Status:** Approved 2026-06-04. Next: `superpowers-extended-cc:writing-plans` → implementation plan. +> **Scope:** dev/test only. Production stays on real corporate AD (out of scope). + +## Goal + +Consolidate the three sister projects (OtOpcUa, MxAccessGateway, ScadaBridge) onto **one shared +GLAuth dev directory** running on the shared Docker host **`10.100.0.35:3893`**, replacing the +three separate LDAP setups in use today. This is the natural endpoint of the Auth-component +normalization: all three already use the shared `ZB.MOM.WW.Auth.Ldap` library (search-then-bind) +and already default to the same base DN `dc=zb,dc=local`. + +## Decisions (locked during brainstorming) + +| Decision | Choice | +|---|---| +| Environments | **Dev/test only** (prod → real AD, untouched) | +| Consolidation depth | **Full** — every dev instance points at 35 | +| Transport | **Plaintext** (`Transport=None`, `AllowInsecure=true`) — trusted lab subnet | +| Source of truth | **`scadaproj/infra/glauth/`** (app-neutral, next to the other shared `ZB.MOM.WW.*` components) — Approach A | + +## Architecture + +``` + scadaproj/infra/glauth/ ← single source of truth (git) + ├── config.toml (merged dc=zb,dc=local directory) + ├── docker-compose.yml (one `glauth` service, :3893) + └── README.md + │ deploy on 10.100.0.35: docker compose up -d + ▼ + GLAuth @ 10.100.0.35:3893 · datastore=config · baseDN dc=zb,dc=local · ldaps=false + ▲ ▲ + plaintext bind │ (None + AllowInsecure) │ + ┌──────────────┴───────────┐ ┌─────────┴─────────────────────┐ + Mac / OrbStack │ windev (10.100.0.48) + • ScadaBridge :9000/:9100 │ • MxGateway (MxAccessGw svc) + • OtOpcUa docker-dev │ • OtOpcUa (OtOpcUa svc) + (un-stubbed) +``` + +- One `glauth` container on `10.100.0.35:3893`, `datastore=config`, `baseDN=dc=zb,dc=local`, ldaps disabled. +- Every dev consumer: `Server=10.100.0.35`, `Port=3893`, `Transport=None`, `AllowInsecure=true`, `SearchBase=dc=zb,dc=local`. +- **Retired:** the `scadabridge-ldap` container (ScadaBridge `infra/docker-compose.yml`) and the windev-local glauth (`C:\publish\glauth`). +- **Consequences:** windev gains a runtime dependency on 35 for *new* logins (existing cookie sessions unaffected); deploying to 35 needs working access (see Prerequisites). + +## The merged directory + +One `dc=zb,dc=local` directory; group families partitioned into **non-overlapping gid ranges** (today +both existing GLAuth files reuse 5501–5505 — the collision to fix). **Each app maps only its own family +and ignores the rest**, so the families coexist with zero conflict. + +**Groups** + +| Family | Used by | Groups (gidnumber) | +|---|---|---| +| `SCADA-*` (55xx) | ScadaBridge roles (DB-mapped) | Admins 5501, Designers 5502, Deploy-All 5503, Deploy-SiteA 5504, Viewers 5505 | +| OPC-perm (560x) | OtOpcUa + MxGateway OPC-UA write model | ReadOnly 5601, WriteOperate 5602, WriteTune 5603, WriteConfigure 5604, AlarmAck 5605 | +| `Gw*` (561x) | MxGateway dashboard (config-mapped) | GwAdmin 5610, GwReader 5611 | +| `OtOpcUa-*` (57xx) | OtOpcUa AdminUI (DB-mapped) | Admins 5701, Designers 5702, Viewers 5703 | + +`SCADA-*` keeps its canonical 55xx numbers (already deployed). The OPC/`Gw` groups move off the old +5501–5505/5510 into 56xx to clear the clash. + +**Users** (all password `password`; uid ranges 50xx ScadaBridge / 51xx MxGateway / 52xx OtOpcUa) + +- **`serviceaccount`** (5999, `cn=serviceaccount,dc=zb,dc=local`, `search *` capability) — the *single* + bind account every app uses. Password `serviceaccount123`. ScadaBridge moves to it from `cn=admin`/`password`. +- **`multi-role`** (5005) — member of **every** group → all roles in all three apps (canonical cross-app QA login). +- **`admin`** (5001) — `SCADA-Admins` + `GwAdmin` + `OtOpcUa-Admins` → Administrator everywhere. +- Per-role testers: `designer`/`deployer`/`site-deployer` (ScadaBridge); `gwreader` (MxGateway Viewer); + `otdesigner`/`otviewer` (OtOpcUa); `readonly`/`writeop`/`writetune`/`writeconfig`/`alarmack` (OPC perms). + +## Per-app config changes + +Each consumer changes only its LDAP `Server` (+ a few keys). Shared service account +`cn=serviceaccount,dc=zb,dc=local` / `serviceaccount123`. + +- **ScadaBridge** (`docker/` + `docker-env2/`, central-node-a & -b `appsettings.Central.json`): + `Ldap:Server` `scadabridge-ldap`→`10.100.0.35`; `ServiceAccountDn` `cn=admin`→`cn=serviceaccount`, + `ServiceAccountPassword`→`serviceaccount123`. Rest unchanged (`SCADA-*` DB mappings already seeded). + Retire the `ldap` service in `infra/docker-compose.yml`; sequenced-recreate central nodes. +- **OtOpcUa docker-dev** (`docker-dev/docker-compose.yml`, all host containers) — **the un-stub**: + drop `Security__Ldap__DevStubMode=true`; add `Server=10.100.0.35`, `Port=3893`, `Transport=None`, + `AllowInsecure=true`, `SearchBase=dc=zb,dc=local`, `ServiceAccountDn=cn=serviceaccount,…`, + `ServiceAccountPassword=serviceaccount123`. Seed OtOpcUa DB mappings + `OtOpcUa-Admins→Administrator`, `OtOpcUa-Designers→Designer`, `OtOpcUa-Viewers→Viewer` (system-wide). +- **MxGateway** (windev `C:\publish\mxaccessgw\Server\appsettings.json`): `Ldap:Server` + `localhost`→`10.100.0.35`; `SearchBase` `dc=lmxopcua`→`dc=zb,dc=local`; `ServiceAccountDn`→`…dc=zb,dc=local`. + `Transport=None`/`AllowInsecure=true` already migrated; `GroupToRole` (`GwAdmin`/`GwReader`) unchanged. + Restart `MxAccessGw` (+ dependent `OtOpcUa` svc). +- **OtOpcUa (windev service)**: locate its deployed overlay; repoint `Server`→`10.100.0.35`, + `SearchBase`→`dc=zb,dc=local`, service account, and switch dev transport `Ldaps`→`None`+`AllowInsecure`. +- **Then** stop/disable the windev-local `glauth` service. + +## Rollout & rollback + +Incremental; **the old glauths stay up until the very end**, so every step is reversible by pointing +`Server` back. + +1. Stand up the shared glauth on 35 → verify via `ldapsearch` (bind `serviceaccount`; `multi-role` + `memberOf` spans all families). Nothing repointed yet. +2. Prove reachability from an OrbStack container to `10.100.0.35:3893` (the linchpin) before any app edit. +3. ScadaBridge `:9000` → recreate → browser-verify `multi-role` = 4 roles. Then `:9100`. +4. OtOpcUa docker-dev → un-stub + repoint + seed → recreate → verify. +5. windev MxGateway (backup appsettings) → restart → verify. Then windev OtOpcUa overlay. +6. Only once all green: stop/disable `scadabridge-ldap` + the windev-local glauth. + +**Rollback** per consumer: revert the one-line `Server` change (git revert on the Mac; `.bak` restore on +windev) and recreate/restart. Remove the shared glauth = `docker compose down` on 35. + +## Testing & verification + +- **LDAP layer:** `ldapsearch` bind `serviceaccount`; confirm each test user + `multi-role`'s `memberOf` + across all four families; bind each user to confirm `password`. +- **Per-app browser (macbook Chrome):** ScadaBridge `:9000`/`:9100` `multi-role` → 4 roles (via + `/auth/token`); OtOpcUa `:9200` → seeded roles; MxGateway `10.100.0.48:5130` → Administrator; windev OtOpcUa → AdminUI. +- **Role-gating spot-checks:** `gwreader`→MxGateway Viewer-only; `designer`→ScadaBridge design-only; + `otviewer`→OtOpcUa read-only. +- **Negative:** wrong password rejected everywhere; a user in no family of an app → denied there. + +## Prerequisites & open items (resolve in the plan) + +1. **Access to `10.100.0.35`** — SSH from this Mac is currently refused (`Permission denied`/connection + reset) and the windev→35 jump is administratively prohibited. Either re-authorize this Mac's key on 35, + or the user runs the final `docker compose up -d`. Artifacts are portable either way. +2. **OtOpcUa group key shape** — confirm OtOpcUa maps on the **short RDN** (`OtOpcUa-Admins`) the shared + lib returns vs the full-DN its `LdapGroupRoleMapping` entity comment shows, before seeding. +3. **OrbStack→LAN reachability** — verify ScadaBridge/OtOpcUa containers can reach `10.100.0.35:3893` + early (likely fine; it's the linchpin). `log()` if any consumer can't reach 35 rather than silently failing. +4. **windev OtOpcUa config path** — discovery step (less is known about this deployment than MxGateway). + +## Notes + +- `scadaproj` is a plain-files umbrella that is *also* a local git repo; `infra/glauth/` lives here as the + canonical source. Per-app config edits land on a `feat/*` branch per repo (merge on the user's go). + windev edits are deployment-only with `.bak` backups (like the GroupToRole / LDAP-key migrations done + 2026-06-04); repo templates optionally aligned. +- Related memory: `multi-role-cross-app-test-user`, `mxgateway-windev-deploy`, + `scadabridge-local-deploy-gotchas`, `auth-audit-normalization-in-progress`.