This commit is contained in:
+63
-8
@@ -1415,7 +1415,7 @@ driver, device, field, allowed form, never the value. The same list, plus runnin
|
||||
warn-only resolution (**Running**, from driver-health diagnostics, fleet-wide), is shown as a banner on `/raw`,
|
||||
with a Re-check button.
|
||||
|
||||
#### Per-instance credential references (#835)
|
||||
#### Per-instance credential references (#835, #848, #849)
|
||||
|
||||
The namespace confines a reference to values provisioned for that driver *type*, but not to one *instance*: before
|
||||
#835 a Designer could create a Galaxy driver pointing at their own endpoint with
|
||||
@@ -1430,7 +1430,31 @@ that instance's **id or name**, case-insensitively.
|
||||
| `secret:galaxy/DRV-a/apikey`, `secret:galaxy/PlantA/apikey` | allowed — its own |
|
||||
| `secret:galaxy/gw/apikey`, `secret:galaxy/apikey` (no instance is called `gw` / `apikey`) | allowed — a shared key |
|
||||
| `secret:galaxy/DRV-b/apikey`, `secret:galaxy/PlantB/apikey`, `secret:galaxy/plantb` | **refused** — another instance's |
|
||||
| `env:OTOPCUA_GALAXY_…` | not checked — environment variables carry no instance convention (see residuals) |
|
||||
| `env:OTOPCUA_GALAXY_DRV_A_KEY`, `env:OTOPCUA_GALAXY_PLANTA_KEY` | allowed — its own (#849, see below) |
|
||||
| `env:GALAXY_MXGW_API_KEY`, `env:OTOPCUA_GALAXY_API_KEY` (no instance is called `API`) | allowed — a shared variable |
|
||||
| `env:OTOPCUA_GALAXY_DRV_B_KEY`, `env:OTOPCUA_GALAXY_PLANTB_KEY`, `env:GALAXY_MXGW_PLANTB` | **refused** — another instance's (#849) |
|
||||
|
||||
**`env:` references have the same rule (#849).** The convention is `env:<PREFIX><INSTANCE>_…` for every prefix of the
|
||||
driver's scope (`OTOPCUA_GALAXY_`, `GALAXY_MXGW_`, `OTOPCUA_OPCUACLIENT_`, `OTOPCUA_HEIDENHAIN_`), where `INSTANCE` is
|
||||
a driver id or name in environment form — ASCII letters upper-cased, digits kept, every other character `_`
|
||||
(`DRV-1a2b` ⇒ `DRV_1A2B`, `Line 1` ⇒ `LINE_1`). The part after the prefix **names** an instance when it equals that
|
||||
form or starts with it followed by `_` (so `PLANTB` names `env:OTOPCUA_GALAXY_PLANTB_KEY` but not
|
||||
`env:OTOPCUA_GALAXY_PLANTBX_KEY`). It is applied at every seam below with the same code
|
||||
(`CredentialReferenceOtherInstance`, message tagged `lmxopcua#849`). Because `_` both separates words and stands in for
|
||||
`-`/space, a variable can name more than one instance (`OTOPCUA_GALAXY_LINE_1_KEY` names both `Line` and `Line 1`); as
|
||||
for secrets, any match against another instance wins — use the id form (`env:OTOPCUA_GALAXY_DRV_1A2B_KEY`) for
|
||||
per-instance variables. Shared variables that start with no instance's id or name (`GALAXY_MXGW_API_KEY`) keep working.
|
||||
|
||||
- **Id-form references are matched by id only.** A reference whose instance part has the shape of a system-generated
|
||||
id — `secret:…/DRV-<12 hex>/…` or `env:<PREFIX>DRV_<12 HEX>` alone or followed by `_` — is never matched against
|
||||
driver **names**, so a driver named `drv` (env form `DRV`), or one named like another's id, cannot make every
|
||||
sibling's id-form variable "another instance's", whether that name was created before or after this rule. New names
|
||||
of that form are refused outright at create / rename / modal update (`DriverCredentialPolicy.IsReservedInstanceName`:
|
||||
env form `DRV` or starting with `DRV_<12 HEX>`).
|
||||
- **Name-form variables are only reliable for ASCII letter/digit names.** Normalisation turns every other character —
|
||||
including non-ASCII letters — into `_`, so `Linie Süd` and `Linie S_d` share `LINIE_S_D`, and a name with no ASCII
|
||||
letter or digit at all normalises to empty and gets **no** name protection (only its id does). Use the id form for
|
||||
per-instance variables.
|
||||
|
||||
Rules worth knowing:
|
||||
|
||||
@@ -1439,11 +1463,24 @@ Rules worth knowing:
|
||||
`secret:galaxy/<VictimName>/…`. Consequence: two same-type drivers that share a *name* cannot use name-scoped
|
||||
secrets — scope them by **driver id** (`secret:galaxy/<DriverInstanceId>/…`, ids are unique) instead.
|
||||
- A driver **being created** owns nothing yet, so any reference naming an existing instance is refused.
|
||||
- Creating or renaming a driver whose name equals a segment other drivers already use as a *shared* name makes those
|
||||
drivers' next deploy fail (`CredentialReferenceOtherInstance`) — rename the shared secret or the driver.
|
||||
- **A driver's name is checked against the references other drivers store (#848).** Creating a driver — or renaming
|
||||
one, through the `/raw` rename or the driver config modal — whose new name is the instance part of a reference
|
||||
**stored on another same-type driver** (its DriverConfig or any DeviceConfig; `secret:` segment or `env:` part) is
|
||||
refused at save (`DriverConfigSaveGate.ValidateNameAsync` → `DriverInstanceIdentities.DescribeNameChangeProblemsAsync`):
|
||||
otherwise naming a driver `gw` (or `API`, for `env:GALAXY_MXGW_API_KEY`) would turn every other driver's shared
|
||||
reference into "another instance's" and fail their next deploy. The message names the other driver, its id, the device
|
||||
and the field path — never the reference or a value.
|
||||
- **A driver cannot be renamed away from a name its own references are named after (#848).** If the driver's stored
|
||||
references (or the config being saved with the rename) use its *current name* — `secret:galaxy/PlantA/…`,
|
||||
`env:OTOPCUA_GALAXY_PLANTA_…` — and do not also name its id or the new name, the rename is refused: it would free
|
||||
the old name, and that reference would then look like an unclaimed shared name to every other driver's save, Test
|
||||
Connect and browse (the issue's "renaming the victim frees its name until the deploy gate runs" window). Move the
|
||||
reference to the id form first (the config modal can do both in one save), then rename. A case-only rename changes
|
||||
nothing the rule matches and is allowed. Id-scoped references are immune — ids never change.
|
||||
|
||||
One rule — `DriverCredentialPolicy.DescribeOtherInstanceProblems` — at the same seams as #815, reading the instance list
|
||||
through `DriverInstanceIdentities` (only when the config carries an in-scope `secret:` reference at all):
|
||||
through `DriverInstanceIdentities` (only when the config carries an in-scope `secret:` or `env:` reference at all — so
|
||||
since #849 a browse of an `env:`-only config also needs the ConfigDb and fails closed without one):
|
||||
|
||||
1. **AdminUI save** — `DriverConfigSaveGate.ValidateAsync` (every `RawTreeService` driver/device create + update; the
|
||||
owner is the driver itself, or the device's driver).
|
||||
@@ -1477,8 +1514,24 @@ config at its next deploy, and the upgrade preflight / `/raw` banner lists it (D
|
||||
the driver's own value under `galaxy/<its DriverInstanceId>/…` (or a shared name no instance uses) and point the field
|
||||
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); a reference to a
|
||||
Upgrade note (#848/#849): the `env:` rule is new, so a stored config whose variable starts with **another same-type
|
||||
driver's id or name** (e.g. a Galaxy driver named `API` beside `env:GALAXY_MXGW_API_KEY` users) is refused at its next
|
||||
deploy — the upgrade preflight / `/raw` banner lists it. Rename that driver (the #848 rename check allows it, since the
|
||||
references naming it belong to other drivers — unless its own references use the name too, in which case move those to
|
||||
its id form first) or move the other drivers' variables to their id form. Existing driver names are not
|
||||
re-checked against stored references except when they change.
|
||||
|
||||
Residuals (accepted): a **deleted** driver's id and name stop protecting its secrets and variables — after the delete
|
||||
any driver may reference `secret:galaxy/<deleted-id>/…` — so remove (or rotate) a deleted driver's secrets with it. The
|
||||
#848 rename pin does not stop a Designer who may edit the victim driver: a **single** config-modal save can move (or
|
||||
drop) its name-scoped reference and rename it in the same commit, after which the old name is free for any driver. That
|
||||
is the same "may author the victim's config ⇒ may redirect it" property as a saved endpoint change below (the save is a
|
||||
persisted, visible draft change, and the later credential use is audited) — use id-scoped references where this
|
||||
matters. For the same reason a low-severity race is accepted: a rename and a **concurrent** device save that adds a
|
||||
reference to the old name are not tied together (the driver's `RowVersion` does not cover its device rows), so both can
|
||||
commit and leave a device reference named after a name the driver no longer has — again needs a Designer who may author that driver's
|
||||
config, and audited at use. A variable is node-wide, so the `env:` rule
|
||||
constrains which driver may *name* it, not who can read the process environment. 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
|
||||
@@ -1503,7 +1556,9 @@ service account can read (another product's client certificate, a host certifica
|
||||
(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.
|
||||
a path past the gate. The upgrade preflight and the `/raw` banner run the same merged check
|
||||
(`CredentialReferenceDeployChecks.MergedOnlyProblems`, shared with the gate) and list such a split as a Draft finding
|
||||
"(merged with its devices)", so it shows before a deploy does (#850).
|
||||
- **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