gRPC: How to configure SSL in client?
Asked Answered
C

2

7

Its new topic for me. I'm able to connect as plaintext.

public ManagedChannel getChannel(String serviceName){
    TSServiceClientManager scm = TSServiceManagementFactory.getInstance().getServiceClientManager();
    TSServiceConnectionInfo connInfo = scm.getServiceConnectionInfo(serviceName);
    if(channel == null){
        channel = ManagedChannelBuilder.forAddress(connInfo.getHost(), connInfo.getPort())
                .usePlaintext(true) //need help here for SSL code 
                .build();
    }

    return channel;
}

I was told to enable client-side SSL. I know how to generate, keystore, truststore, pem, CA etc. I need help in :

How to enable SSL instead of .usePlaintext(true) as shown in above code?

(Kindly rewrite the code considering the cert file, keystore, truststore and .pem file exist)

And

I want to know is there anything to do with server to make SSL connection work?

Crossindex answered 4/12, 2017 at 7:17 Comment(0)
D
11

Since grpc-java 1.37.0 it is possible for most users to configure TLS without using transport-specific APIs. This leverages the ChannelCredentials concept introduced in 1.34.0.

ChannelCredentials creds = TlsChannelCredentials.newBuilder()
    // if server's cert doesn't chain to a standard root
    .trustManager(caFile)
    .keyManager(clientCertFile, keyFile) // client cert
    .build();
channel = Grpc.newChannelBuilderForAddress(serverHost, serverPort, creds)
    .build();

TlsServerCredentials and Grpc.newServerBuilderForPort() would be used on server-side.

Advanced use cases may need to use transport-specific APIs like GrpcSslContexts and NettyChannelBuilder.sslContext().


Original answer: You need to use a transport-specific API. You're likely using Netty today. For Netty, you need to configure Netty's SslContext and pass it to gRPC. Your usage may look something like this:

SslContext sslcontext = GrpcSslContexts.forClient()
    // if server's cert doesn't chain to a standard root
    .trustManager(caFile)
    .keyManager(clientCertFile, keyFile) // client cert
    .build();
channel = NettyChannelBuilder.forAddress(serverHost, serverPort)
    .sslContext(sslContext)
    .build();

If you need server-side configuration, it would use the similar NettyServerBuilder.sslContext(). But the context itself would be different.

Devon answered 4/12, 2017 at 17:8 Comment(7)
Thanks for the reply @Eric Anderson , I'll try tomorrow. Almost cleared my doubts. Once got it, I'll mark it as answer and I will share what changes I did.Crossindex
"But the context itself would be different." could you please add an example of the server side configuration?ThanksCharioteer
Server-side normally looks something like GrpcSslContexts.forServer(serverCertChainFile, keyFile).build(). Specifying a keyManager is required on-server side, so the builder is requiring those parameters early. Specifying trustManager(caFile) is necessary if the client's cert chain doesn't chain to a standard root (which only applies when using client-certs).Devon
Hi Eric, do we need to send the client cert to server's trust list before we establish the channel?Averyaveryl
I just answered your SO question: https://mcmap.net/q/1478876/-grpc-sslcontext-config . Normally the client and server agree ahead-of-time on a CA to use, because otherwise the server can't easily trust the client is permitted to use a particular certificate. There can be schemes where that is done, but it'd normally require having some other way to authenticate that client (an older cert, a password, etc).Devon
@EricAnderson Instead of providing a file, can you provide a string? And how?Flareup
@Nikk, String isn't supported, but you can pass an InputStream, as you're already aware in https://mcmap.net/q/1478877/-issues-loading-tls-from-a-string-instead-of-a-file/4690866 . The problem you have there seems to have nothing to do with "string vs file." The problem is the key.Devon
A
2

If any one wants to use JKS files then below code might help.

InputStream is = Utils.class.getClassLoader().getResourceAsStream("truststore.jks");
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(is, "secret".toCharArray());

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(truststore);

SslContextBuilder sslContextbuilder = GrpcSslContexts.forClient().trustManager(trustManagerFactory);
SslContext sslContext = sslContextbuilder.build();
channel = NettyChannelBuilder.forAddress("localhost", "8443").sslContext(sslContext).build();
Athallia answered 30/3, 2022 at 15:5 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.