# Shared GLAuth Standardization — Design > **Status:** IMPLEMENTED + verified 2026-06-04 (all 18 plan tasks). See `shared-glauth-on-35` memory. > Plan: [`2026-06-04-shared-glauth-standardization.md`](2026-06-04-shared-glauth-standardization.md). > **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`.