grpc-node
grpc-node copied to clipboard
grpc-node TLS sample code is not complete.
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
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.
grpc nodejs docs are appalling. What shall I supply in root_certs? Buffer of what?
@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
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 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
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.
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.
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.
Using credentials.createSsl()
as credentials
for a client side TLS connection(without any authentication) worked for me.
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() });
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?
On the server side, you need to use ServerCredentials.createSsl()
.
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.
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
@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
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);
I wrote an article about it - https://itnext.io/how-to-setup-and-test-tls-in-grpc-grpc-web-1b67cc4413e6