Skip to content

[TLS] Root CAs are not automatically used #3059

@afharo

Description

@afharo

Problem description

When using TLS, ca is always required by this client: either specified via parameter or via the env var GRPC_DEFAULT_SSL_ROOTS_FILE_PATH (code).

If an application wants to rely on the system's root certificates, it must append them explicitly:

import { rootCertificates } from 'tls';

export const toGrpcRootCerts = (config: { ca?: Buffer | Buffer[] }): Buffer => {
  const systemRoots = Buffer.from(rootCertificates.join('\n'));
  // Use Node's built-in roots only if no custom CAs are configured
  if (config.ca === undefined) {
    return systemRoots;
  }

  const customCa = Array.isArray(config.ca) ? concatCaBuffers(config.ca) : config.ca;
  // Append to Node's built-in roots so intermediate CAs can be verified
  return Buffer.concat([customCa, Buffer.from('\n'), systemRoots]);
};

I wonder if the return null in the following code could be changed to return the rootCertificates:

export function getDefaultRootsData(): Buffer | null {
if (DEFAULT_ROOTS_FILE_PATH) {
if (defaultRootsData === null) {
defaultRootsData = fs.readFileSync(DEFAULT_ROOTS_FILE_PATH);
}
return defaultRootsData;
}
return null;
}

Reproduction steps

  1. Use a TLS connection, connecting with certificates that are authorized by CAs that are verified on your machine
  2. Set up the client without the ca option.
  3. Observe the error Error: 14 UNAVAILABLE: No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca.

Environment

  • OS name, version and architecture: Linux Wolfi
  • Node version: 24.14.1
  • Node installation method: nvm
    - If applicable, compiler version [e.g. clang 3.8.0-2ubuntu4]
  • Package name and version @grpc/grpc-js@1.14.3

Additional context

The only relevant log entry that I have is

{"service":{"version":"73edd814d001","type":"kibana","state":"available","node":{"roles":["background_tasks"]},"id":"U1FDpZnLRSuHt25sUlys9g"},"ecs":{"version":"9.3.0"},"@timestamp":"2026-05-27T22:10:12.903+00:00","message":"{\"stack\":\"Error: 14 UNAVAILABLE: No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca. Resolution note: \\n  at callErrorFromStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/call.js:32:19)\\n  at Object.onReceiveStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client.js:193:76)\\n  at Object.onReceiveStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:367:141)\\n  at Object.onReceiveStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:327:181)\\n  at /usr/share/kibana/node_modules/@grpc/grpc-js/build/src/resolving-call.js:135:78\\n  at processTicksAndRejections (node:internal/process/task_queues:85:11)\\nfor call at\\n  at ServiceClientImpl.makeUnaryRequest (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client.js:161:32)\\n  at ServiceClientImpl.export (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19)\\n  at /usr/share/kibana/node_modules/@opentelemetry/otlp-grpc-exporter-base/build/src/grpc-exporter-transport.js:98:32\\n  at new Promise (<anonymous>)\\n  at GrpcExporterTransport.send (/usr/share/kibana/node_modules/@opentelemetry/otlp-grpc-exporter-base/build/src/grpc-exporter-transport.js:87:16)\\n  at OTLPExportDelegate.export (/usr/share/kibana/node_modules/@opentelemetry/otlp-exporter-base/build/src/otlp-export-delegate.js:47:56)\\n  at OTLPLogExporter.export (/usr/share/kibana/node_modules/@opentelemetry/otlp-exporter-base/build/src/OTLPExporterBase.js:19:30)\\n  at /usr/share/kibana/node_modules/@opentelemetry/sdk-logs/build/src/export/BatchLogRecordProcessorBase.js:69:28\\n  at new Promise (<anonymous>)\\n  at ExportOperation._exportWithTimeout (/usr/share/kibana/node_modules/@opentelemetry/sdk-logs/build/src/export/BatchLogRecordProcessorBase.js:64:16)\",\"message\":\"14 UNAVAILABLE: No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca. Resolution note: \",\"code\":\"14\",\"details\":\"No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca. Resolution note: \",\"metadata\":\"[object Object]\",\"name\":\"Error\"}","log":{"level":"ERROR","logger":"telemetry"},"process":{"pid":7,"uptime":27187.550138107},"span":{"id":"c260aa5603661248"},"trace":{"id":"32b429e7a682b92e957ed8026ca706be"}}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions