LmxProxy is no longer needed. Moved the entire lmxproxy/ workspace, DCL adapter files, and related docs to deprecated/. Removed LmxProxy registration from DataConnectionFactory, project reference from DCL, protocol option from UI, and cleaned up all requirement docs.
120 lines
5.1 KiB
Markdown
120 lines
5.1 KiB
Markdown
# 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.
|