grpc-node icon indicating copy to clipboard operation
grpc-node copied to clipboard

grpc-node TLS sample code is not complete.

Open GingerMoon opened this issue 6 years ago • 17 comments

Hi gurus, I am a newbee to node.js and grpc. So a good sample code is really appreciated.

The grpc-node TLS sample code is in https://grpc.io/docs/guides/auth.html#nodejs not complete. For example, no sample code for TLS client side. The strange thing is,
https://grpc.io/grpc/node/grpc.credentials.html createSsl( [root_certs] [, private_key] [, cert_chain]) Create an SSL Credentials object. If using a client-side certificate, both the second and third arguments must be passed. Why are private key and cert chain needed for client side? They are not needed for grpc-go TLS client side. https://github.com/grpc/grpc-go/issues/1980

GingerMoon avatar Apr 12 '18 03:04 GingerMoon

There is some confusion here and I'm not certain if you are trying to initiate a "normal" TLS connection to a server from the client side or if you are instead trying to connect to a server that performs client authentication via certs ("mutual TLS").

If it is the latter ("mutual TLS"), then you do need to pass the client cert (cert_chain) and private key for the cert (private_key) because the server you are connecting to requires it. Furthermore, the go example you point to (which I think is more pointing to the example here) is not doing mutual TLS (which requires providing a client-side cert/key) but rather it is just initiating a "normal" TLS connection to the server.

If it is the former (you are not doing mutual TLS), the optional [, private_key] [, cert_chain] parts would be omitted when making the call (which would match the go example you link to).

Hopefully that helps. I stumbled on this issue looking for other issues here and thought I would try to help clear things up.

marzolfb avatar Jun 22 '18 16:06 marzolfb

grpc nodejs docs are appalling. What shall I supply in root_certs? Buffer of what?

celesteking avatar Sep 17 '20 21:09 celesteking

@celesteking were you able to figure that out? We are having the same issue. In particular, node's root certs (require("tls").rootCertificates) are an array of strings

gja avatar Sep 20 '20 14:09 gja

The root certs is supposed to be a Buffer loaded from a root certificates file. If you want to use the default public root certificates, just omit that argument. It is supposed to be used with self-signed certificates, or certificates that otherwise don't have a signing chain that includes one of the main root certificate authorities.

An example of self-signed certificates can be found in this directory: https://github.com/grpc/grpc-node/tree/master/test/data. The ca.pem file contains the root certificate.

murgatroid99 avatar Sep 21 '20 18:09 murgatroid99

@murgatroid99 I don't believe the code works like that. The following example from the grpc-js, but I believe the native version works the same way. If ssl is missing, it looks for an environment variable called GRPC_DEFAULT_SSL_ROOTS_FILE_PATH (which is still a single .pem I believe).

https://github.com/grpc/grpc-node/blob/1d14203c382509c3f36132bd0244c99792cb6601/packages/grpc-js/src/tls-helpers.ts#L30

gja avatar Sep 23 '20 14:09 gja

If that environment variable is not set, it defaults to using the built in root certificates.

Also, I'm not sure if this is clear: one .pem file can contain information for multiple certificates.

murgatroid99 avatar Sep 23 '20 15:09 murgatroid99

Thank you guys for the time on this ticket. Since I am not working on this anymore, please feel free to close the ticket if needed.

GingerMoon avatar Sep 30 '20 05:09 GingerMoon

Was also looking at just doing a TLS client connection from node (not mutual TLS) and couldn't get it working. The Java and Go equivalent are fairly straightforward but was unable to get it working in node.

yellowandy avatar Feb 17 '21 05:02 yellowandy

Using credentials.createSsl() as credentials for a client side TLS connection(without any authentication) worked for me.

sourinMT avatar Mar 12 '21 15:03 sourinMT

it is super easy to create a grpc ssl server you only have to import the certificates in my case with letsencrypt

let credentials = grpc.ServerCredentials.createSsl(null /fs.readFileSync('./certs/ca.crt')/, [{ cert_chain: fs.readFileSync('/etc/letsencrypt/fullchain.pem'), private_key: fs.readFileSync('/etc/letsencrypt/privkey.pem') }], false);

await server.bindAsync("0.0.0.0:50051", credentials, (error, port) => { if (error) console.log(error) console.log("listening grpc on *:50051"); server.start() });

njavilas2015 avatar Aug 08 '21 14:08 njavilas2015

Creating a server is straightforward based on the docs, it is the client-side what is lacking docs and possibly features.

I have managed to create server-side with a Node server, connecting golang clients, but I cannot add Node clients the same manner as with golang.

I would like to achieve server-side TLS. The same way as it is done in golang example & mentioned by the OP: https://grpc.io/docs/guides/auth/#with-server-authentication-ssltls

credentials.createSsl() is not working, and I see no option to provide the public key alone.

Authenticate using a public key, not using a CA, is this feature missing?

nandor-magyar avatar Nov 19 '21 15:11 nandor-magyar

On the server side, you need to use ServerCredentials.createSsl().

murgatroid99 avatar Nov 19 '21 16:11 murgatroid99

Server-side, the node component being the client, ServerCredentials.createSsl() will work if the system already trusts the servers public key, otherwise it is to be set up. Providing the public cert file into the rootCert/first param works with a generated private/public key-pair.

nandor-magyar avatar Nov 23 '21 09:11 nandor-magyar

I had a use case where I needed to test minimal setup of gRPC SSL on LAN with Node.js across multiple devices and without being familiar in detail with gRPC and SSL (plus everyone names root and intermediate certificates differently making it confusing sometimes) It took me couple days of frustration with lack of examples for server setup, so I made small server-client example for localhost in case anyone finds it useful: sample-grpc-ssl. It uses selfsigned certs with node-forge (Alternative with openssl here) or can replace them with letsencrypt or other

ragauskl avatar Feb 23 '22 19:02 ragauskl

@murgatroid99 can you please give some sample code in nodejs for server to apply TLS

ServerCredentials.createSsl(). for this thing it will be really helpful or any link where in nodejs server side and client side TLS is setup sir please

vthakuri avatar Apr 29 '22 12:04 vthakuri

Example, if you have to use combine systemRootCerts and self-signed root cert as trust certs when gRPC client has to connect to both production server endpoint (server cert signed by public CA) as well as developoment server endpoint (server cert signed by self-signed CA)

import grpc from '@grpc/grpc-js';
import { readFileSync } from 'node:fs';
import tls from 'node:tls';
import { EOL } from 'node:os';
import type { ClientOptions } from '@grpc/grpc-js';
import type {VerifyOptions} from "@grpc/grpc-js/src/channel-credentials";

const systemRootCerts = Buffer.from(tls.rootCertificates.join(EOL));
const myRootCert = readFileSync('config/certs/ca-cert.pem')
const rootCerts  =  Buffer.concat([myRootCert, systemRootCerts])
const privateKey = readFileSync('config/certs/client-key.pem')
const certChain =	readFileSync('config/certs/client-cert.pem')
const verifyOptions: VerifyOptions = {}

const channelCredentials = grpc.credentials.createSsl(rootCerts, privateKey, certChain, verifyOptions)

console.debug('endpoints', endpoints);
// If no ServerName is set, infer the ServerName from the hostname we're connecting to.
const hostname = endpoints.engine?.split(':')[0] ?? 'localhost';
console.debug('engine hostname:', hostname);

const clientOptions: ClientOptions = {
	'grpc.ssl_target_name_override': hostname,
	'grpc.default_authority': hostname
};

const transport = new GrpcTransport({ host: endpoints.engine, channelCredentials, clientOptions });

const engineServiceClient = new EngineServiceClient(transport);

xmlking avatar Oct 01 '22 06:10 xmlking

I wrote an article about it - https://itnext.io/how-to-setup-and-test-tls-in-grpc-grpc-web-1b67cc4413e6

notmedia avatar Oct 02 '22 09:10 notmedia