diff --git a/clients/dotnet/DotnetClientDesign.md b/clients/dotnet/DotnetClientDesign.md index fd913b5..4124f3d 100644 --- a/clients/dotnet/DotnetClientDesign.md +++ b/clients/dotnet/DotnetClientDesign.md @@ -107,6 +107,7 @@ public sealed class MxGatewayClientOptions public required string ApiKey { get; init; } public bool UseTls { get; init; } public string? CaCertificatePath { get; init; } + public bool RequireCertificateValidation { get; init; } public string? ServerNameOverride { get; init; } public TimeSpan ConnectTimeout { get; init; } = TimeSpan.FromSeconds(10); public TimeSpan DefaultCallTimeout { get; init; } = TimeSpan.FromSeconds(30); @@ -124,6 +125,24 @@ or subscription changes because those calls can partially succeed in MXAccess. API key may be loaded from `MXGATEWAY_API_KEY` by the CLI, not implicitly by the library constructor unless a helper explicitly says it does that. +### TLS trust posture + +The gateway can serve a self-signed certificate it generates itself (it has no +PKI). To make that usable, TLS is **lenient by default**: when `UseTls` is set +and `CaCertificatePath` is empty, `CreateHttpHandler` installs a +`RemoteCertificateValidationCallback` that returns `true`, so the gateway's +self-signed certificate is accepted without verification. + +To verify the gateway instead: + +- set `CaCertificatePath` to pin a CA — validated via a `CustomRootTrust` + `X509Chain` against that root, and the callback additionally rejects a + hostname/SAN mismatch (`RemoteCertificateNameMismatch`); or +- set `RequireCertificateValidation` to `true` to keep the default OS/system-trust + verification on a connection with no pinned CA. + +Pinning a CA always wins over the lenient default. + ## Auth Interceptor Use a gRPC call credentials/interceptor layer to attach: diff --git a/clients/dotnet/README.md b/clients/dotnet/README.md index 333df1f..a4db520 100644 --- a/clients/dotnet/README.md +++ b/clients/dotnet/README.md @@ -287,6 +287,17 @@ Use TLS options for a secured gateway: dotnet run --project clients/dotnet/ZB.MOM.WW.MxGateway.Client.Cli -- smoke --endpoint https://ZB.MOM.WW.MxGateway.example.local:5001 --tls --ca-file C:\certs\mxgateway-ca.pem --server-name ZB.MOM.WW.MxGateway.example.local --api-key-env MXGATEWAY_API_KEY --item Area001.Pump001.Speed --json ``` +### TLS trust + +The gateway can auto-generate its own self-signed certificate (it has no PKI), so +the client is **lenient by default**: a TLS connection (`UseTls` / `--tls`) with +no pinned CA accepts whatever certificate the gateway presents. To verify +instead, pin a CA with `CaCertificatePath` / `--ca-file` (this path also enforces +the certificate hostname/SAN match), or set `RequireCertificateValidation` to +force OS/system-trust verification without pinning. Use `ServerNameOverride` / +`--server-name` when the dialed host differs from the certificate SAN. See +[Gateway Configuration](../../docs/GatewayConfiguration.md#automatic-self-signed-certificate). + ## Integration Checks Run live checks only when a gateway and MXAccess-backed worker are available: diff --git a/clients/go/GoClientDesign.md b/clients/go/GoClientDesign.md index f7d2682..dd0d51b 100644 --- a/clients/go/GoClientDesign.md +++ b/clients/go/GoClientDesign.md @@ -104,6 +104,23 @@ Support: - `credentials.NewClientTLSFromFile`, - custom `tls.Config` for advanced callers. +### Trust posture + +The gateway can serve a self-signed certificate it generates itself (it has no +PKI). To make that usable, TLS is **lenient by default**: when `Plaintext` is +`false` and no `CACertFile`/`TLSConfig`/`TransportCredentials` is supplied, +`buildCredentials` dials with `tls.Config{InsecureSkipVerify: true}` (carrying +`ServerNameOverride` as the SNI when set), so the gateway's self-signed +certificate is accepted without verification. + +To verify the gateway instead: + +- set `CACertFile` to pin a CA (full verification against that root), or +- set `RequireCertificateValidation: true` to verify against the OS/system trust + roots without pinning. + +Pinning a CA always wins over the lenient default. + ## Streaming `Events(ctx)` should return a receive channel of: diff --git a/clients/go/README.md b/clients/go/README.md index 07beb00..b6ab95c 100644 --- a/clients/go/README.md +++ b/clients/go/README.md @@ -75,6 +75,14 @@ client, err := mxgateway.Dial(ctx, mxgateway.Options{ }) ``` +The gateway can auto-generate its own self-signed certificate (it has no PKI), so +the client is **lenient by default**: a TLS connection (`Plaintext: false`) with +no `CACertFile`/`TLSConfig` accepts whatever certificate the gateway presents +(`InsecureSkipVerify`, with `ServerNameOverride` as the SNI when set). To verify +instead, set `CACertFile` to pin a CA, or set `RequireCertificateValidation: +true` to verify against the OS/system trust roots without pinning. See +[Gateway Configuration](../../docs/GatewayConfiguration.md#automatic-self-signed-certificate). + `Client.OpenSession` returns a `Session` with helpers for `Register`, `AddItem`, `AddItem2`, `Advise`, `Write`, `Events`, and `Close`. Prefer `SubscribeEvents` or `SubscribeEventsAfter` for long-running streams because the diff --git a/clients/java/JavaClientDesign.md b/clients/java/JavaClientDesign.md index b21ba41..d300ca8 100644 --- a/clients/java/JavaClientDesign.md +++ b/clients/java/JavaClientDesign.md @@ -112,6 +112,23 @@ Support: - custom CA certificate file, - server name override for test environments. +### Trust posture + +The gateway can serve a self-signed certificate it generates itself (it has no +PKI). To make that usable, TLS is **lenient by default**: when the channel is not +plaintext and no `caCertificatePath` is set, the client builds +`GrpcSslContexts.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)` +(grpc-netty-shaded), so the gateway's self-signed certificate is accepted without +verification. + +To verify the gateway instead: + +- set `caCertificatePath` to pin a CA (full verification against that root), or +- set `requireCertificateValidation` to `true` to verify against the JVM trust + store without pinning. + +Pinning a CA always wins over the lenient default. + ## Streaming Support both: diff --git a/clients/java/README.md b/clients/java/README.md index 36f4486..c6abd36 100644 --- a/clients/java/README.md +++ b/clients/java/README.md @@ -57,6 +57,16 @@ try (MxGatewayClient client = MxGatewayClient.connect(options); } ``` +The gateway can auto-generate its own self-signed certificate (it has no PKI), so +the client is **lenient by default**: a TLS connection (`plaintext(false)`) with +no `caCertificatePath` accepts whatever certificate the gateway presents (via +grpc-netty-shaded's `InsecureTrustManagerFactory`). To verify instead, set +`caCertificatePath` to pin a CA, or set `requireCertificateValidation(true)` to +verify against the JVM trust store without pinning. Use `serverNameOverride` / +`--server-name-override` when the dialed host differs from the certificate SAN. +See +[Gateway Configuration](../../docs/GatewayConfiguration.md#automatic-self-signed-certificate). + Use `rawBlockingStub`, `rawFutureStub`, `rawAsyncStub`, `openSessionRaw`, `closeSessionRaw`, `invoke`, and raw session helper methods when tests need the underlying protobuf messages. `MxGatewayCommandException` and diff --git a/clients/python/PythonClientDesign.md b/clients/python/PythonClientDesign.md index 5865e8c..9eb0d5c 100644 --- a/clients/python/PythonClientDesign.md +++ b/clients/python/PythonClientDesign.md @@ -112,6 +112,28 @@ Support: - TLS channel with default roots, - custom root certificate file. +### Trust posture (trust-on-first-use) + +The gateway can serve a self-signed certificate it generates itself (it has no +PKI). grpc-python exposes no per-channel skip-verify hook, so the client cannot +"accept any certificate" the way the other clients do. Instead, when the channel +is not plaintext and neither `ca_file` nor `require_certificate_validation` is +set, the TLS default is **trust-on-first-use**: the client fetches the server's +presented certificate once via `ssl.get_server_certificate` (an unverified +probe), pins it as the channel's only trust root, and — because the generated +certificate always carries a `localhost` SAN — defaults +`grpc.ssl_target_name_override` to `localhost` when no `server_name_override` was +supplied (tolerating dial-by-IP or a hostname mismatch). A failed probe is +surfaced as a transport error naming the endpoint. + +To verify the gateway instead: + +- set `ca_file` to verify against a specific CA, or +- set `require_certificate_validation=True` to verify against the system trust + roots. + +Both bypass the TOFU path. + ## Streaming Expose `stream_events` as an async iterator. Canceling the task should cancel diff --git a/clients/python/README.md b/clients/python/README.md index 3ffa16c..70b59d9 100644 --- a/clients/python/README.md +++ b/clients/python/README.md @@ -230,6 +230,17 @@ The client supports plaintext channels for local development, TLS with system roots, TLS with a custom `ca_file`, and an optional test server name override. API keys are redacted from option repr output and CLI error output. +The gateway can auto-generate its own self-signed certificate (it has no PKI). +grpc-python has no per-channel skip-verify, so the lenient TLS default is +**trust-on-first-use**: with no `ca_file` and `require_certificate_validation` +left `False`, the client fetches the gateway's presented certificate once +(unverified) and pins it for the channel, defaulting the SNI/target-name override +to `localhost` (the generated certificate always carries a `localhost` SAN) when +none was supplied. To verify instead, pass `ca_file` to verify against a specific +CA, or set `require_certificate_validation=True` to verify against the system +trust roots. See +[Gateway Configuration](../../docs/GatewayConfiguration.md#automatic-self-signed-certificate). + ## CLI The CLI emits deterministic JSON for automation: diff --git a/clients/rust/README.md b/clients/rust/README.md index b31dc8a..ccb3397 100644 --- a/clients/rust/README.md +++ b/clients/rust/README.md @@ -76,6 +76,19 @@ types. cargo run -p mxgw-cli -- smoke --endpoint https://mxgateway.example.local:5001 --tls --ca-file C:\certs\mxgateway-ca.pem --server-name-override mxgateway.example.local --api-key-env MXGATEWAY_API_KEY --item TestChildObject.TestInt --json ``` +### TLS trust (pin-only) + +The gateway can auto-generate its own self-signed certificate (it has no PKI). +Unlike the other clients, the Rust client is **not** lenient: tonic 0.13.1 +exposes no public hook to inject a custom certificate verifier, so TLS over Rust +is pin-only. A TLS connection requires either `--ca-file` / +`ClientOptions::with_ca_file(...)` to pin a CA (export the gateway's self-signed +certificate and pin it), or `--require-certificate-validation` / +`with_require_certificate_validation(true)` to verify against the system trust +roots. TLS with neither set fails `connect` with a clear, actionable error rather +than accepting the certificate. See +[Gateway Configuration](../../docs/GatewayConfiguration.md#automatic-self-signed-certificate). + ## Library Surface `ClientOptions` configures endpoint, API key, plaintext or TLS transport, diff --git a/clients/rust/RustClientDesign.md b/clients/rust/RustClientDesign.md index fc94e4d..d6c1385 100644 --- a/clients/rust/RustClientDesign.md +++ b/clients/rust/RustClientDesign.md @@ -189,6 +189,25 @@ Support: - custom CA file, - domain override. +### Trust posture (pin-only) + +The gateway can serve a self-signed certificate it generates itself (it has no +PKI). Rust is the **exception** to the lenient-by-default posture the other +clients use: tonic 0.13.1 exposes no public hook to inject a custom certificate +verifier, so the Rust client cannot accept an arbitrary certificate. TLS over the +Rust client is therefore **pin-only** — it requires either: + +- `ClientOptions::with_ca_file(...)` to pin a CA (the supported path for the + gateway's self-signed certificate; export the certificate and pin it), or +- `ClientOptions::with_require_certificate_validation(true)` to verify against the + system trust roots. + +With TLS enabled (`with_plaintext(false)`), no pinned CA, and certificate +validation not required, `GatewayClient::connect` rejects the connection with a +clear, actionable error pointing at `with_ca_file` / +`require_certificate_validation` rather than silently accepting the certificate. +The CLI exposes `--ca-file` and `--require-certificate-validation`. + ## Streaming Expose event streams as a `Stream>`. Dropping the diff --git a/docs/CrossLanguageSmokeMatrix.md b/docs/CrossLanguageSmokeMatrix.md index 2675d0e..e6acb2d 100644 --- a/docs/CrossLanguageSmokeMatrix.md +++ b/docs/CrossLanguageSmokeMatrix.md @@ -51,6 +51,19 @@ The shared inputs are: The commands in the matrix use `MXGATEWAY_API_KEY` through each CLI's `api-key-env` flag. They must not embed bearer tokens or raw API keys. +### TLS variant + +The matrix runs over plaintext (`h2c`) by default. A TLS variant exists but stays +a manual/opt-in run, consistent with the gate above, because it needs the gateway +started with an HTTPS endpoint (an `https://` `MXGATEWAY_ENDPOINT`) and each CLI +switched to its TLS flag (`--tls` / `-tls` / `--plaintext=false` / +`plaintext=False`). The clients are lenient by default and accept the gateway's +auto-generated self-signed certificate without extra trust setup, except the Rust +CLI, which is pin-only and needs `--ca-file` or `--require-certificate-validation` +(and Python uses trust-on-first-use). See +[Gateway Configuration — Automatic self-signed certificate](./GatewayConfiguration.md#automatic-self-signed-certificate) +and each client README for the per-client TLS flags. + ## JSON Comparison Every command in the matrix requests JSON output. A runner can compare the diff --git a/docs/DesignDecisions.md b/docs/DesignDecisions.md index 681eed4..ad8005e 100644 --- a/docs/DesignDecisions.md +++ b/docs/DesignDecisions.md @@ -375,6 +375,42 @@ deployment-heavy box, multiply per-session SQL connections, and complicate the cold-start path. Wire-side laziness solves the actual pain (oversized gRPC replies and a heavy DOM) without disturbing the materialization model. +## TLS Auto-Certificate and Lenient Client Trust + +Decision: when a Kestrel `https://` endpoint is configured without a certificate +of its own (and no `Kestrel:Certificates:Default` is set), the gateway generates +and persists a self-signed certificate rather than failing to start. Clients +connecting over TLS without a pinned CA accept whatever certificate the server +presents by default; pinning a CA restores full verification. + +Rationale: `mxaccessgw` is an internal tool with no PKI to issue or distribute +certificates. The prior behavior — an `https` endpoint with no certificate +fails at startup with Kestrel's opaque "no server certificate was specified" +error — pushed operators toward plaintext (`h2c`), exposing the API key and +request payloads on the wire. Auto-generating a long-lived, persisted, reused +certificate lets TLS "just work" with zero certificate management, while the +lenient client default means clients connect to that self-signed certificate +without a manual trust step. Both choices are deliberate, not oversights: +strict-by-default would force PKI work this tool does not warrant. Plaintext-only +deployments are untouched — no certificate or key material is written for them — +and an operator who supplies a real certificate transparently overrides the +generated one. + +Two clients diverge from "accept any certificate" because their gRPC stacks lack +a per-channel skip-verify hook: + +- Python uses trust-on-first-use: it fetches the server's presented certificate + over a separate unverified probe and pins it for the channel, and defaults the + SNI/target-name override to `localhost` (the generated certificate always + carries a `localhost` SAN). +- Rust is pin-only: tonic exposes no public hook to inject a custom certificate + verifier, so TLS over Rust requires either a pinned CA or an explicit opt-in to + system-trust verification; otherwise connecting returns a clear, actionable + error. + +See [Gateway Configuration — Automatic self-signed certificate](./GatewayConfiguration.md#automatic-self-signed-certificate) +and the per-client READMEs for the as-built behavior. + ## Later Revisit Items These are explicit post-v1 revisit items, not open blockers: diff --git a/docs/GatewayConfiguration.md b/docs/GatewayConfiguration.md index d6d000c..0bfb769 100644 --- a/docs/GatewayConfiguration.md +++ b/docs/GatewayConfiguration.md @@ -229,6 +229,185 @@ behavior. The alarm monitor is independent of client sessions: `AcknowledgeAlarm` and `StreamAlarms` are session-less RPCs served by the monitor. +## Host Endpoints and Transport Security (Kestrel) + +The listening endpoints are **not** part of the `MxGateway` section. The gateway +uses the stock ASP.NET Core host (`WebApplication.CreateBuilder`) with no +`ConfigureKestrel` call in code, so endpoints come entirely from the standard +`Kestrel` configuration section. On the deployed hosts these values are supplied +as NSSM environment variables (`Kestrel__Endpoints__...`), not from +`appsettings.json`. + +Two named endpoints are bound: + +| Endpoint name | Purpose | Protocol requirement | +|---|---|---| +| `Http` | Public gRPC API (sessions, invoke, events, Galaxy browse) | HTTP/2 | +| `Dashboard` | Blazor dashboard and SignalR hubs | HTTP/1.1 (HTTP/2 optional) | + +Both endpoints share one routing pipeline; the names only select which TCP port +serves which traffic. The gRPC endpoint must negotiate **HTTP/2**, which drives +the protocol settings below. + +### Plaintext (current deployments) + +Both running hosts (`10.100.0.48` and `wonder-app-vd03`) serve the gRPC port in +**cleartext HTTP/2 (`h2c`)**. Because cleartext HTTP/2 has no ALPN to negotiate +the protocol, the gRPC endpoint must be pinned to `Http2` with prior knowledge: + +```text +Kestrel__Endpoints__Http__Url=http://0.0.0.0:5120 +Kestrel__Endpoints__Http__Protocols=Http2 +Kestrel__Endpoints__Dashboard__Url=http://0.0.0.0:5130 +``` + +In this mode all client↔gateway traffic — including the +`authorization: Bearer mxgw_...` API key and any `WriteSecured` / `AuthenticateUser` +payloads — crosses the network **unencrypted**. This is acceptable only on a +trusted/isolated network segment. Prefer TLS for anything else. + +### TLS + +To encrypt the gRPC channel, give the `Http` endpoint an `https://` URL and a +certificate. Over TLS, ALPN negotiates HTTP/2, so the explicit `Protocols=Http2` +pin is no longer required (the default `Http1AndHttp2` works for gRPC over TLS). + +`appsettings.json` form: + +```json +{ + "Kestrel": { + "Endpoints": { + "Http": { + "Url": "https://0.0.0.0:5120", + "Certificate": { + "Path": "C:\\ProgramData\\MxGateway\\certs\\gateway.pfx", + "Password": "" + } + }, + "Dashboard": { + "Url": "https://0.0.0.0:5130", + "Certificate": { + "Path": "C:\\ProgramData\\MxGateway\\certs\\gateway.pfx", + "Password": "" + } + } + } + } +} +``` + +Equivalent NSSM environment-variable form (how config is delivered on the hosts — +see [server deploy mechanics in the project notes]): + +```text +Kestrel__Endpoints__Http__Url=https://0.0.0.0:5120 +Kestrel__Endpoints__Http__Certificate__Path=C:\ProgramData\MxGateway\certs\gateway.pfx +Kestrel__Endpoints__Http__Certificate__Password= +Kestrel__Endpoints__Dashboard__Url=https://0.0.0.0:5130 +Kestrel__Endpoints__Dashboard__Certificate__Path=C:\ProgramData\MxGateway\certs\gateway.pfx +Kestrel__Endpoints__Dashboard__Certificate__Password= +``` + +Certificate sourcing options (any standard ASP.NET Core form is accepted): + +| Form | Keys | +|---|---| +| PFX file | `Certificate:Path` (+ `Certificate:Password` if encrypted) | +| PEM pair | `Certificate:Path` (cert) + `Certificate:KeyPath` (private key) | +| Windows cert store | `Certificate:Subject`, `Certificate:Store` (e.g. `My`), `Certificate:Location` (`LocalMachine`), `Certificate:AllowInvalid` | + +The certificate's CN/SAN must cover the host name clients dial (or clients must +set a server-name override — see below). The dashboard endpoint can keep its own +certificate independent of the gRPC endpoint; pair this with +`MxGateway:Dashboard:RequireHttpsCookie` (`true`) for production HTTPS. + +### Automatic self-signed certificate + +`mxaccessgw` is an internal tool with no PKI to issue certificates, so requiring +an operator to supply one before TLS works pushed deployments toward plaintext. +To avoid that, the gateway fills in a self-signed certificate when an HTTPS +endpoint is configured without one. + +**Trigger.** At startup the gateway inspects `Kestrel:Endpoints:*`. If any +endpoint has an `https://` URL and no `Certificate` subsection of its own, and no +`Kestrel:Certificates:Default` is set, the gateway generates (or loads) a +persisted self-signed certificate and wires it in as the HTTPS *default* via +`ConfigureHttpsDefaults`. All-plaintext deployments are untouched: when no HTTPS +endpoint is configured, no certificate or key material is generated or written. + +**Generated certificate.** ECDSA P-256, `serverAuth` EKU, validity ≈ +`ValidityYears` (default 10 years, with one day of clock-skew slack before +`notBefore`). SANs cover `localhost`, the machine name (and its FQDN when +resolvable), each entry in `AdditionalDnsNames`, and the loopback addresses +`127.0.0.1` and `::1`. + +**`MxGateway:Tls:*` options.** All optional; the zero-config path needs none of +them. + +| Option | Default | Purpose | +|---|---|---| +| `Tls:SelfSignedCertPath` | `C:\ProgramData\MxGateway\certs\gateway-selfsigned.pfx` | Where the generated certificate is persisted | +| `Tls:ValidityYears` | `10` | Lifetime of the generated certificate (validated 1–100) | +| `Tls:AdditionalDnsNames` | `[]` | Extra DNS SANs (e.g. a load-balancer name) | +| `Tls:RegenerateIfExpired` | `true` | Replace an expired persisted certificate instead of failing | + +`ValidityYears` is validated by `GatewayOptionsValidator` (range 1–100); the +"HTTPS endpoint configured but no certificate available" fail-fast lives in the +bootstrap/provider, because the validator only sees the `MxGateway` section, not +`Kestrel:Endpoints`. + +**Persistence.** The PFX is written with an **empty** export password — a random +in-memory password could not be reused across restarts, which the +persist-and-reuse model requires. The private key is instead protected at rest by +filesystem permissions: a restrictive ACL on Windows (SYSTEM + Administrators, +inherited ACEs stripped) on the `certs` directory and file, and mode `0600` on +non-Windows. The write is atomic (hardened temp file, then move). The persisted +certificate is reused across restarts (stable thumbprint, so CA-pinning clients +keep working) and regenerated only when it is missing, expired (and +`RegenerateIfExpired` is `true`), or unreadable/corrupt. If the directory is not +writable or the ACL cannot be applied, the gateway fails fast with a diagnostic +naming the path rather than falling back to an in-memory certificate. + +**Logging.** On generate or load, the gateway logs the certificate thumbprint, +SAN list, and `notAfter` at Information. The PFX bytes, export password, and +private key are never logged. + +**Operator override.** The generated certificate is only the HTTPS *default*. To +use a real certificate, configure one explicitly — either per endpoint via +`Kestrel:Endpoints::Certificate` (`Path`/`Subject`/`Thumbprint`, etc., as +in the table above) or globally via `Kestrel:Certificates:Default`. An +explicitly-configured certificate takes precedence, and the gateway then writes +no self-signed material. + +### Client side + +Each official client opts into TLS explicitly. For the .NET client +(`MxGatewayClientOptions`): + +| Option | Effect | +|---|---| +| `UseTls` (default `false`) | Enables TLS. Requires an `https://` endpoint; an `https://` endpoint without `UseTls` fails validation, and vice versa. | +| `CaCertificatePath` | Pins a custom root (self-signed / private CA) using `CustomRootTrust` chain validation instead of the OS trust store; the .NET client also enforces the certificate hostname/SAN match on this path. | +| `RequireCertificateValidation` (default `false`) | Forces OS/system-trust verification on a TLS connection with no pinned CA. Leave `false` for the lenient default. | +| `ServerNameOverride` | SNI / certificate host name override when the dialed host differs from the certificate CN/SAN. | + +To pair with the auto-generated self-signed certificate above, the clients are +**lenient by default**: a TLS connection with no pinned CA accepts whatever +certificate the gateway presents. Pin `CaCertificatePath` to verify, or set +`RequireCertificateValidation` to force system-trust verification without +pinning. The other language clients expose the equivalent options; the exact +behavior differs per stack — Python uses trust-on-first-use and Rust is pin-only. +See each client README for the as-built behavior. + +### Gateway↔worker IPC + +Transport security here applies only to the public gRPC channel. The +gateway↔worker link is a per-session **named pipe** +(`mxaccess-gateway-{gatewayPid}-{sessionId}`), not a network socket. It is not +TLS-encrypted and does not need to be: it never leaves the local Windows host and +is secured by the OS pipe ACL. See [Worker Frame Protocol](./WorkerFrameProtocol.md). + ## Related Documentation - [Gateway Process Detailed Design](./GatewayProcessDesign.md) diff --git a/docs/Grpc.md b/docs/Grpc.md index f601c38..0043127 100644 --- a/docs/Grpc.md +++ b/docs/Grpc.md @@ -243,9 +243,27 @@ services.AddGrpc(options => options.Interceptors.Add