docs(components): normalize Secrets component + index the shared lib

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.
This commit is contained in:
Joseph Doherty
2026-07-16 04:49:57 -04:00
parent de77bc30e3
commit e347286f28
9 changed files with 474 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
# Secrets — GAPS (adoption backlog)
The delta between each project's [`current-state`](current-state/) and the
[`SPEC`](spec/SPEC.md), as prioritized work. The library itself is **built + published +
reference-consumer-proven**; everything here is per-app adoption of an existing lib (not lib
construction).
## Cross-cutting observations
- **No app has `${secret:}` resolution today.** All three assemble config with the stock
`AddJsonFile`+`AddEnvironmentVariables` chain and read secrets verbatim. Two already lean
on the *pattern* the expander formalizes: ScadaBridge's non-functional `${SCADABRIDGE_*}`
placeholders (whole-key env override) and OtOpcUa's driver-level `GalaxySecretRef`
(`env:`/`file:`/`dev:`/literal). These are the natural first swaps.
- **The common high-value gap is plaintext credentials in appsettings/env:** LDAP
service-account passwords (all three), SQL connection-string passwords (OtOpcUa ConfigDb,
ScadaBridge ConfigDb + MachineDataDb), JWT/HS256 signing keys (OtOpcUa, ScadaBridge), and
API-key peppers (all three, runtime-supplied but plaintext).
- **Secrets already stored in a DB in plaintext are the sharpest edge:** OtOpcUa's OpcUaClient
`Password`/`UserCertificatePassword` and the `dev:`/literal Galaxy API key live cleartext in
the central config DB; ScadaBridge's MxGateway per-endpoint `ApiKey` lives plaintext in the
ConfigDb `DataConnections` JSON. These leak at rest to anyone with DB read.
- **Existing at-rest crypto is Data Protection, and only ScadaBridge applies it to secrets**
(4 encrypted ConfigDb columns via `EncryptedStringConverter`). OtOpcUa/mxaccessgw use Data
Protection only for cookies/tokens. None use DPAPI or `ProtectKeysWith*`; key rings are
unencrypted-at-rest. `ZB.MOM.WW.Secrets` adds envelope encryption with a KEK held **outside**
the store — a stronger boundary than "the DB is the only protection."
- **Peppered-HMAC API-key stores stay bespoke** (mxaccessgw + ScadaBridge): they are hashed,
not reversibly stored — already correct. Secrets only takes over the *pepper value* supply.
## Backlog (prioritized)
### G-1 — HistorianGateway reference consumer ✅ DONE
Adopted + live-proven 2026-07-16 (historian password via `${secret:}`, authenticated read
against the real wonder historian). This is the wiring template for the three apps.
### G-2 — OtOpcUa: cleartext-in-DB driver secrets (highest value)
Add a `secret:` arm to `GalaxySecretRef` (its own comment anticipates this) and to the
OpcUaClient driver options, resolving through `ISecretResolver` — retire the `dev:`/literal
and plaintext `Password`/`UserCertificatePassword` DB paths.
### G-3 — ScadaBridge: MxGateway `ApiKey` plaintext-in-ConfigDb
Resolve via `ISecretResolver` or extend the existing `EncryptedStringConverter` to that JSON
column.
### G-4 — Pre-host `${secret:}` for plaintext config secrets (all three)
LDAP passwords, SQL connstr passwords, JWT signing keys, deploy API key (OtOpcUa),
peppers — swap to `${secret:…}` tokens, expander running **before** each app's existing
validator (`ConfigPreflight` / `Ldap`+`OpcUa` validators / `GatewayOptionsValidator`).
Delete committed dev plaintext and the loose `*_login.txt` files (ScadaBridge).
### G-5 — Master-key provider per deployment
Env (`ZB_SECRETS_MASTER_KEY`) for containers; DPAPI for the Windows boxes; **File (shared
mounted key)** for clustered pairs (hard requirement — same KEK on every node).
### G-6 — Mount `/admin/secrets` UI (all three)
Add the RCL page to each dashboard (OtOpcUa AdminUI, MxGateway Server, ScadaBridge CentralUI)
and map each app's admin role onto `secrets:manage` / `secrets:reveal`.
### G-7 — Clustered replication (ScadaBridge, OtOpcUa) — build `ZB.MOM.WW.Secrets.Akka`
Deferred until G-2…G-6 land for a clustered app. Options per SPEC: shared SQL-Server
`ISecretStore` (simplest — mirrors the shared Data-Protection key ring) **or** the Akka
replicator (LWW, anti-entropy resync, tombstones). Requires a shared KEK.
### G-8 — KEK-rotation runbook + `RewrapAll`
The `RewrapAll(oldKek, newKek)` admin primitive + an operator runbook. Deferred (design-only
in this cut).
## Out of scope (this component)
- Akka remoting authentication/TLS (ScadaBridge plain TCP remoting) — a separate hardening
concern, not secret storage.
- SQL-Server `ISecretStore` provider construction (seam supports it; build with G-7).