# Zimmer NAM — LDAP / Active Directory Auth Setup Reference for configuring services to authenticate against the Zimmer NAM domain. Extracted from the production Ignition 8.1 gateway `Ignition-IGNTN-APP-VP01` (`config.idb`, `NAM` AD-Hybrid user source), audited 2026-08-05. Full audit: `~/Desktop/config-idb-users-groups.md`. ## Directory / connection | Setting | Value | |---------|-------| | Domain | `nam.zimmer.com` | | Primary DC | `uswap-vdc-nam1:389` | | Secondary DC | `uswap-vdc-nam2:389` | | Encryption | **None** — plain LDAP on 389 (no LDAPS/StartTLS in the Ignition config) | | SASL | `DIGEST-MD5`, `CRAM-MD5` offered; QoP `auth-conf,auth-int,auth`; strength `high,medium,low`; no mutual auth | | Referrals | FOLLOW | | Read timeout | 60 000 ms | | Paging | 1000 entries/page | | Anonymous bind | Disallowed | ## Bind identity (UPN, not DN) - Service account: `svc_igntnapp` - Binds by **UPN**: `svc_igntnapp@nam.zimmer.com` — there is no bind DN/CN anywhere in the working config; end users also authenticate as `@nam.zimmer.com` (automatic suffix). - Password: held encrypted by the gateway; obtain from the credential owner — never commit it (in this repo's services use a `${secret:NAME}` reference). ## User lookup | Setting | Value | |---------|-------| | Search base | domain root `DC=nam,DC=zimmer,DC=com` (Ignition field left empty) | | User search filter | `(&(objectClass=user)(sAMAccountName={0}))` | | User enumeration filter | `(&(objectClass=user)(!(objectClass=computer)))` | | Username attribute | `sAMAccountName` | | Display name | `name` | | Email | `mail` | | Phone / SMS | `telephoneNumber` / `mobile` | ## Groups / roles **The working setup does not use LDAP groups at all.** The Ignition profile is AD-Hybrid: AD answers *who you are*, while *what you may do* (roles Administrator, Designer, Engineer, Maintenance, Management, Mfg_Tech, Operator) is assigned manually per user inside the application. AD security-group membership grants nothing. Implication for new services: don't assume a `memberOf`-based authorization scheme exists to mirror — there is no established group→role convention in this domain's SCADA stack. Either keep app-local role assignment (matching the existing pattern) or define new AD groups deliberately; standard AD attributes (`memberOf`, filter `(&(objectClass=group)(member={0}))`) are available if we choose to. ## Behavioral notes from the working config - Users are **populated on demand**: a local record is created on first successful AD login (with no roles until granted). - Failover: soft failover to the local internal user source, 60 s credential-cache validation — cached logins keep working through a DC outage. - Lockout: 5 failed attempts / 15-minute window. ## Cautions - Port 389 without TLS means simple binds transit cleartext unless SASL confidentiality is negotiated — for new .NET services prefer LDAPS (636) or StartTLS against the same DCs. ## TLS probe results (verified 2026-08-10, from the dev Mac) Both DCs were live-probed; **LDAPS and StartTLS both work on both DCs.** | Check | uswap-vdc-nam1 | uswap-vdc-nam2 | |---|---|---| | Ports open | 389, 636, 3268, 3269 | 389, 636, 3268, 3269 | | LDAPS (636) handshake | TLSv1.3 OK | TLSv1.3 OK | | StartTLS on 389 | OK | OK | | Anonymous rootDSE over LDAPS | `result: 0 Success` | `result: 0 Success` | | Cert subject/SAN | `USWAP-VDC-NAM1.nam.zimmer.com` (matches FQDN) | `USWAP-VDC-NAM2.nam.zimmer.com` (matches FQDN) | | Cert validity | 2026-03-21 → 2027-03-21 | 2026-03-20 → 2027-03-20 | | Chain | leaf ← `zimmer-issueca1` ← `zimmer-rootca` (intermediate served, root not) | same | | **Key size** | **RSA 1024-bit** (sha256 sig) | **RSA 1024-bit** (sha256 sig) | Implications for new .NET services: - **Use LDAPS 636** (or StartTLS) — no reason to accept cleartext binds. - **Trust:** `zimmer-rootca` is an internal CA, not in default OS/container trust stores. Either install the root (+ intermediate) into the host/container trust store, or pin the chain via `LdapOptions.ServerCertificateValidationCallback` (code-only seam in `ZB.MOM.WW.Auth.Ldap`). - **⚠️ RSA 1024-bit DC certs:** OpenSSL at default security level (SECLEVEL=2 — what Debian-based .NET containers ship) **rejects 1024-bit keys** (`EE certificate key too weak`, observed in this probe), so a Linux/container client may fail the TLS handshake even with the CA trusted. Windows/Schannel hosts accept them. Options: get the DC cert template reissued at 2048+ (right fix, needs AD PKI owner), or lower SECLEVEL / use a custom validation callback in affected containers (workaround). Certs expire 2027-03 — a reissue opportunity. - Hostnames resolve from the dev network: nam1 = `10.201.216.2`, nam2 = `10.201.138.78`.