Claude-Session: https://claude.ai/code/session_013L3XdmVii9i5sY4FChU8pB
15 KiB
UG_WW_* → app role mapping (proposal)
Maps the Zimmer NAM UG_WW_* Active Directory groups onto the roles each ZB.MOM.WW app
actually implements. Inputs: the 39-group inventory in ldap_setup.md
(enumerated live 2026-08-12) and the standardized
CANONICAL-ROLES.md.
Status: PROPOSAL. The mechanical parts (
_RO_,_OPERATOR,APP_IDE,APP_ADMIN) are safe to adopt. Four items marked ⚠ DECIDE need a human answer before anyone writes them into a production config — they are listed in §6 and none of them can be resolved from the directory alone. Ignition's role set is deliberately out of scope.⚠️ ignitionoee (router): ON HOLD (decision 2026-08-13) — do not set up its LDAP. Its role vocabulary is outside the canonical set (admin role is literally
"Admin"), so no existingUG_WW_*group maps to it; wiring it to NAM AD requires minting new AD groups first. Revisit only once those groups exist and their mapping is decided.
1. The app role vocabularies (verified in source 2026-08-12)
Each app implements only a subset of the canonical six. This is the constraint that shapes everything below — there is no point mapping a group to a role an app does not have.
| App | Roles it actually implements | Where the mapping lives |
|---|---|---|
| OtOpcUa (AdminUI) | Viewer, Designer, Administrator |
Security:Ldap:GroupToRole (appsettings, merged with a DB overlay) |
| ScadaBridge | Viewer, Operator, Verifier, Designer, Deployer, Administrator |
LdapGroupMapping table (database, not config) |
| MxAccessGateway | Viewer, Administrator |
MxGateway:Dashboard:GroupToRole |
| HistorianGateway | Viewer, Administrator |
Dashboard:GroupToRole |
Three things follow that are easy to get wrong:
- OtOpcUa's LDAP mapping governs the AdminUI only. Since Gitea #520 (2026-08-01) the
OPC UA data plane does not use LDAP at all — a client presents an
otua_API key as an OPC UA UserName token. So a plant operator who only reads tags needs no AD group here; granting one gives them the configuration UI, which is not what anyone means by "operator access". TheCANONICAL-ROLES.mdrow showing OtOpcUa data-plane bundles predates that change and no longer applies to LDAP. Administratoris the literal string in all four apps. MxGateway's constant is namedDashboardRoles.Adminbut its value is"Administrator", and its validator rejects anything that is notAdministratororViewer.- Every app fails closed on zero matched groups. A user whose groups match no entry is denied. So an unmapped group grants nothing — the mapping does not have to be exhaustive, and leaving a group out is a safe default rather than an omission.
2. Group family → canonical role
UG_WW_* family |
Canonical | Confidence |
|---|---|---|
APP_IDE_RO_<env>, BTMGR_RO_<env> |
Viewer | firm — RO is unambiguous |
<SITE>_<AREA>_OPERATOR |
Operator | firm |
BTMGR_<PLANT>_<env> |
Operator | firm — batch execution is operate-level |
<SITE>_<AREA>_ENGINEER |
Engineer | firm canonically, but no app implements Engineer — see §6.1 |
APP_IDE_<env> |
Designer + Deployer | DECIDED — see §2.1 |
APP_ADMIN_<env> |
Administrator | firm |
HIST_ADMIN_<env> |
Administrator, historian-scoped | firm for HistorianGateway; see §4 for the others |
SITE_ADMIN_<SITE> |
Administrator (scoped) — not Deployer | ⚠ DECIDE — §6.2 |
<SITE>_<AREA>_SUPERVISOR |
Verifier? | ⚠ DECIDE — §6.3 |
<SITE>_SMS_TESTER |
— | ⚠ DECIDE — §6.4 |
CITRIX_<env> |
none — deliberately unmapped | firm — see below |
CITRIX_* is not a role and must not be mapped. It grants desktop/session access to a
Citrix farm, not authority within an application. Mapping it would hand app privileges to
everyone who merely has a published desktop — 12 people in QA alone — which is a
privilege-escalation path disguised as a convenience.
2.1 APP_IDE carries both Designer and Deployer — DECIDED
The ArchestrA IDE is both the authoring surface and the deployment surface: templates are
created there and pushed to runtime from the same tool, by the same person, in the same
session. So APP_IDE_<env> maps to both canonical roles, and APP_IDE_RO_<env> maps to
Viewer — read the Galaxy, change nothing, deploy nothing.
This closes §6.5: the AUTHOR/DEPLOY separation the canonical set describes does not
exist in this estate, and rather than inventing one, the mapping reflects how the tooling
actually works. It is a deliberate collapse, not an oversight.
Only ScadaBridge can express it. Its LdapGroupMapping is a row per (group, role)
pair and its RoleMapper accumulates matches into a HashSet<string>, so two rows against
the same group grant both roles. The other three apps bind GroupToRole as a
Dictionary<string, string> — one role per group, structurally; a duplicate key is a
config error, not a second grant. That is not a limitation in practice: none of those
three implements Deployer at all, so there is nothing to lose.
Consequence for SITE_ADMIN_*: §6.2 previously recommended mapping it to a site-scoped
Deployer. With Deployer now sourced from APP_IDE, that would mean two unrelated groups
granting the same authority by different routes, and would leave "site admin" meaning
nothing beyond what an IDE user already has. Administrator is the remaining reading — see
the revised §6.2, which raises rather than settles the blast-radius question.
3. The environment axis is per-deployment, not per-role
DEV/QA/PROD is orthogonal to role and has no representation in CanonicalRole.
Do not encode it into role names; that triples the role set and buys nothing.
Instead, each deployment maps only its own environment's groups. The mapping already lives in per-instance config, so this is free:
- the PROD instance's config lists
UG_WW_APP_ADMIN_PRODand never mentions_DEV - the DEV instance's config lists
UG_WW_APP_ADMIN_DEV
This is load-bearing, not cosmetic. A single config listing all three environments would make every DEV administrator a PROD administrator, silently, with no error anywhere.
The blocks in §4 are written for PROD. For DEV/QA, substitute the suffix. Note
CITRIX has no PROD group at all, which is further reason not to treat it as a role.
4. Per-app configuration
OtOpcUa — Security:Ldap:GroupToRole
"GroupToRole": {
"UG_WW_APP_ADMIN_PROD": "Administrator",
"UG_WW_SITE_ADMIN_WW19": "Administrator",
"UG_WW_APP_IDE_PROD": "Designer",
"UG_WW_APP_IDE_RO_PROD": "Viewer",
"UG_WW_HIST_ADMIN_PROD": "Viewer"
}
HIST_ADMIN gets Viewer because historization targets are authored in the OtOpcUa
AdminUI: a historian admin needs to see how tags are historized without being able to
change the address space. Plant-floor operator and engineer groups are deliberately
absent — the AdminUI is a configuration surface, and their runtime access is API-key
based (§1).
Replace WW19 with the site that owns the instance; see §6.2 before listing all eight.
ScadaBridge — LdapGroupMapping table
The only app with a role set rich enough to use most of the directory, and the only one where site scoping is real.
| Group | Role | Scope |
|---|---|---|
UG_WW_APP_ADMIN_PROD |
Administrator |
— |
UG_WW_APP_IDE_PROD |
Designer and Deployer — two rows (§2.1) |
— |
UG_WW_APP_IDE_RO_PROD |
Viewer |
— |
UG_WW_BTMGR_RO_PROD |
Viewer |
— |
UG_WW_SITE_ADMIN_<SITE> |
Administrator |
that site ⚠ §6.2 |
UG_WW_B19_SMS_OPERATOR |
Operator |
B19 |
UG_WW_B19_VitE_OPERATOR |
Operator |
B19 |
UG_WW_PON_PRESS_OPERATOR |
Operator |
PON |
UG_WW_WN_ARCOM_OPERATOR |
Operator |
WN |
UG_WW_WN_ARCOMXL_OPERATOR |
Operator |
WN |
UG_WW_WN_SOLAR_OPERATOR |
Operator |
WN |
UG_WW_WN_STERIS_OPERATOR |
Operator |
WN |
UG_WW_BTMGR_BE_PROD |
Operator |
BE |
UG_WW_BTMGR_MC_PROD |
Operator |
MC |
UG_WW_WN_STERIS_SUPERVISOR |
Verifier? |
WN ⚠ §6.3 |
UG_WW_B19_VitE_ENGINEER |
⚠ §6.1 | B19 |
UG_WW_PON_PRESS_ENGINEER |
⚠ §6.1 | PON |
The IDE grant is two rows against one group — this is the only place in the four apps where that is possible, and it is the row pair most likely to be entered as one:
INSERT INTO LdapGroupMapping (LdapGroupName, Role) VALUES
('UG_WW_APP_IDE_PROD', 'Designer'),
('UG_WW_APP_IDE_PROD', 'Deployer');
RoleMapper unions every matched row into a HashSet<string>, so the user comes out
holding both. A single row grants only what it names — there is no implicit widening, and
nothing will report the missing half.
MxAccessGateway — MxGateway:Dashboard:GroupToRole
"GroupToRole": {
"UG_WW_APP_ADMIN_PROD": "Administrator",
"UG_WW_APP_IDE_PROD": "Viewer",
"UG_WW_APP_IDE_RO_PROD": "Viewer"
}
Only two roles exist, so Designer collapses to Viewer: an IDE author has a legitimate
reason to browse Galaxy through the gateway dashboard, but no reason to administer API
keys. The gRPC surface is API-key authenticated and is not governed by this mapping.
HistorianGateway — Dashboard:GroupToRole
"GroupToRole": {
"UG_WW_HIST_ADMIN_PROD": "Administrator",
"UG_WW_APP_ADMIN_PROD": "Administrator",
"UG_WW_APP_IDE_RO_PROD": "Viewer",
"UG_WW_BTMGR_RO_PROD": "Viewer"
}
HIST_ADMIN is the exact-fit group for this app — it is the one place in the directory
whose name already means what the app's Administrator grants.
5. Blast radius
Worth doing the arithmetic before adopting, because these groups are larger than they look:
| Grant | People |
|---|---|
APP_ADMIN_PROD → Administrator |
5 |
SITE_ADMIN_* → Administrator, all 8 sites |
~48 |
APP_IDE_PROD → Designer |
4 |
all _OPERATOR groups → Operator |
~87 |
Mapping all eight SITE_ADMIN_* groups to Administrator on all four apps grants roughly
48 people full administrative control of every app, including the ones whose site has
nothing to do with the deployment. That is the single largest risk in this document, and
it is why §6.2 exists.
6. Open questions — DECIDE before adopting
6.1 Engineer has no home ⚠
_ENGINEER maps cleanly to canonical Engineer (OBSERVE + OPERATE + TUNE), and
no app implements it. OtOpcUa has Viewer/Designer/Administrator; ScadaBridge has
Operator/Verifier but no Engineer; the two gateways have Viewer/Administrator.
Options: (a) map _ENGINEER → Operator and accept that engineers lose TUNE;
(b) add an Engineer role to ScadaBridge; (c) leave unmapped, so the 18 people in the two
_ENGINEER groups get nothing. Recommendation: (a) for now — it is the honest subset,
grants no authority the group name does not imply, and can be widened later. Do not
silently map Engineer to Administrator to "cover" TUNE.
6.2 SITE_ADMIN_* — how much authority, and how many sites? ⚠
Narrowed by §2.1, not settled. Deployer now comes from APP_IDE, so site-scoped
Deployer is no longer available as the gentle reading of "site admin". What remains is
Administrator (scoped to the site), Viewer, or leaving it unmapped — and those are very
far apart.
This matters more than it did. There are eight of these groups at 6 members each, so
Administrator is the maximum grant in the vocabulary being handed to as many as ~48
people (§5). If a "site admin" is really a local IT contact rather than an application
owner, Administrator is badly wrong.
Second question, unchanged: which sites should a given deployment list? Every group has
exactly 6 members and they look like the same handful of people, but that is inference from
counts, not fact. Recommendation: list only the owning site, and confirm what the role
means before granting Administrator to any of them.
6.3 _SUPERVISOR → Verifier? ⚠
UG_WW_WN_STERIS_SUPERVISOR (6 members) is the only _SUPERVISOR group. ScadaBridge's
Verifier approves a two-person Secured Write that an Operator initiates, so a
supervisor approving an operator's action is a plausible reading — but "supervisor" could
equally mean a shift lead with no approval authority at all. Confirm with the group owner.
Whatever is decided, never map one group to both Operator and Verifier. The control
requires two distinct principals; a person holding both could initiate and approve their
own write, which removes the entire point of the mechanism while leaving it looking wired.
6.4 _TESTER ⚠
UG_WW_B19_SMS_TESTER (13 members) has no canonical equivalent and appears only in a QA
context. Leave unmapped until someone states what it is for — 13 people is too many to
guess at.
6.5 Deployer vs AUTHOR separation — RESOLVED
Closed by §2.1: APP_IDE grants both Designer and Deployer, because the ArchestrA IDE
authors and deploys from the same tool and the same session. The canonical AUTHOR/DEPLOY
split has no counterpart in this estate, and the mapping now records that as a decision
rather than leaving it to be discovered later. Same class of accepted SoD collapse already
noted in CANONICAL-ROLES.md.
7. Prerequisites
- Auth
0.2.1adopted — DONE 2026-08-13. All four apps pin0.2.1(OtOpcUamaster @ 08e33fc7, ScadaBridgemain @ d28824d9, MxAccessGatewaymain @ 1cb14d2, HistorianGatewaye42ff31, merged tomain; all pushed to origin). The continuation-referral defect (ldap_setup.md) is closed at the app level, so this mapping is exercisable once configs are authored. UG_WW_BTMGR_RO_QAis empty. It appears in the QA variant of the ScadaBridge and HistorianGateway tables; mapping it grants nobody anything today. Harmless, but do not read a working config as evidence that the grant works.- Verify with a real account before rollout. Every group in §4 was observed on one
long-tenured architect account, which holds every admin-flavoured group and no
operator group. The operator mappings are therefore untested against a real operator.
ldapprobe --self-bind <operator-account>settles it in one run — and specifically whether such an account has anymemberOfat all, since the library refuses a zero-group login (GroupLookupFailed) regardless of a correct password. - New groups are provisioned by ServiceNow ticket (the group descriptions are
TASK…ids). If §6 concludes that a group is missing — aVerifiercounterpart, or anEngineertier — that is a ticket, not a config change.