【问题标题】:Reload Netty Server's SSL Context for gRPC为 gRPC 重新加载 Netty 服务器的 SSL 上下文
【发布时间】:2018-07-18 22:01:19
【问题描述】:

有人可以告诉我如何在刷新/更新服务器证书而不重新启动 gRPC 服务器的情况下重新加载 SSLContext 吗?

我有这段代码来构建和启动 gRPC 服务器。 每当证书发生更改时,即我创建新的 SSL 上下文时,就会调用方法 certificateRefreshed(),但除非我重新启动 grpc 服务器,否则这不起作用。

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();
    }

}

【问题讨论】:

  • 目前不支持在不重启服务器的情况下刷新证书。

标签: ssl certificate netty grpc grpc-java


【解决方案1】:

我不确定是否有更简单的替代方案,但我看到了两种可能的方法。

  1. 制作你自己的SslContext,模仿DelegatingSslContext。当您需要不同的证书时,您可以换成不同的SslContext(尤其是在newEngine 期间)。

  2. 使用KeyManagerFactory,其密钥材料会随时间变化。我不知道这样一个工厂的预先存在的实现,所以你可能需要实现一个KeyManagerFactorySpi,它委托给KeyManagerFactory。然后你可以随着时间的推移换掉KeyManagerFactory

我会警告说,我很容易错过一些会使方法无效的东西。

【讨论】:

    【解决方案2】:

    本题与本题类似:Reloading a java.net.http.HttpClient's SSLContext

    很遗憾,此选项默认不可用。将 SSLContext 提供给服务器并构建服务器后,您将无法更改 SSLContext。您将需要创建一个新的 SSLContext 和一个新的服务器。

    我的一个项目遇到了同样的挑战,我通过使用自定义的 trustmanager 和 keymanager 解决了这个问题,它包裹了实际的 trustmanager 和 keymanager,同时能够交换实际的 trustmanager 和 trustmanager。因此,如果您仍然想在不需要重新创建服务器和 SSLContext 的情况下完成它,您可以使用以下设置:

    SSLFactory sslFactory = SSLFactory.builder()
        .withSwappableIdentityMaterial()
        .withIdentityMaterial("identity.jks", "password".toCharArray())
        .withSwappableTrustMaterial()
        .withTrustMaterial("truststore.jks", "password".toCharArray())
        .build();
    
    SslContext sslContext = NettySslUtils.forServer(sslFactory).build();
              
    Server server = NettyServerBuilder
        .forPort(8443)
        .executor(executorService)
        .addService(myService)
        .sslContext(sslContext)
        .build();
    
    server.start();
    
    // swap identity and trust materials and reuse existing server
    KeyManagerUtils.swapKeyManager(sslFactory.getKeyManager().get(), anotherKeyManager);
    TrustManagerUtils.swapTrustManager(sslFactory.getTrustManager().get(), anotherTrustManager);
    
    // Cleanup old ssl sessions by invalidating them all. Forces to use new ssl sessions which will be created by the swapped KeyManager/TrustManager
    SSLSessionUtils.invalidateCaches(sslFactory.getSslContext());
    

    在上面的代码示例中,当您有新证书时,您需要将swapKeyManagerswapTrustManager方法的第二个参数替换为新创建的KeyManager和TrustManager。

    有关此选项的文档,请参见此处:Swapping KeyManager and TrustManager at runtime

    这里有一个使用 Jetty 的实际工作示例(类似于 Netty):Example swapping certificates at runtime with Jetty Server

    您可以通过以下方式将库添加到您的项目中:

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

    您可以在此处查看完整文档和其他示例:GitHub - SSLContext Kickstart

    顺便说一句,我需要添加一个小免责声明,我是该库的维护者。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-26
      • 2021-01-03
      • 2022-01-20
      • 2018-02-13
      • 1970-01-01
      • 2016-10-09
      • 2021-01-14
      • 2012-10-21
      相关资源
      最近更新 更多