2

Can someone tell me how to reload the SSLContext when a server certificate it refreshed/renewed without restarting the gRPC server?

I have this code to build and start a gRPC server. The method certificateRefreshed() gets called whenever a certificate changes which is when I create a new SSL context, but this doesn't work unless I restart the grpc server.

public class ServerWithTls {
    Server server;
    SslContext sslContext;

    public ServerWithTls() {
        this.sslContext = getSslContext();

        NettyServerBuilder serverBuilder = NettyServerBuilder
            .forPort(settings.port())
            .executor(executorService)
            .addService(myService);
            .sslContext(this.sslContext);

        server = serverBuilder.build();
        server.start();
    }

    public io.netty.handler.ssl.SslContext getSslContext() {
        // returns ssl context based on cert and key
    }

    // gets notified when a server cert changes
    public void certificateRefreshed() {
        // create a new SSL context when cert changes
        this.sslContext = getSslContext();
    }

}
rahul
  • 21
  • 2

2 Answers2

1

I'm unsure if there are easier alternatives, but I see two potentially possible ways.

  1. Make your own SslContext, mimicking DelegatingSslContext. You would swap to a different SslContext (especially during newEngine) when you want a different certificate.

  2. Use a KeyManagerFactory whose key material can change over time. I'm not aware of a pre-existing implementation of such a factory, so you probably would need to implement a KeyManagerFactorySpi that delegates to a KeyManagerFactory. You could then swap out the KeyManagerFactory over time.

I will warn that it would have been easy for me to miss something that would invalidate the approaches.

Eric Anderson
  • 24,057
  • 5
  • 55
  • 76
0

This question is similar to this question: Reloading a java.net.http.HttpClient's SSLContext

This option is unfortunately not available by default. After you have supplied the SSLContext to the Server and build the Server you cannot change the SSLContext. You will need to create a new SSLContext and a new Server.

I had the same challenge for one of my projects and I solved it by using a custom trustmanager and keymanager which wraps around the actual trustmanager and keymanager while having the capability of swapping the actual trustmanager and trustmanager. So you can use the following setup if you still want to accomplish it without the need of recreating the Server and SSLContext:

SSLFactory baseSslFactory = SSLFactory.builder()
        .withDummyIdentityMaterial()
        .withDummyTrustMaterial()
        .withSwappableIdentityMaterial()
        .withSwappableTrustMaterial()
        .build();

Runnable sslUpdater = () -> {
    SSLFactory updatedSslFactory = SSLFactory.builder()
            .withIdentityMaterial(Paths.get("/path/to/your/identity.jks"), "password".toCharArray())
            .withTrustMaterial(Paths.get("/path/to/your/truststore.jks"), "password".toCharArray())
            .build();

    SSLFactoryUtils.reload(baseSslFactory, updatedSslFactory);
};

// initial update of ssl material to replace the dummies
sslUpdater.run();

// update ssl material every hour
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(sslUpdater, 1, 1, TimeUnit.HOURS);

SslContext sslContext = NettySslUtils.forServer(sslFactory).build();
          
Server server = NettyServerBuilder
    .forPort(8443)
    .executor(executorService)
    .addService(myService)
    .sslContext(sslContext)
    .build();

server.start();

See here for the documentation of this option: Reloading ssl at runtime

And here for an actual working example with Jetty (similar to Netty): Example swapping certificates at runtime with Jetty Server

You can add the library to your project with:

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>sslcontext-kickstart-for-netty</artifactId>
    <version>7.4.4</version>
</dependency>

You can view the full documentation and other examples here: GitHub - SSLContext Kickstart

By the way I need to add a small disclaimer I am the maintainer of the library.

Hakan54
  • 3,121
  • 1
  • 23
  • 37