docs: #873 SDK 2.0.1 API-key logins need client clock within 5 min ahead of the server (rollout runbook + security guide)
v2-ci / unit-tests (push) Waiting to run
v2-ci / unit-tests (push) Waiting to run
Claude-Session: https://claude.ai/code/session_01GT67AD99zQQqpLCVm3p7xk
This commit is contained in:
@@ -30,6 +30,17 @@ and smoke record; this runbook supplies no invented Linux service-unit name.
|
||||
Do not use `scripts/install/Refresh-Services.ps1` as a blanket upgrade action: it
|
||||
also touches gateway/retired sidecar paths outside this SDK rollout.
|
||||
|
||||
**Clock sync is a prerequisite (#873).** Under SDK 2.0.1 a client whose UserName password is longer
|
||||
than 64 bytes encrypts it as `RsaEncryptedSecret`, which carries a signing time. OtOpcUa API keys are
|
||||
65 characters, so every SDK 2 client, including our CLI and the OpcUaClient driver, does this. The
|
||||
2.0.1 server rejects the token with `BadIdentityTokenInvalid` if the client's signing time is more
|
||||
than **5 minutes ahead** of the server's clock, or more than 1 hour behind it. On windev, a clock
|
||||
549 s slow made every API-key login from the Mac fail, while the same key from the same host
|
||||
succeeded. Before upgrading, confirm the Windows Time service is running and the offset is small on
|
||||
the server **and** every SDK 2 client host (`w32tm /query /status`). SDK 1.5 clients (ScadaBridge
|
||||
today, ScadaBridge#125) are not affected. Since #874 the server logs these refusals under the SDK's
|
||||
`Opc.Ua.*` categories.
|
||||
|
||||
## Preserved contract
|
||||
|
||||
- Existing raw/UNS namespace URIs, identifier forms, endpoint profiles, API-key/anonymous
|
||||
|
||||
@@ -210,6 +210,11 @@ The Server accepts three OPC UA identity-token types:
|
||||
| UserName/Password | `ApiKeyOpcUaUserAuthenticator.AuthenticateUserNameAsync` (`src/Server/ZB.MOM.WW.OtOpcUa.Host/OpcUa/ApiKeyOpcUaUserAuthenticator.cs`, implements `IOpcUaUserAuthenticator`), backed by an `IApiKeyStore`. | The username is the literal `apikey` and the password is an `otua_<keyId>_<secret>` credential (#520). One indexed lookup plus one peppered HMAC-SHA256, no network I/O. The key resolves to a **principal**, whose `NodeAcl` grants become roles on a `RoleCarryingUserIdentity`. **LDAP is not on this path** — it backs AdminUI login only. |
|
||||
| X.509 Certificate | Stack-level acceptance during the secure-channel handshake. | The certificate must be trusted (see PKI trust flow). It carries **no** roles, so a cert-only session is read-everything / write-nothing. |
|
||||
|
||||
> **SDK 2.0.1 clock window (#873).** An SDK 2 client sends the API key as an `RsaEncryptedSecret` with a
|
||||
> signing time. The server rejects it with `BadIdentityTokenInvalid` when the client clock is more than
|
||||
> 5 minutes ahead of the server's, or more than 1 hour behind it. Keep client and server clocks in sync. The
|
||||
> refusal is logged under the SDK's `Opc.Ua.*` categories (#874); SDK 1.5 clients are unaffected.
|
||||
|
||||
When no authenticator is supplied, `OpcUaApplicationHost` falls back to `NullOpcUaUserAuthenticator`;
|
||||
the Host wires the real `ApiKeyOpcUaUserAuthenticator` as a singleton in `Program.cs`. Which
|
||||
**`IApiKeyStore`** backs it depends on the node's role:
|
||||
|
||||
Reference in New Issue
Block a user