e347286f28
Add components/secrets/ (SPEC, realized shared-contract, code-verified current-state for OtOpcUa/mxaccessgw/ScadaBridge, GAPS adoption backlog) and register the Secrets row in CLAUDE.md + components/README.md. The ZB.MOM.WW.Secrets lib is built + published 0.1.2 + reference-consumer-proven (HistorianGateway, live vs the wonder historian); per-app adoption is the tracked follow-on.
4.3 KiB
4.3 KiB
OtOpcUa — secrets current state
Descriptive baseline (code-verified) of how OtOpcUa handles secrets today, before
adopting ZB.MOM.WW.Secrets. Paths are relative to ~/Desktop/OtOpcUa.
Where each secret lives today
| Secret | Location today | At-rest protection |
|---|---|---|
| ConfigDb (SQL Server) connstr password | Connection string ConfigDb / env OTOPCUA_CONFIG_CONNECTION (…Configuration/ServiceCollectionExtensions.cs:10,21-25; DesignTimeDbContextFactory.cs:16,25-31 — "Do not add a plaintext password as a fallback"); not in committed appsettings |
Whatever config source supplies it (plaintext) |
| LDAP service-account password | Security:Ldap:ServiceAccountPassword (Security/Ldap/LdapOptions.cs:22,60,63, bound Security/ServiceCollectionExtensions.cs:41); not in committed appsettings |
None |
| Deploy API key | Security:DeployApiKey compared via FixedTimeEquals (AdminUI/Api/DeployApiEndpoints.cs:30-54); disabled when unset |
Plaintext config value |
| HistorianGateway client API key | Env ServerHistorian__ApiKey (Runtime/Historian/ServerHistorianOptions.cs:41-46; appsettings ships "" + "NEVER commit") |
None (env at rest) |
| Galaxy/MxAccess gateway API key | GalaxyDriverOptions.ApiKeySecretRef resolved by GalaxySecretRef.cs:43-88 into 4 forms: env: / file: / dev: / literal; stored in the driver DriverConfig JSON in the central config DB |
env:/file: indirect out; dev:/literal are cleartext in the DB (self-documented GalaxySecretRef.cs:86) |
| OPC UA client-driver session + PFX passwords | OpcUaClientDriverOptions.Password / UserCertificatePassword in the driver DriverConfig JSON in the config DB (Driver.OpcUaClient/OpcUaClientDriver.cs:382,495) |
Plaintext in the config DB |
| JWT signing key | Security:Jwt:SigningKey (HS256, Jwt/JwtOptions.cs:5-9); not in committed appsettings |
Plaintext config value |
End-user login/OPC-UA passwords flow in-memory only (never persisted); the desktop client deliberately re-prompts each launch.
Encryption-at-rest today
- The only mechanism is ASP.NET Core Data Protection for the auth cookie/JWT payload —
not for any credential above:
Security/ServiceCollectionExtensions.cs:73-75(AddDataProtection().PersistKeysToDbContext<OtOpcUaConfigDbContext>().SetApplicationName("OtOpcUa")), key ring in the ConfigDbDataProtectionKeystable (OtOpcUaConfigDbContext.cs:70-73). No DPAPI, noProtectKeysWith*— the key ring itself is unencrypted-at-rest in SQL. - Log redaction (not at-rest):
Configuration/LocalCache/ResilientConfigReader.cs:76-89scrubsPassword|Pwd|User Id|AccessToken|Api-Keyfragments before logging.
Config expansion today
- None as a general mechanism (no
${...}expander; stockAddJsonFile+AddEnvironmentVariables+AddCommandLine,Host/Program.cs:59-73). The one partial exception is the driver-levelGalaxySecretRef(env:/file:/dev:/literal indirection,GalaxySecretRef.cs:23) which already anticipates "a future PR can swap any of these arms for a DPAPI-backed lookup" — a natural hook for${secret:}.
Adoption plan (toward SPEC)
- Highest value first: the driver
DriverConfigsecrets that sit cleartext in the config DB — the OpcUaClientPassword/UserCertificatePasswordand thedev:/literal Galaxy API-key arm. Add asecret:arm toGalaxySecretRef(and the OpcUaClient options) resolving throughISecretResolver, replacing the cleartext-in-DB path. - Pre-host
${secret:}forSecurity:Jwt:SigningKey,Security:Ldap:ServiceAccountPassword,Security:DeployApiKey, and theConfigDbconnstr password — expander runs before the existingLdap/OpcUaoptions validators. - Master key: env provider (
ZB_SECRETS_MASTER_KEY) per node. Clustered: OtOpcUa is Akka-clustered, so every node must resolve the same KEK — useFileMasterKeyProviderwith a shared mounted key, and when theZB.MOM.WW.Secrets.Akkareplicator is built, adopt it (or pointISecretStoreat the shared ConfigDb SQL store). See SPEC "Clustered pairs". - UI: mount
/admin/secretsin the AdminUI; map OtOpcUa's admin role onto the two policies. - Keep bespoke: the Data-Protection cookie/JWT key ring, in-memory end-user passwords, and the file-system OPC UA PKI Directory stores.