feat(glauth): merged shared dev GLAuth directory + compose + runbook (10.100.0.35)
Phase 0 of the shared-GLAuth standardization. config.toml = merged dc=zb,dc=local directory (15 groups in partitioned 55xx/56xx/57xx families, 14 users incl. multi-role spanning all groups, serviceaccount search account). compose runs one glauth/glauth:latest on :3893. README is the deploy/verify runbook. Code-reviewed; fixed scp -r idempotency in the deploy command (README + plan Task 4).
This commit is contained in:
@@ -281,10 +281,14 @@ git commit -m "feat(glauth): merged shared dev GLAuth directory + compose + runb
|
||||
|
||||
**Step 1: Resolve access.** Confirm `ssh dohertj2@10.100.0.35 'echo ok'` works. If it does NOT (currently the case from this Mac), STOP and either (a) have the user re-authorize this Mac's key on 35, or (b) hand the user `infra/glauth/` + the deploy command to run on 35. Do not proceed past this gate until GLAuth is up on 35.
|
||||
|
||||
**Step 2: Deploy** (once access works):
|
||||
**Step 2: Deploy** (once access works). Copy the FILES into the dest dir (not the dir itself) so a
|
||||
re-deploy doesn't nest them at `~/zb-glauth/glauth/` (the `scp -r dir-into-existing-dir` trap):
|
||||
```bash
|
||||
scp -r /Users/dohertj2/Desktop/scadaproj/infra/glauth dohertj2@10.100.0.35:~/zb-glauth
|
||||
ssh dohertj2@10.100.0.35 'cd ~/zb-glauth && docker compose up -d && docker ps --filter name=zb-shared-glauth'
|
||||
ssh dohertj2@10.100.0.35 'mkdir -p ~/zb-glauth'
|
||||
scp /Users/dohertj2/Desktop/scadaproj/infra/glauth/config.toml \
|
||||
/Users/dohertj2/Desktop/scadaproj/infra/glauth/docker-compose.yml \
|
||||
dohertj2@10.100.0.35:~/zb-glauth/
|
||||
ssh dohertj2@10.100.0.35 'cd ~/zb-glauth && docker compose up -d --force-recreate && docker ps --filter name=zb-shared-glauth'
|
||||
```
|
||||
Expected: `zb-shared-glauth` container `Up`.
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# Shared dev GLAuth (`dc=zb,dc=local`)
|
||||
|
||||
One [GLAuth](https://github.com/glauth/glauth) directory that **all three sister apps use for
|
||||
dev/test auth** — OtOpcUa, MxAccessGateway, ScadaBridge. It runs as a single container on the
|
||||
shared Docker host **`10.100.0.35:3893`** (plaintext LDAP). This is the app-neutral source of
|
||||
truth; each app just points its `…Ldap:Server` at `10.100.0.35`.
|
||||
|
||||
> Scope: **dev/test only**. Production uses real corporate AD. See
|
||||
> [`../../docs/plans/2026-06-04-shared-glauth-standardization-design.md`](../../docs/plans/2026-06-04-shared-glauth-standardization-design.md).
|
||||
|
||||
## Directory layout
|
||||
|
||||
Group families are partitioned into **non-overlapping gid ranges** so the three apps coexist —
|
||||
each app maps only its own family and ignores the rest.
|
||||
|
||||
| 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 |
|
||||
|
||||
**Users** (all password `password` except `serviceaccount` → `serviceaccount123`):
|
||||
|
||||
- **`serviceaccount`** (`cn=serviceaccount,dc=zb,dc=local`) — the single bind account every app
|
||||
uses for search-then-bind. Has a `search *` capability.
|
||||
- **`multi-role`** — member of **every** group → all roles in all three apps (canonical cross-app login).
|
||||
- **`admin`** — `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).
|
||||
|
||||
## Deploy on `10.100.0.35`
|
||||
|
||||
> **Access note:** deploying needs working SSH/Docker access to `10.100.0.35`. If your key is not
|
||||
> authorized there, hand this folder to whoever administers the box and have them run the same
|
||||
> `docker compose up -d`. The artifact is self-contained.
|
||||
|
||||
```bash
|
||||
# From this repo root. Copy the FILES into the dest (not the dir) so a re-deploy
|
||||
# doesn't nest them at ~/zb-glauth/glauth/ (scp -r of a dir into an existing dir).
|
||||
ssh dohertj2@10.100.0.35 'mkdir -p ~/zb-glauth'
|
||||
scp infra/glauth/config.toml infra/glauth/docker-compose.yml dohertj2@10.100.0.35:~/zb-glauth/
|
||||
ssh dohertj2@10.100.0.35 'cd ~/zb-glauth && docker compose up -d --force-recreate && docker ps --filter name=zb-shared-glauth'
|
||||
```
|
||||
|
||||
## Verify
|
||||
|
||||
Bind as the service account and confirm `multi-role` spans all four families:
|
||||
|
||||
```bash
|
||||
ldapsearch -x -H ldap://10.100.0.35:3893 \
|
||||
-D cn=serviceaccount,dc=zb,dc=local -w serviceaccount123 \
|
||||
-b dc=zb,dc=local "(cn=multi-role)" memberOf
|
||||
# → result: 0 Success. memberOf comes back as group DNs (e.g. ou=SCADA-Admins,ou=groups,dc=zb,dc=local)
|
||||
# spanning all four families: SCADA-*, ReadOnly/Write*/AlarmAck, GwAdmin/GwReader, OtOpcUa-*.
|
||||
# (The shared ZB.MOM.WW.Auth.Ldap lib strips each to its bare RDN, e.g. "SCADA-Admins", at login.)
|
||||
```
|
||||
|
||||
Confirm a user authenticates with `password` (a bad password returns `result: 49`; this user lacks
|
||||
the search capability, so a successful bind shows `result: 50 Insufficient access` on the search):
|
||||
|
||||
```bash
|
||||
ldapsearch -x -H ldap://10.100.0.35:3893 \
|
||||
-D cn=multi-role,dc=zb,dc=local -w password \
|
||||
-b dc=zb,dc=local "(cn=multi-role)" cn
|
||||
```
|
||||
|
||||
No `ldapsearch` locally? Run it from a throwaway container:
|
||||
|
||||
```bash
|
||||
docker run --rm alpine:3.20 sh -c 'apk add -q openldap-clients >/dev/null 2>&1 && \
|
||||
ldapsearch -x -H ldap://10.100.0.35:3893 -D cn=serviceaccount,dc=zb,dc=local -w serviceaccount123 \
|
||||
-b dc=zb,dc=local "(cn=multi-role)" memberOf'
|
||||
```
|
||||
|
||||
## Editing the directory
|
||||
|
||||
GLAuth uses the `config` datastore (this `config.toml`, mounted read-only). To add/change a user
|
||||
or group, edit `config.toml` and **recreate** the container — a plain `restart` keeps the stale
|
||||
file (single-file Docker bind-mount inode trap):
|
||||
|
||||
```bash
|
||||
docker compose up -d --force-recreate
|
||||
```
|
||||
|
||||
Group `gidnumber`s and user `uidnumber`s must stay **unique** across the whole file; keep new
|
||||
groups inside the per-app range (55xx / 56xx / 57xx) so the families don't collide.
|
||||
@@ -0,0 +1,165 @@
|
||||
[ldap]
|
||||
enabled = true
|
||||
listen = "0.0.0.0:3893"
|
||||
|
||||
[ldaps]
|
||||
enabled = false
|
||||
|
||||
[backend]
|
||||
datastore = "config"
|
||||
baseDN = "dc=zb,dc=local"
|
||||
|
||||
[behaviors]
|
||||
# Dev: do not lock out on failed binds (avoids surprises during testing).
|
||||
LimitFailedBinds = false
|
||||
|
||||
# ── Groups ───────────────────────────────────────────────────────────
|
||||
# ScadaBridge role groups (55xx) — DB-mapped (LdapGroupMappings)
|
||||
[[groups]]
|
||||
name = "SCADA-Admins"
|
||||
gidnumber = 5501
|
||||
[[groups]]
|
||||
name = "SCADA-Designers"
|
||||
gidnumber = 5502
|
||||
[[groups]]
|
||||
name = "SCADA-Deploy-All"
|
||||
gidnumber = 5503
|
||||
[[groups]]
|
||||
name = "SCADA-Deploy-SiteA"
|
||||
gidnumber = 5504
|
||||
[[groups]]
|
||||
name = "SCADA-Viewers"
|
||||
gidnumber = 5505
|
||||
|
||||
# OPC-UA permission groups (560x) — OtOpcUa + MxGateway OPC write model
|
||||
[[groups]]
|
||||
name = "ReadOnly"
|
||||
gidnumber = 5601
|
||||
[[groups]]
|
||||
name = "WriteOperate"
|
||||
gidnumber = 5602
|
||||
[[groups]]
|
||||
name = "WriteTune"
|
||||
gidnumber = 5603
|
||||
[[groups]]
|
||||
name = "WriteConfigure"
|
||||
gidnumber = 5604
|
||||
[[groups]]
|
||||
name = "AlarmAck"
|
||||
gidnumber = 5605
|
||||
|
||||
# MxGateway dashboard groups (561x) — config-mapped (GroupToRole)
|
||||
[[groups]]
|
||||
name = "GwAdmin"
|
||||
gidnumber = 5610
|
||||
[[groups]]
|
||||
name = "GwReader"
|
||||
gidnumber = 5611
|
||||
|
||||
# OtOpcUa AdminUI role groups (57xx) — DB-mapped (LdapGroupRoleMapping)
|
||||
[[groups]]
|
||||
name = "OtOpcUa-Admins"
|
||||
gidnumber = 5701
|
||||
[[groups]]
|
||||
name = "OtOpcUa-Designers"
|
||||
gidnumber = 5702
|
||||
[[groups]]
|
||||
name = "OtOpcUa-Viewers"
|
||||
gidnumber = 5703
|
||||
|
||||
# ── Users ────────────────────────────────────────────────────────────
|
||||
# All passwords are "password" except serviceaccount ("serviceaccount123").
|
||||
# sha256("password") = 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
|
||||
# sha256("serviceaccount123") = af29d0e5c9801ae98a999ed3915e1cf428a64b4b62b3cf221b6336cce0398419
|
||||
|
||||
# The single bind account every app uses (search-then-bind).
|
||||
[[users]]
|
||||
name = "serviceaccount"
|
||||
uidnumber = 5999
|
||||
primarygroup = 5601
|
||||
passsha256 = "af29d0e5c9801ae98a999ed3915e1cf428a64b4b62b3cf221b6336cce0398419"
|
||||
[[users.capabilities]]
|
||||
action = "search"
|
||||
object = "*"
|
||||
|
||||
# Cross-app: member of EVERY group → all roles in all three apps.
|
||||
[[users]]
|
||||
name = "multi-role"
|
||||
givenname = "Multi"
|
||||
sn = "Role"
|
||||
mail = "multi-role@zb.local"
|
||||
uidnumber = 5005
|
||||
primarygroup = 5501
|
||||
othergroups = [5502, 5503, 5504, 5505, 5601, 5602, 5603, 5604, 5605, 5610, 5611, 5701, 5702, 5703]
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
|
||||
# Administrator everywhere (admin-equivalent of each app).
|
||||
[[users]]
|
||||
name = "admin"
|
||||
uidnumber = 5001
|
||||
primarygroup = 5501
|
||||
othergroups = [5610, 5701]
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
|
||||
# ScadaBridge single-role testers
|
||||
[[users]]
|
||||
name = "designer"
|
||||
uidnumber = 5002
|
||||
primarygroup = 5502
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
[[users]]
|
||||
name = "deployer"
|
||||
uidnumber = 5003
|
||||
primarygroup = 5503
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
[[users]]
|
||||
name = "site-deployer"
|
||||
uidnumber = 5004
|
||||
primarygroup = 5504
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
|
||||
# MxGateway dashboard Viewer tester
|
||||
[[users]]
|
||||
name = "gwreader"
|
||||
uidnumber = 5106
|
||||
primarygroup = 5611
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
|
||||
# OPC-UA permission testers
|
||||
[[users]]
|
||||
name = "readonly"
|
||||
uidnumber = 5101
|
||||
primarygroup = 5601
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
[[users]]
|
||||
name = "writeop"
|
||||
uidnumber = 5102
|
||||
primarygroup = 5602
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
[[users]]
|
||||
name = "writetune"
|
||||
uidnumber = 5103
|
||||
primarygroup = 5603
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
[[users]]
|
||||
name = "writeconfig"
|
||||
uidnumber = 5104
|
||||
primarygroup = 5604
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
[[users]]
|
||||
name = "alarmack"
|
||||
uidnumber = 5105
|
||||
primarygroup = 5605
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
|
||||
# OtOpcUa single-role testers (admin covers OtOpcUa-Admins)
|
||||
[[users]]
|
||||
name = "otdesigner"
|
||||
uidnumber = 5202
|
||||
primarygroup = 5702
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
[[users]]
|
||||
name = "otviewer"
|
||||
uidnumber = 5203
|
||||
primarygroup = 5703
|
||||
passsha256 = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
@@ -0,0 +1,15 @@
|
||||
# Shared dev GLAuth for OtOpcUa + MxAccessGateway + ScadaBridge.
|
||||
# Deploy on the shared Docker host 10.100.0.35: docker compose up -d
|
||||
# Verify: ldapsearch -x -H ldap://10.100.0.35:3893 \
|
||||
# -D cn=serviceaccount,dc=zb,dc=local -w serviceaccount123 \
|
||||
# -b dc=zb,dc=local "(cn=multi-role)" memberOf
|
||||
name: zb-shared-glauth
|
||||
services:
|
||||
glauth:
|
||||
image: glauth/glauth:latest
|
||||
container_name: zb-shared-glauth
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3893:3893"
|
||||
volumes:
|
||||
- ./config.toml:/app/config/config.cfg:ro
|
||||
Reference in New Issue
Block a user