Files
scadalink-design/lmxproxy/docs/requirements/Component-Security.md
Joseph Doherty 683aea0fbe docs: add LmxProxy requirements documentation with v2 protocol as authoritative design
Generate high-level requirements and 10 component documents derived from source code
and protocol specs. Uses lmxproxy_updates.md (v2 TypedValue/QualityCode) as the source
of truth, with v1 string-based encoding documented as legacy context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 22:38:11 -04:00

5.1 KiB

Component: Security

Purpose

Provides API key-based authentication and role-based authorization for the gRPC service, along with TLS certificate management for transport security.

Location

  • src/ZB.MOM.WW.LmxProxy.Host/Security/ApiKeyService.cs — API key storage and validation.
  • src/ZB.MOM.WW.LmxProxy.Host/Security/ApiKeyInterceptor.cs — gRPC server interceptor for authentication/authorization.
  • src/ZB.MOM.WW.LmxProxy.Client/Security/GrpcChannelFactory.cs — Client-side TLS channel factory.

Responsibilities

  • Load and hot-reload API keys from a JSON configuration file.
  • Validate API keys on every gRPC request via a server interceptor.
  • Enforce role-based access control (ReadOnly vs ReadWrite).
  • Manage TLS certificates for server and optional mutual TLS.

1. API Key Service

1.1 Key Storage

  • Keys are stored in a JSON file (default apikeys.json).
  • File format: { "ApiKeys": [{ "Key": "...", "Description": "...", "Role": "ReadOnly|ReadWrite", "Enabled": true|false }] }.
  • If the file does not exist at startup, the service auto-generates a default file with two random keys: one ReadOnly and one ReadWrite.

1.2 Hot Reload

  • A FileSystemWatcher monitors the API key file for changes.
  • Rapid changes are debounced (1-second minimum between reloads).
  • ReloadConfigurationAsync uses a SemaphoreSlim to serialize reload operations.
  • New and modified keys take effect on the next request. Removed or disabled keys reject future requests immediately.
  • Active sessions are not affected by key changes — sessions are tracked independently by SessionManager.

1.3 Validation

  • ValidateApiKey(apiKey) — Returns the ApiKey object if the key exists and Enabled is true, otherwise null.
  • HasRole(apiKey, requiredRole) — Returns true if the key has the required role. Role hierarchy: ReadWrite implies ReadOnly.

2. API Key Interceptor

2.1 Authentication Flow

The ApiKeyInterceptor intercepts every unary and server-streaming RPC:

  1. Extracts the x-api-key header from gRPC request metadata.
  2. Calls ApiKeyService.ValidateApiKey().
  3. If the key is invalid or missing, returns StatusCode.Unauthenticated.
  4. For write-protected methods (Write, WriteBatch, WriteBatchAndWait), checks that the key has the ReadWrite role. Returns StatusCode.PermissionDenied if the key is ReadOnly.
  5. Adds the validated ApiKey to context.UserState["ApiKey"] for downstream use.
  6. Continues to the service method.

2.2 Write-Protected Methods

These RPCs require the ReadWrite role:

  • Write
  • WriteBatch
  • WriteBatchAndWait

All other RPCs (Connect, Disconnect, GetConnectionState, Read, ReadBatch, Subscribe, CheckApiKey) are allowed for ReadOnly keys.

3. API Key Model

Field Type Description
Key string The secret API key value
Description string Human-readable name for the key
Role ApiKeyRole ReadOnly or ReadWrite
Enabled bool Whether the key is active

ApiKeyRole enum: ReadOnly (read and subscribe only), ReadWrite (full access including writes).

4. TLS Configuration

4.1 Server-Side (Host)

Configured via TlsConfiguration in appsettings.json:

Setting Default Description
Enabled false Enable TLS on the gRPC server
ServerCertificatePath certs/server.crt PEM server certificate
ServerKeyPath certs/server.key PEM server private key
ClientCaCertificatePath certs/ca.crt CA certificate for mTLS client validation
RequireClientCertificate false Require client certificates (mutual TLS)
CheckCertificateRevocation false Check certificate revocation lists

If TLS is enabled but certificates are missing, the service generates self-signed certificates at startup.

4.2 Client-Side

ClientTlsConfiguration in the client library:

Setting Default Description
UseTls false Enable TLS on the client connection
ClientCertificatePath null Client certificate for mTLS
ClientKeyPath null Client private key for mTLS
ServerCaCertificatePath null Custom CA for server validation
ServerNameOverride null SNI/hostname override
ValidateServerCertificate true Validate the server certificate chain
AllowSelfSignedCertificates false Accept self-signed server certificates
IgnoreAllCertificateErrors false Skip all certificate validation (dangerous)
  • SSL protocols: TLS 1.2 and TLS 1.3.
  • Client certificates loaded from PEM files and converted to PKCS12.
  • Custom CA trust store support via chain building.

Dependencies

  • Configuration — TLS settings and API key file path from appsettings.json.
  • System.IO.FileSystemWatcher — API key file change detection.

Interactions

  • GrpcServer — the ApiKeyInterceptor runs before every RPC in ScadaGrpcService.
  • ServiceHost — creates ApiKeyService and ApiKeyInterceptor at startup, configures gRPC server credentials.
  • Client — GrpcChannelFactory creates TLS-configured gRPC channels in LmxProxyClient.