From 22370ca4da7ade311dea3deec6832c9c75e428c6 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 4 Jun 2026 16:38:24 -0400 Subject: [PATCH] docs(glauth): repoint glauth.md at the shared GLAuth on 10.100.0.35 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No more per-box C:\publish\glauth NSSM service — dev/test LDAP is the shared zb-shared-glauth on 10.100.0.35:3893 (dc=zb,dc=local). Provisioning now via scadaproj/infra/glauth/config.toml. Old localhost/NSSM procedures kept as retired reference; test users multi-role/gw-viewer. --- CLAUDE.md | 2 +- glauth.md | 121 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 82 insertions(+), 41 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8cf6ea1..ff2705a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -100,7 +100,7 @@ When source code changes, build and test the affected component before reporting ## Design Sources To Consult Before Non-Trivial Changes - `gateway.md` — top-level architecture, command/event surface, IPC envelope, STA thread model, fault handling. -- `glauth.md` — local LDAP server (GLAuth on `localhost:3893`, base DN `dc=zb,dc=local`) used for dev authn. Pre-provisioned users (`admin/admin123`, `readonly/readonly123`, etc.) and the role→capability mapping live there. +- `glauth.md` — shared GLAuth LDAP server (`10.100.0.35:3893`, base DN `dc=zb,dc=local`, source of truth `scadaproj/infra/glauth/`) used for dev authn. Dashboard test users (`multi-role`/`password` = Administrator, `gw-viewer`/`password` = Viewer) and the role→capability mapping live there. - `docs/DesignDecisions.md` — v1 choices (MXAccess COM target `LMXProxyServerClass` from `C:\Program Files (x86)\ArchestrA\Framework\Bin\ArchestrA.MXAccess.dll`, API-key-in-SQLite auth, fail-fast event backpressure, etc.). - `docs/GatewayProcessDesign.md`, `docs/MxAccessWorkerInstanceDesign.md`, `docs/WorkerFrameProtocol.md`, `docs/WorkerProcessLauncher.md` — detailed component designs. - `docs/GatewayConfiguration.md` — full `MxGateway:*` options bound by `GatewayOptions` and validated at startup by `GatewayOptionsValidator`. diff --git a/glauth.md b/glauth.md index 0b57f55..32dd3c7 100644 --- a/glauth.md +++ b/glauth.md @@ -1,27 +1,36 @@ # GLAuth — LDAP authn reference for mxaccessgw -GLAuth is a lightweight LDAP server installed on this dev box at -`C:\publish\glauth\` and run as a Windows service via NSSM. It already -backs the LmxOpcUa OPC UA server's UserName-token authn and the LmxOpcUa -Admin UI's cookie login; this doc captures everything mxaccessgw needs -to consume the same directory so a single set of dev credentials covers -both stacks. +> **UPDATED 2026-06-04 — mxaccessgw no longer uses a per-box GLAuth at `C:\publish\glauth`. +> Dev/test LDAP is now the SHARED GLAuth on `10.100.0.35:3893` (`dc=zb,dc=local`); +> the single source of truth is `scadaproj/infra/glauth/` (`config.toml` + `README`). +> The localhost/NSSM/`glauth.cfg` procedures below are RETIRED, kept for reference/rollback.** -The authoritative copy of LmxOpcUa's reference lives at -`C:\publish\glauth\auth.md`. This doc is a redistilled view tailored to -mxaccessgw — what users + groups are already provisioned, how to bind -against them, and what's needed to add a gw-specific role. +GLAuth is a lightweight LDAP server. It already backs all three sister apps (MxAccessGateway, +OtOpcUa, ScadaBridge) through a **shared container** (`zb-shared-glauth`) running on the Linux +docker host at **`10.100.0.35:3893`**. This doc captures everything mxaccessgw needs to consume +that directory so a single set of dev credentials covers all stacks. + +~~GLAuth is installed on this dev box at `C:\publish\glauth\` and run as a Windows service via +NSSM.~~ *(RETIRED — the per-box Windows service has been stopped and set to Manual startup; +kept only as a rollback option. Do not edit or restart it for new work.)* + +The single source of truth for the shared GLAuth is +**`~/Desktop/scadaproj/infra/glauth/config.toml`** (deploy/verify runbook: +`scadaproj/infra/glauth/README.md`). This doc is a redistilled view tailored to mxaccessgw — +what users + groups are provisioned, how to bind against them, and what's needed to add a +gw-specific role. ## Connection details | Setting | Value | |---|---| | Protocol | LDAP (unencrypted) | -| Host | `localhost` | +| Host | **`10.100.0.35`** (shared docker host — ~~`localhost`~~ retired) | | Port | `3893` | -| LDAPS | disabled in dev (set `[ldaps]` block to enable) | +| LDAPS | disabled in dev (`Transport=None`, `AllowInsecure=true`) | | Base DN | `dc=zb,dc=local` | | Bind DN format | `cn={username},dc=zb,dc=local` | +| Service account DN | `cn=serviceaccount,dc=zb,dc=local` / `serviceaccount123` | | Group OU | `ou=,ou=groups,dc=zb,dc=local` | | Failed-bind throttle | 3 fails → 10-minute IP lockout (per `[behaviors]`) | @@ -59,13 +68,13 @@ For mxaccessgw dev, `admin` covers every gw-side capability test; `readonly` is the right "negative" case for proving Browse-OK / Write-denied. -The gateway dashboard adds one role beyond this LmxOpcUa taxonomy: -`GwAdmin`. `LdapOptions.RequiredGroup` defaults to `GwAdmin`, so the -dashboard login and `DashboardLdapLiveTests` require `admin` to be a -member of a `GwAdmin` group. `GwAdmin` is **not** in the baseline -GLAuth config — it must be provisioned before dashboard authn or the -LDAP live tests work. See [Provisioning the GwAdmin -group](#provisioning-the-gwadmin-group) below. +The gateway dashboard uses two gateway-specific groups beyond the LmxOpcUa taxonomy: +`GwAdmin` (gid 5610 → role `Administrator`) and `GwReader` (gid 5611 → role `Viewer`). +These are already provisioned in the shared `scadaproj/infra/glauth/config.toml`. +The dashboard test users are **`multi-role`/`password`** (Administrator) and +**`gw-viewer`/`password`** (Viewer). `LdapOptions.RequiredGroup` defaults to `GwAdmin`. +See [Provisioning the GwAdmin group](#provisioning-the-gwadmin-group) below for the +(now-retired) per-box procedure and for the shared-config equivalent. > **Dashboard role value (Task 1.7):** the LDAP `GwAdmin` group now maps to > the canonical dashboard role **`Administrator`** (was `Admin`); `GwReader` @@ -118,7 +127,7 @@ record: ```yaml ldap: enabled: true - server: localhost + server: 10.100.0.35 # shared GLAuth on docker host (was localhost) port: 3893 useTls: false allowInsecureLdap: true # dev only @@ -143,13 +152,29 @@ look that up in `groupToRole`. ## Provisioning the GwAdmin group +> **UPDATED 2026-06-04 — RETIRED per-box procedure.** `GwAdmin` (gid 5610) and `GwReader` +> (gid 5611) are already present in the shared GLAuth. To add or modify users/groups, +> edit **`~/Desktop/scadaproj/infra/glauth/config.toml`** on host `10.100.0.35` and run: +> +> ```bash +> cd ~/Desktop/scadaproj/infra/glauth +> docker compose up -d --force-recreate +> ``` +> +> The per-box `C:\publish\glauth\glauth.cfg` + NSSM procedure below is kept for +> rollback reference only — do not use it for new provisioning. + `GwAdmin` is the gateway-specific dashboard-admin role. It is the default `LdapOptions.RequiredGroup`, so the dashboard cookie login and `DashboardLdapLiveTests` (`MXGATEWAY_RUN_LIVE_LDAP_TESTS=1`) reject -`admin` until a `GwAdmin` group exists and `admin` is a member. -GLAuth's baseline config ships only the five LmxOpcUa role groups, so -`GwAdmin` must be added to GLAuth rather than run from a separate LDAP -server: +logins unless the user is a member of `GwAdmin`. +The `GwAdmin` (gid 5610) and `GwReader` (gid 5611) groups already exist in the shared +config at `scadaproj/infra/glauth/config.toml`. Dashboard test users are +`multi-role`/`password` (Administrator) and `gw-viewer`/`password` (Viewer). + +--- + +**RETIRED — per-box provisioning (reference/rollback only):** 1. Edit `C:\publish\glauth\glauth.cfg` 2. Append the group: @@ -199,15 +224,16 @@ echo -n "yourpassword" | openssl dgst -sha256 ## Quick verification -From mxaccessgw's dev box, prove the directory is reachable: +From mxaccessgw's dev box, prove the shared directory is reachable: ```powershell # Plain bind via PowerShell + System.DirectoryServices.Protocols -$ldap = New-Object System.DirectoryServices.Protocols.LdapConnection("localhost:3893") +# (shared GLAuth on 10.100.0.35 — was localhost, now the docker host) +$ldap = New-Object System.DirectoryServices.Protocols.LdapConnection("10.100.0.35:3893") $ldap.AuthType = [System.DirectoryServices.Protocols.AuthType]::Basic $ldap.SessionOptions.ProtocolVersion = 3 $ldap.SessionOptions.SecureSocketLayer = $false -$cred = New-Object System.Net.NetworkCredential("cn=admin,dc=zb,dc=local","admin123") +$cred = New-Object System.Net.NetworkCredential("cn=multi-role,dc=zb,dc=local","password") $ldap.Bind($cred) "Bind OK" ``` @@ -215,17 +241,32 @@ $ldap.Bind($cred) Or via `ldapsearch` if you have OpenLDAP CLI tools: ```bash -ldapsearch -x -H ldap://localhost:3893 \ - -D "cn=admin,dc=zb,dc=local" -w admin123 \ - -b "dc=zb,dc=local" "(uid=admin)" +ldapsearch -x -H ldap://10.100.0.35:3893 \ + -D "cn=serviceaccount,dc=zb,dc=local" -w serviceaccount123 \ + -b "dc=zb,dc=local" "(uid=multi-role)" ``` -The response should list `admin`'s entry with `memberOf` populated for -all five role groups — plus `GwAdmin` once the gateway-specific group -is provisioned. +The response should list `multi-role`'s entry with `memberOf` including +`ou=GwAdmin,ou=groups,dc=zb,dc=local`. ## Service management +> **RETIRED — per-box NSSM service (reference/rollback only).** The shared GLAuth is +> managed via `docker compose` on `10.100.0.35` (`scadaproj/infra/glauth/`). The +> Windows NSSM `GLAuth` service on the dev box has been stopped and set to +> `StartupType=Manual`; only restart it if you need to roll back to a local directory. +> +> **Active (shared) management:** +> ```bash +> ssh 10.100.0.35 +> cd ~/Desktop/scadaproj/infra/glauth +> docker compose ps # check container status +> docker compose up -d --force-recreate # apply config.toml changes +> docker compose logs -f # tail logs +> ``` + +**RETIRED — per-box NSSM commands (rollback reference):** + ```powershell # Status / start / stop / restart nssm status GLAuth @@ -259,7 +300,7 @@ applies to mxaccessgw verbatim. Keys that change: | Field | GLAuth dev value | AD production value | |---|---|---| -| `Server` | `localhost` | a domain controller FQDN, or the domain itself | +| `Server` | `10.100.0.35` (shared docker host) | a domain controller FQDN, or the domain itself | | `Port` | `3893` | `636` (LDAPS) — AD increasingly rejects plain bind under LDAP-signing enforcement | | `UseTls` | `false` | `true` | | `AllowInsecureLdap` | `true` | `false` | @@ -275,12 +316,12 @@ add a `tokenGroups` query as an enhancement. ## Security notes for production -- **Plaintext passwords in `glauth.cfg` are dev-only.** The config is - unencrypted on disk; anyone with read access to `C:\publish\glauth\` - can SHA256-rainbow-table the entries. Treat the dev creds as - throwaway. Production LDAP is Active Directory. +- **Plaintext passwords in `config.toml` are dev-only.** The shared config is in + `scadaproj/infra/glauth/config.toml` (unencrypted); restrict filesystem access on + `10.100.0.35` accordingly. Treat the dev creds as throwaway. Production LDAP is Active + Directory. *(The retired per-box `C:\publish\glauth\glauth.cfg` has the same caveat.)* - The 3-fail / 10-minute lockout is per source IP, not per user — a shared NAT can lock out a whole office. Tunable in `[behaviors]`. - LDAPS isn't enabled in dev; binding sends passwords cleartext on the - wire. Fine for `localhost`, never expose port 3893 off-box without - enabling TLS first. + wire. The shared GLAuth listens only on the LAN (`10.100.0.35`); never + expose port 3893 externally without enabling TLS first.