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.
This commit is contained in:
@@ -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`.
|
||||
Reference in New Issue
Block a user