Covers JWT authentication, subject mapping/transforms, OCSP support, Windows Service integration, per-subsystem logging, per-client trace, per-account stats, and TLS cert expiry in /varz.
161 lines
7.1 KiB
Markdown
161 lines
7.1 KiB
Markdown
# Remaining Lower-Priority Gaps — Design Document
|
|
|
|
**Goal:** Resolve all remaining lower-priority gaps from differences.md with full Go parity, bringing the .NET NATS server to feature completeness for single-server (non-clustered) deployments.
|
|
|
|
**Approach:** Full Go parity — implement all listed gaps including JWT authentication, subject mapping, OCSP, and quick wins.
|
|
|
|
---
|
|
|
|
## 1. JWT Authentication
|
|
|
|
The largest component. NATS uses standard JWT encoding (base64url header.payload.signature) with Ed25519 signing via the `nats-io/jwt/v2` Go library.
|
|
|
|
### New Files
|
|
|
|
- **`Auth/Jwt/NatsJwt.cs`** — JWT decode/encode utilities. Base64url parsing, header extraction, Ed25519 signature verification via NATS.NKeys. Detects JWT by `"eyJ"` prefix.
|
|
- **`Auth/Jwt/UserClaims.cs`** — User claim record: `Subject` (nkey), `Issuer` (account nkey), `IssuerAccount` (scoped signer), `Name`, `Tags`, `BearerToken`, `Permissions` (pub/sub allow/deny), `ResponsePermission`, `Src` (allowed CIDRs), `Times` (time-based access), `AllowedConnectionTypes`, `IssuedAt`, `Expires`.
|
|
- **`Auth/Jwt/AccountClaims.cs`** — Account claim record: `Subject`, `Issuer` (operator nkey), `SigningKeys`, `Limits`, `Exports`, `Imports`.
|
|
- **`Auth/Jwt/PermissionTemplates.cs`** — Template expansion for all 6 mustache-style templates:
|
|
- `{{name()}}` → user's Name
|
|
- `{{subject()}}` → user's Subject (nkey)
|
|
- `{{tag(name)}}` → user tags matching `name:` prefix
|
|
- `{{account-name()}}` → account display name
|
|
- `{{account-subject()}}` → account nkey
|
|
- `{{account-tag(name)}}` → account tags matching prefix
|
|
- Cartesian product applied for multi-value tags.
|
|
- **`Auth/Jwt/AccountResolver.cs`** — `IAccountResolver` interface (`FetchAsync`, `StoreAsync`, `IsReadOnly`) + `MemAccountResolver` in-memory implementation.
|
|
- **`Auth/JwtAuthenticator.cs`** — Implements `IAuthenticator`. Flow: decode user JWT → resolve account → verify Ed25519 signature against nonce → expand permission templates → build `NkeyUser` → validate source IP + time restrictions → check user revocation.
|
|
|
|
### Modified Files
|
|
|
|
- **`Auth/Account.cs`** — Add `Nkey`, `Issuer`, `SigningKeys` (Dictionary), `RevokedUsers` (ConcurrentDictionary<string, long>).
|
|
- **`NatsOptions.cs`** — Add `TrustedKeys` (string[]), `AccountResolver` (IAccountResolver).
|
|
- **`NatsClient.cs`** — Pass JWT + signature from CONNECT opts to authenticator.
|
|
|
|
### Design Decisions
|
|
|
|
- No external JWT NuGet — NATS JWTs are simple enough to parse inline (base64url + System.Text.Json + Ed25519 via NATS.NKeys).
|
|
- `MemAccountResolver` only — URL/directory resolvers are deployment infrastructure.
|
|
- User revocation: `ConcurrentDictionary<string, long>` on Account (nkey → issuedAt; JWTs issued before revocation time are rejected).
|
|
- Source IP validation via `System.Net.IPNetwork.Contains()` (.NET 8+).
|
|
|
|
---
|
|
|
|
## 2. Subject Mapping / Transforms
|
|
|
|
Port Go's `subject_transform.go`. Configurable source pattern → destination template with function tokens.
|
|
|
|
### New File
|
|
|
|
- **`Subscriptions/SubjectTransform.cs`** — A transform has a source pattern (with wildcards) and a destination template with function tokens. On match, captured wildcard values are substituted into the destination.
|
|
|
|
### Transform Functions
|
|
|
|
| Function | Description |
|
|
|----------|-------------|
|
|
| `{{wildcard(n)}}` / `$n` | Replace with nth captured wildcard token (1-based) |
|
|
| `{{partition(num,tokens...)}}` | FNV-1a hash of captured tokens mod `num` |
|
|
| `{{split(token,delim)}}` | Split captured token by delimiter into subject tokens |
|
|
| `{{splitFromLeft(token,pos)}}` | Split token into two at position from left |
|
|
| `{{splitFromRight(token,pos)}}` | Split token into two at position from right |
|
|
| `{{sliceFromLeft(token,size)}}` | Slice token into fixed-size chunks from left |
|
|
| `{{sliceFromRight(token,size)}}` | Slice token into fixed-size chunks from right |
|
|
| `{{left(token,len)}}` | Take first `len` chars |
|
|
| `{{right(token,len)}}` | Take last `len` chars |
|
|
|
|
### Integration
|
|
|
|
- `NatsOptions.SubjectMappings` — `Dictionary<string, string>` of source→destination rules.
|
|
- Transforms compiled at config time into token operation lists (no runtime regex).
|
|
- Applied in `NatsServer.DeliverMessage` before subject matching.
|
|
- Account-level mappings for import/export rewriting.
|
|
|
|
---
|
|
|
|
## 3. OCSP Support
|
|
|
|
Two dimensions: peer verification (client cert revocation checking) and stapling (server cert status).
|
|
|
|
### New File
|
|
|
|
- **`Tls/OcspConfig.cs`** — `OcspMode` enum (`Auto`, `Always`, `Must`, `Never`) + `OcspConfig` record with `Mode` and `OverrideUrls`.
|
|
|
|
### Peer Verification
|
|
|
|
- Modify `TlsConnectionWrapper` to set `X509RevocationMode.Online` when `OcspPeerVerify` is true.
|
|
- Checks CRL/OCSP during TLS handshake for client certificates.
|
|
|
|
### OCSP Stapling
|
|
|
|
- Build `SslStreamCertificateContext.Create(cert, chain, offline: false)` at startup — .NET fetches OCSP response automatically.
|
|
- Pass to `SslServerAuthenticationOptions.ServerCertificateContext`.
|
|
- `Must` mode: verify OCSP response obtained; fail startup if not.
|
|
|
|
### Modified Files
|
|
|
|
- `NatsOptions.cs` — `OcspConfig` and `OcspPeerVerify` properties.
|
|
- `TlsConnectionWrapper.cs` — Peer verification in cert validation callback.
|
|
- `NatsServer.cs` — `SslStreamCertificateContext` with OCSP at startup.
|
|
- `VarzHandler.cs` — Populate `TlsOcspPeerVerify` field.
|
|
|
|
---
|
|
|
|
## 4. Quick Wins
|
|
|
|
### A. Windows Service Integration
|
|
|
|
- Add `Microsoft.Extensions.Hosting.WindowsServices` NuGet.
|
|
- Detect `--service` flag in `Program.cs`, call `UseWindowsService()`.
|
|
- .NET generic host handles service lifecycle automatically.
|
|
|
|
### B. Per-Subsystem Log Control
|
|
|
|
- `NatsOptions.LogOverrides` — `Dictionary<string, string>` mapping namespace→level.
|
|
- CLI: `--log_level_override "NATS.Server.Protocol=Trace"` (repeatable).
|
|
- Serilog: `MinimumLevel.Override(namespace, level)` per entry.
|
|
|
|
### C. Per-Client Trace Mode
|
|
|
|
- `TraceMode` flag in `ClientFlagHolder`.
|
|
- When set, parser receives logger regardless of global `options.Trace`.
|
|
- Connz response includes `trace` boolean per connection.
|
|
|
|
### D. Per-Account Stats
|
|
|
|
- `long _inMsgs, _outMsgs, _inBytes, _outBytes` on `Account` with `Interlocked`.
|
|
- `IncrementInbound(long bytes)` / `IncrementOutbound(long bytes)`.
|
|
- Called from `DeliverMessage` (outbound) and message processing (inbound).
|
|
- `/accountz` endpoint returns per-account stats.
|
|
|
|
### E. TLS Certificate Expiry in /varz
|
|
|
|
- In `VarzHandler`, read server TLS cert `NotAfter`.
|
|
- Populate existing `TlsCertNotAfter` field.
|
|
|
|
### F. differences.md Update
|
|
|
|
- Mark all resolved features as Y with notes.
|
|
- Update summary section.
|
|
- Correct any stale entries.
|
|
|
|
---
|
|
|
|
## Task Dependencies
|
|
|
|
```
|
|
Independent (parallelizable):
|
|
- JWT Authentication (#23)
|
|
- Subject Mapping (#24)
|
|
- OCSP Support (#25)
|
|
- Windows Service (#26)
|
|
- Per-Subsystem Logging (#27)
|
|
- Per-Client Trace (#28)
|
|
- Per-Account Stats (#29)
|
|
- TLS Cert Expiry (#30)
|
|
|
|
Dependent:
|
|
- Update differences.md (#31) — blocked by all above
|
|
```
|
|
|
|
Most tasks can run in parallel since they touch different files. JWT and Subject Mapping are the two largest. The quick wins (26-30) are all independent of each other and of the larger tasks.
|