Merge #835/#836 review fixes (owner check on unsaved endpoints, credential-use audit)
This commit is contained in:
+32
-6
@@ -1419,7 +1419,25 @@ through `DriverInstanceIdentities` (only when the config carries an in-scope `se
|
||||
3. **Test Connect** — `AdminOperationsActor`, before the probe; `TestDriverConnect.DriverInstanceId` names the owner
|
||||
(the device modal passes it; omitted ⇒ treated as a new driver, i.e. stricter).
|
||||
4. **Live browse** — `BrowserSessionService.OpenAsync(…, driverInstanceId, …)`, before any browser; `/raw` browse
|
||||
resolves the owner from the device. Without a ConfigDb it fails closed.
|
||||
resolves the owner from the device. Without a ConfigDb, or when the ConfigDb read faults, it is refused (a message on
|
||||
the modal, never a circuit error).
|
||||
|
||||
**An unsaved endpoint never gets the named owner's own secrets (review I-1).** Test Connect and browse take a config
|
||||
that may carry UNSAVED edits — the device modal merges the stored DriverConfig with the device config being typed — so
|
||||
naming the owner would otherwise let a Designer type their own host into a victim's device and Test Connect it with the
|
||||
victim's `secret:galaxy/<victim-id>/…`. The server (`DriverInstanceIdentities.EffectiveOwnerAsync`, called by the actor
|
||||
and by `BrowserSessionService` — the client's claim is not trusted) honours the named owner only when it exists, has the
|
||||
same type, and every **endpoint value** of the config (`DriverCredentialRules.EndpointFields`: Galaxy `Endpoint`,
|
||||
OpcUaClient `EndpointUrl`/`EndpointUrls`/`DiscoveryUrl`, Heidenhain `Host`/`Port`) is one that driver already stores
|
||||
(its DriverConfig or any DeviceConfig). Otherwise the owner is treated as null — no instance-named secret at all — and
|
||||
the refusal says to save the change first. Saving is the deliberate, persisted act; a saved endpoint change then
|
||||
behaves like any other saved config.
|
||||
|
||||
**Every credential-carrying Test Connect / browse is audited.** When the config carries an in-scope `secret:` or `env:`
|
||||
reference, `CredentialUseAudit` records an audit event (category `CredentialUse`, action `TestConnect` / `Browse`,
|
||||
actor = the signed-in user, target = the named driver or `(unsaved driver)`, outcome, and the endpoint host(s) — URI
|
||||
user-info dropped, never the reference or a value) through the shared `IAuditWriter`, plus a structured Information
|
||||
log line (`Credential use: …`).
|
||||
|
||||
Already-running drivers: a deployed driver resolves its reference exactly as before (the driver itself does not know
|
||||
the other instances, so the runtime adds no check) — the same deprecated window as #815: the deploy gate refuses the
|
||||
@@ -1428,10 +1446,11 @@ the driver's own value under `galaxy/<its DriverInstanceId>/…` (or a shared na
|
||||
at it.
|
||||
|
||||
Residuals (accepted): `env:` references are not instance-scoped (a variable is node-wide, and there is no naming
|
||||
convention to match — a deployment that needs per-instance isolation must use the secret store); and the rule cannot
|
||||
stop a Designer from editing an **existing** driver's endpoint and Test-Connecting with that driver's own reference —
|
||||
that is the general "anyone who may author config may redirect it" property described above (the lever is the page
|
||||
policy). A gateway-side complement — mxaccessgw binding each API key to the client identity / Galaxy it was issued for
|
||||
convention to match — a deployment that needs per-instance isolation must use the secret store); a reference to a
|
||||
**shared** name (one no instance is called) is not tied to any owner, so an unsaved endpoint can still be Test-Connected
|
||||
with it (audited); and a Designer who **saves** a new endpoint on an existing driver can then Test Connect / browse /
|
||||
deploy it with that driver's own reference — the general "anyone who may author config may redirect it" property
|
||||
described above (the save is persisted, the use is audited; the lever is the page policy). A gateway-side complement — mxaccessgw binding each API key to the client identity / Galaxy it was issued for
|
||||
— would make a captured key useless elsewhere; that is cross-repo (`mxaccessgw`) and not implemented here.
|
||||
|
||||
#### Key-material file paths are confined to a node directory (#836)
|
||||
@@ -1443,9 +1462,16 @@ service account can read (another product's client certificate, a host certifica
|
||||
- The field is a **relative path** (`plant1/user.pfx`) inside the node's user-certificate directory,
|
||||
**`Drivers:OpcUaClient:UserCertificateDirectory`** (env `Drivers__OpcUaClient__UserCertificateDirectory`; default
|
||||
`<LocalAppData>/OtOpcUa/pki/user-certificates`, beside the driver's PKI stores — for a service running as LocalSystem
|
||||
that is under `C:\Windows\System32\config\systemprofile\AppData\Local`). Segments are `[A-Za-z0-9._-]`; an absolute,
|
||||
that is under `C:\Windows\System32\config\systemprofile\AppData\Local`). A **relative** directory setting is resolved
|
||||
against the install directory (`AppContext.BaseDirectory`), never the working directory (a Windows service starts in
|
||||
`System32`). Segments are `[A-Za-z0-9._-]`; an absolute,
|
||||
rooted, drive-qualified or UNC path, `.`/`..`/empty segments and anything else are refused
|
||||
(`CredentialFilePaths`, rule row `DriverCredentialPolicy.OpcUaClientUserCertificatePathField`).
|
||||
- The rule applies unless the **same JSON object** explicitly sets `AuthType` to something other than `Certificate`
|
||||
(string or enum ordinal) — the driver never loads the file then, and the AdminUI form no longer persists the hidden
|
||||
field. An object without `AuthType` stays checked, and the deploy gate also checks the driver's config **as the
|
||||
runtime merges it with its devices**, so splitting `AuthType: Certificate` (device) from the path (driver) cannot slip
|
||||
a path past the gate.
|
||||
- **Refused at the same five seams as #815** (save, deploy gate `CredentialReferenceOutOfScope`, Test Connect, browse —
|
||||
messages never carry the path) and **at load time**: `OpcUaUserIdentityFactory.ResolveSecretRefsAsync` (called by the
|
||||
running driver and the AdminUI browse before the identity is built) joins it to the directory, canonicalises it, and
|
||||
|
||||
Reference in New Issue
Block a user