[Bug] EXTERNAL voice applications are always dialed with insecure credentials, so a TLS endpoint can't be used
Summary
GrpcClientHandler dials every EXTERNAL application endpoint with grpc.credentials.createInsecure(), so an application whose endpoint terminates TLS (behind a reverse proxy / ingress) can never be reached — and all voice session traffic to external apps travels in plaintext.
Steps to Reproduce
- Deploy a voice application behind a TLS-terminating reverse proxy (Envoy, nginx, Traefik) exposing gRPC over HTTP/2 on
:443. - Create an EXTERNAL application with
endpoint: "api.example.com:443". - Place a call routed to that application.
Expected Behavior
The apiserver dials the external application over TLS when the endpoint is a secure one, and the voice session is established.
Actual Behavior
The connection fails immediately. The proxy expects a TLS ClientHello and receives a plaintext HTTP/2 preface, so it drops the connection before any routing happens. Logs show voice server not available at "api.example.com:443".
Pointing the same application at a bare plaintext host:port works — which is what makes this look like a DNS/TLS problem on the deployment side when it isn't.
Relevant code — mods/apiserver/src/voice/client/GrpcClientHandler.ts:46:
this.grpcClient = new VoiceServiceClientConstructor(
this.config.endpoint,
grpc.credentials.createInsecure()
) as unknown as GRPCClient;config.endpoint is app.endpoint passed through verbatim (mods/apiserver/src/voice/integrations/createCreateContainer.ts:74-79) — a bare string with no scheme. There is no secure / allowInsecure field on VoiceClientConfig (mods/common/src/voice/voice.ts:103) nor on Application in mods/common/src/protos/applications.proto, so there is no configuration path that reaches TLS. createInsecure() is the only code path.
This is inconsistent with the rest of the codebase, which already models the choice: mods/sdk/src/client/Client.ts:58 and mods/common/src/identity/getPublicKey.ts:37 both switch on allowInsecure between createInsecure() and createSsl().
Suggested Fix
Add a per-application secure flag (e.g. bool secure on Application, or accept a grpcs:// scheme in endpoint), thread it through VoiceClientConfig, and use grpc.credentials.createSsl() in GrpcClientHandler when set — mirroring the existing allowInsecure pattern. Happy to submit a PR.
Notes
Reported downstream as fonoster/qcobro#28, where it was first diagnosed. Beyond the connectivity failure, the current behavior means external voice application traffic (including the session token in gRPC metadata) is always sent unencrypted.
Priority
P2 – Normal
Source: fonoster/fonoster