Securing gRPC service-to-service communications with mTLS
What is gRPC?
gRPC is a modern open-source high-performance Remote Procedure Call (RPC) framework developed by Google. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication.
I recommend the following blog post to get a good understanding about gRPC if you don’t have an understanding about gRPC protocol.
We can use gRPC to communicate with two backend services. This blog covers how communication between two services can be secured with TLS and mTLS.
TLS and mTLS?
In TLS, the client needs to have the certificate of the server. So that client verifies that the server is the legit server. But the server does not verify who the client is accessing the resources. Anyone who has the server certificate can connect to the server. But in mTLS, the server also needs to have the client certificate, while the client needs to have the server certificate. Therefore only the registered client can be connected to the server.
If the server is not enabled TLS or mTLS, these communications are not happening via encrypted channels. And also, anyone can invoke this gRPC API since this is exposed to the public without any security.
By enabling TLS, we can secure the communication between the Client and the Server using the public certificate of the server. But since the certificate of the server is public, anyone who has the server certificate can invoke the gRPC API.
But if we use mTLS, Ther client certificate is also needed to be added as a trusted certificate in the server. Server needs to have a list of certificates of the intended clients and only allow those clients to access the server.
Generating certificates for Client and Server.
Private keys and certificates will be generated using keytool utility and those private keys and certificates will be stored in Java Keystore (jks) files.
We need to use above generated carparkserver-keystore.jks and carpark-server-truststore.jks files in CarParkServer and carparkclient-keystore.jks and carparkclient-truststore.jks files in CarParkClient.
Configuring CarParkServer for TLS/mTLS.
We need to add following codes to read jks files and build KeyStores and TrustManagers.
To enable TLS we need to change the Server Builder code snippet as follows.
TlsServerCredentials.ClientAuth clientAuth = TlsServerCredentials.ClientAuth.NONE;TlsServerCredentials.Builder tlsBuilder = TlsServerCredentials.newBuilder().keyManager(Utils.getKeyManagers(“<path-to-keystore>/carparkserver-keystore.jks”,“<keystore-password>”.toCharArray(),“JKS”)).trustManager(Utils.getTrustManagers(“<path-to-truststore>/carparkserver-truststore.jks”,“<truststore-password>”.toCharArray(),“JKS”)).clientAuth(clientAuth);Server server = Grpc.newServerBuilderForPort(40404, tlsBuilder.build()).addService(new CarParkServiceImpl()).build();
To enable mTLS, we need to change the clientAuth variable in the above code snippet as follows.
TlsServerCredentials.ClientAuth clientAuth = TlsServerCredentials.ClientAuth.REQUIRE;
Configuring CarParkClient for TLS/mTLS
Following Util class needs to be added in order to initialize the keystores and truststores.
To enable TLS/mTLS we need to change the Managed Channel code snippet as follows.
TlsChannelCredentials.Builder tlsBuilder = TlsChannelCredentials.newBuilder();tlsBuilder.keyManager(Utils.getKeyManagers(“scripts/carparkclient-keystore.jks”,“111111”.toCharArray(), “JKS”));tlsBuilder.trustManager(Utils.getTrustManagers(“scripts/carparkclient-truststore.jks”,“111111”.toCharArray(), “JKS”));ManagedChannel channel = Grpc.newChannelBuilderForAddress(“localhost”, 40404, tlsBuilder.build()).build();
Full source code for the blog can be found here.
Summery