How do I connect to GRPC using TLS?

Viewed 1786

I'm trying unsuccessfully to get a basic GRPC server and client working with SSL/TLS, with a node client and Java server. Starting with no security:

// client.js
const creds = grpc.credentials.createInsecure()
const stub  = new hello_proto.Greeter('localhost:50051', creds)
stub.sayHello(...)
// server.java
Server server = ServerBuilder.forPort(50051)
  .addService(serviceImplementation)
  .build();
server.start();

All works as expected here. I then tried to add SSL credentials, generating a certificate and private key like this (following a Python example):

$ openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt

This generates a certificate (server.crt) and private key (server.key). I then add those credentials to client and server (private key on server only), following the guidance from the grpc.io Auth Guide and grpc-java respectively:

// client.js
const rootCert = fs.readFileSync("path/to/server.crt");
const channelCreds = grpc.credentials.createSsl(rootCert);
const stub = new hello_proto.Greeter('localhost:50051', channelCreds);
stub.sayHello(...)
// server.java
File certChainFile  = File("path/to/server.crt")
File privateKeyFile = File("path/to/server.key")
Server server = ServerBuilder.forPort(50051)
  .useTransportSecurity(certChainFile, privateKeyFile)
  .addService(serviceImplementation)
  .build();
server.start();

Now I get an error UNAVAILABLE: No connection established on the client side:

Error: 14 UNAVAILABLE: No connection established
    at Object.callErrorFromStatus (path/to/node_modules/@grpc/grpc-js/build/src/call.js:31:26)
    at Object.onReceiveStatus (path/to/node_modules/@grpc/grpc-js/build/src/client.js:176:52)
    at Object.onReceiveStatus (path/to/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:336:141)
    at Object.onReceiveStatus (path/to/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:299:181)
    at path/to/node_modules/@grpc/grpc-js/build/src/call-stream.js:130:78
    at processTicksAndRejections (node:internal/process/task_queues:76:11) {
  code: 14,
  details: 'No connection established',
  metadata: Metadata { internalRepr: Map(0) {}, options: {} }
}

No error on the server side. The client-side error is, unhelpfully, identical to the one I get when the server is down.

How do I implement basic TLS authentication between a Java server and node client?

1 Answers

Maybe you can reference my code in helloworlde/grpc-java-sample, feel free to translate Chinese;

For the both side, it need SslContext

  • Server
       File keyCertChainFile = new File("server.pem");
       File keyFile = new File("server.key");
       SslContext sslContext = GrpcSslContexts.forServer(keyCertChainFile, keyFile)
                                              .clientAuth(ClientAuth.OPTIONAL)
                                              .build();

       Server server = NettyServerBuilder.forAddress(new InetSocketAddress(9090))
                                          .addService(new HelloServiceImpl())
                                          .sslContext(sslContext)
                                          .build();

  • Client

        File trustCertCollectionFile = new File("server.pem");
        SslContext sslContext = GrpcSslContexts.forClient()
                                            .trustManager(trustCertCollectionFile)
                                            .build();

        ManagedChannel channel = NettyChannelBuilder.forAddress("127.0.0.1", 9090)
                                                    .overrideAuthority("localhost")
                                                    .sslContext(sslContext)
                                                    .build();
Related