Resolve DA, A&C, and security spec gaps with ServerCapabilities, alarm methods, and modern profiles
Add ServerCapabilities/OperationLimits node, enable diagnostics, add OnModifyMonitoredItemsComplete override for DA compliance. Wire shelving, enable/disable, confirm, and addcomment handlers on alarm conditions with LocalTime/Quality event fields for Part 9 compliance. Add Aes128/Aes256 security profiles, X.509 certificate authentication, and AUDIT-prefixed auth logging. Fix flaky probe monitor test. Update docs for all changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,29 @@ Key configuration on the condition node:
|
||||
|
||||
The condition's `OnReportEvent` callback forwards events to `Server.ReportEvent` so they reach clients subscribed at the server level.
|
||||
|
||||
### Condition Methods
|
||||
|
||||
Each alarm condition supports the following OPC UA Part 9 methods:
|
||||
|
||||
- **Acknowledge** (`OnAcknowledge`) -- Writes the acknowledgment message to the Galaxy `AckMsg` tag. Requires the `AlarmAck` role.
|
||||
- **Confirm** (`OnConfirm`) -- Confirms a previously acknowledged alarm. The SDK manages the `ConfirmedState` transition.
|
||||
- **AddComment** (`OnAddComment`) -- Attaches an operator comment to the condition for audit trail purposes.
|
||||
- **Enable / Disable** (`OnEnableDisable`) -- Activates or deactivates alarm monitoring for the specific condition. The SDK manages the `EnabledState` transition.
|
||||
- **Shelve** (`OnShelve`) -- Supports `TimedShelve`, `OneShotShelve`, and `Unshelve` operations. The SDK manages the `ShelvedStateMachineType` state transitions including automatic timed unshelve.
|
||||
- **TimedUnshelve** (`OnTimedUnshelve`) -- Automatically called by the SDK when a timed shelve period expires.
|
||||
|
||||
### Event Fields
|
||||
|
||||
Alarm events include the following fields:
|
||||
|
||||
- `EventId` -- Unique GUID for each event, used as reference for Acknowledge/Confirm
|
||||
- `ActiveState`, `AckedState`, `ConfirmedState` -- State transitions
|
||||
- `Message` -- Alarm message from Galaxy `DescAttrName` or default text
|
||||
- `Severity` -- Galaxy Priority clamped to OPC UA range 1-1000
|
||||
- `Retain` -- True while alarm is active or unacknowledged
|
||||
- `LocalTime` -- Server timezone offset with daylight saving flag
|
||||
- `Quality` -- Set to Good for alarm events
|
||||
|
||||
## Auto-subscription to Alarm Tags
|
||||
|
||||
After alarm condition nodes are created, `SubscribeAlarmTags` opens MXAccess subscriptions for three tags per alarm:
|
||||
|
||||
@@ -185,7 +185,7 @@ Controls OPC UA transport security profiles and certificate handling. Defined in
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| `Profiles` | `List<string>` | `["None"]` | Security profiles to expose. Valid: `None`, `Basic256Sha256-Sign`, `Basic256Sha256-SignAndEncrypt` |
|
||||
| `Profiles` | `List<string>` | `["None"]` | Security profiles to expose. Valid: `None`, `Basic256Sha256-Sign`, `Basic256Sha256-SignAndEncrypt`, `Aes128_Sha256_RsaOaep-Sign`, `Aes128_Sha256_RsaOaep-SignAndEncrypt`, `Aes256_Sha256_RsaPss-Sign`, `Aes256_Sha256_RsaPss-SignAndEncrypt` |
|
||||
| `AutoAcceptClientCertificates` | `bool` | `true` | Auto-accept untrusted client certificates. Set to `false` in production |
|
||||
| `RejectSHA1Certificates` | `bool` | `true` | Reject client certificates signed with SHA-1 |
|
||||
| `MinimumCertificateKeySize` | `int` | `2048` | Minimum RSA key size for client certificates |
|
||||
|
||||
@@ -95,8 +95,23 @@ On startup, `OpcUaServerHost.StartAsync` calls `CheckApplicationInstanceCertific
|
||||
`LmxOpcUaServer` inherits from the OPC Foundation `StandardServer` base class and overrides two methods:
|
||||
|
||||
- **`CreateMasterNodeManager`** -- Instantiates `LmxNodeManager` with the Galaxy namespace URI, the `IMxAccessClient` for runtime I/O, performance metrics, and an optional `HistorianDataSource`. The node manager is wrapped in a `MasterNodeManager` with no additional core node managers.
|
||||
- **`OnServerStarted`** -- Configures redundancy, history capabilities, and server capabilities at startup. Called after the server is fully initialized.
|
||||
- **`LoadServerProperties`** -- Returns server metadata: manufacturer `ZB MOM`, product `LmxOpcUa Server`, and the assembly version as the software version.
|
||||
|
||||
### ServerCapabilities
|
||||
|
||||
`ConfigureServerCapabilities` populates the `ServerCapabilities` node at startup:
|
||||
|
||||
- **ServerProfileArray** -- `StandardUA2017`
|
||||
- **LocaleIdArray** -- `en`
|
||||
- **MinSupportedSampleRate** -- 100ms
|
||||
- **MaxBrowseContinuationPoints** -- 100
|
||||
- **MaxHistoryContinuationPoints** -- 100
|
||||
- **MaxArrayLength** -- 65535
|
||||
- **MaxStringLength / MaxByteStringLength** -- 4MB
|
||||
- **OperationLimits** -- 1000 nodes per Read/Write/Browse/RegisterNodes/TranslateBrowsePaths/MonitoredItems/HistoryRead; 0 for MethodCall/NodeManagement/HistoryUpdate (not supported)
|
||||
- **ServerDiagnostics.EnabledFlag** -- `true` (SDK tracks session/subscription counts automatically)
|
||||
|
||||
### Session tracking
|
||||
|
||||
`LmxOpcUaServer` exposes `ActiveSessionCount` by querying `ServerInternal.SessionManager.GetSessions().Count`. `OpcUaServerHost` surfaces this for status reporting.
|
||||
|
||||
@@ -11,13 +11,17 @@ There are two distinct layers of security in OPC UA:
|
||||
|
||||
## Supported Security Profiles
|
||||
|
||||
The server supports three transport security profiles in Phase 1:
|
||||
The server supports seven transport security profiles:
|
||||
|
||||
| Profile Name | Security Policy | Message Security Mode | Description |
|
||||
|-----------------------------------|---------------------|-----------------------|--------------------------------------------------|
|
||||
| `None` | None | None | No signing or encryption. Suitable for development and isolated networks only. |
|
||||
| `Basic256Sha256-Sign` | Basic256Sha256 | Sign | Messages are signed but not encrypted. Protects against tampering but data is visible on the wire. |
|
||||
| `Basic256Sha256-SignAndEncrypt` | Basic256Sha256 | SignAndEncrypt | Messages are both signed and encrypted. Full protection against tampering and eavesdropping. |
|
||||
| Profile Name | Security Policy | Message Security Mode | Description |
|
||||
|-----------------------------------|----------------------------|-----------------------|--------------------------------------------------|
|
||||
| `None` | None | None | No signing or encryption. Suitable for development and isolated networks only. |
|
||||
| `Basic256Sha256-Sign` | Basic256Sha256 | Sign | Messages are signed but not encrypted. Protects against tampering but data is visible on the wire. |
|
||||
| `Basic256Sha256-SignAndEncrypt` | Basic256Sha256 | SignAndEncrypt | Messages are both signed and encrypted. Full protection against tampering and eavesdropping. |
|
||||
| `Aes128_Sha256_RsaOaep-Sign` | Aes128_Sha256_RsaOaep | Sign | Modern profile with AES-128 encryption and SHA-256 signing. |
|
||||
| `Aes128_Sha256_RsaOaep-SignAndEncrypt` | Aes128_Sha256_RsaOaep | SignAndEncrypt | Modern profile with AES-128 encryption. Recommended for production. |
|
||||
| `Aes256_Sha256_RsaPss-Sign` | Aes256_Sha256_RsaPss | Sign | Strongest profile with AES-256 and RSA-PSS signatures. |
|
||||
| `Aes256_Sha256_RsaPss-SignAndEncrypt` | Aes256_Sha256_RsaPss | SignAndEncrypt | Strongest profile. Recommended for high-security deployments. |
|
||||
|
||||
Multiple profiles can be enabled simultaneously. The server exposes a separate endpoint for each configured profile, and clients select the one they prefer during connection.
|
||||
|
||||
@@ -44,7 +48,7 @@ Transport security is configured in the `Security` section of `appsettings.json`
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|--------------------------------|------------|--------------------------------------------------|-------------|
|
||||
| `Profiles` | `string[]` | `["None"]` | List of security profile names to expose as server endpoints. Valid values: `None`, `Basic256Sha256-Sign`, `Basic256Sha256-SignAndEncrypt`. Profile names are case-insensitive. Duplicates are ignored. |
|
||||
| `Profiles` | `string[]` | `["None"]` | List of security profile names to expose as server endpoints. Valid values: `None`, `Basic256Sha256-Sign`, `Basic256Sha256-SignAndEncrypt`, `Aes128_Sha256_RsaOaep-Sign`, `Aes128_Sha256_RsaOaep-SignAndEncrypt`, `Aes256_Sha256_RsaPss-Sign`, `Aes256_Sha256_RsaPss-SignAndEncrypt`. Profile names are case-insensitive. Duplicates are ignored. |
|
||||
| `AutoAcceptClientCertificates` | `bool` | `true` | When `true`, the server automatically trusts client certificates that are not already in the trusted store. Set to `false` in production for explicit trust management. |
|
||||
| `RejectSHA1Certificates` | `bool` | `true` | When `true`, client certificates signed with SHA-1 are rejected. SHA-1 is considered cryptographically weak. |
|
||||
| `MinimumCertificateKeySize` | `int` | `2048` | Minimum RSA key size (in bits) required for client certificates. Certificates with shorter keys are rejected. |
|
||||
@@ -142,7 +146,7 @@ Remove `None` from the `Profiles` list to prevent unencrypted connections:
|
||||
```json
|
||||
{
|
||||
"Security": {
|
||||
"Profiles": ["Basic256Sha256-SignAndEncrypt"]
|
||||
"Profiles": ["Aes256_Sha256_RsaPss-SignAndEncrypt"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -174,6 +178,32 @@ While UserName tokens are always encrypted by the OPC UA stack (using the server
|
||||
|
||||
Periodically inspect the `rejected/` directory. Certificates that appear here were presented by clients but were not trusted. If you recognize a legitimate client certificate, move it to the `trusted/` directory to grant access.
|
||||
|
||||
## X.509 Certificate Authentication
|
||||
|
||||
The server supports X.509 certificate-based user authentication in addition to Anonymous and UserName tokens. When any non-None security profile is configured, the server advertises `UserTokenType.Certificate` in its endpoint descriptions.
|
||||
|
||||
Clients can authenticate by presenting an X.509 certificate. The server extracts the Common Name (CN) from the certificate subject and assigns the `AuthenticatedUser` and `ReadOnly` roles. The authentication is logged with the certificate's CN, subject, and thumbprint.
|
||||
|
||||
X.509 authentication is available automatically when transport security is enabled -- no additional configuration is required.
|
||||
|
||||
## Audit Logging
|
||||
|
||||
The server generates audit log entries for security-relevant operations. All audit entries use the `AUDIT:` prefix and are written to the Serilog rolling file sink for compliance review.
|
||||
|
||||
Audited events:
|
||||
- **Authentication success**: Logs username, assigned roles, and session ID
|
||||
- **Authentication failure**: Logs username and session ID
|
||||
- **X.509 authentication**: Logs certificate CN, subject, and thumbprint
|
||||
- **Certificate validation**: Logs certificate subject, thumbprint, and expiry for all validation events (accepted or rejected)
|
||||
- **Write access denial**: Logged by the role-based access control system when a user lacks the required role
|
||||
|
||||
Example audit log entries:
|
||||
```
|
||||
AUDIT: Authentication SUCCESS for user admin with roles [ReadOnly, WriteOperate, AlarmAck] session abc123
|
||||
AUDIT: Authentication FAILED for user baduser from session def456
|
||||
X509 certificate authenticated: CN=ClientApp, Subject=CN=ClientApp,O=Acme, Thumbprint=AB12CD34
|
||||
```
|
||||
|
||||
## CLI Examples
|
||||
|
||||
The Client CLI supports the `-S` (or `--security`) flag to select the transport security mode when connecting. Valid values are `none`, `sign`, `encrypt`, and `signandencrypt`.
|
||||
|
||||
Reference in New Issue
Block a user