ssl 我们能否避免spring Boot 应用程序重启,以刷新与其嵌入的tomcat容器相关的证书?

66bbxpm5  于 12个月前  发布在  Spring
关注(0)|答案(4)|浏览(185)

对SSL证书(在其密钥库中)进行任何更改后,我们需要重新启动spring Boot 应用程序。我想定期(可能是每年)更新我的密钥库条目,但希望避免重新启动JVM。如何才能实现这一点。我想知道编写自定义KeyManager是否是一种可接受的做法?

7eumitmz

7eumitmz1#

不幸的是,这是不可能的。
但是
这里有几种解决方案。

安装Tomcat连接器(有点黑客)

您可以重新启动Tomcat连接器,即在更改jssecacert文件后重新启动8843
但我认为这仍然是一个黑客。

反向代理:NginxApache

这是一种方法。您的应用程序应该在某个反向代理之后(例如nginx)。这将给予您额外的灵活性,并减少应用程序的负载。Nginx将处理https并将其转换为普通的http。无论如何,您必须重新启动nginx,但nginx重新启动非常快,不会停机。此外,你可以配置脚本来为你做这件事。

kxeu7u2r

kxeu7u2r2#

在Tomcat上,可以使用本地JMX重新加载SSL上下文:

private static final String JMX_THREAD_POOL_NAME = "*:type=ThreadPool,name=*";
private static final String JMX_OPERATION_RELOAD_SSL_HOST_CONFIGS_NAME = "reloadSslHostConfigs"; 
private void reloadSSLConfigsOnConnectors() {
    try {
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        ObjectName objectName = new ObjectName(JMX_THREAD_POOL_NAME);
        Set<ObjectInstance> allTP = server.queryMBeans(objectName, null);
        logger.info("MBeans found: {}", allTP.size());
        allTP.forEach(tp -> reloadSSLConfigOnThreadPoolJMX(server, tp));
    } catch (Exception ex) {
        logger.error("", ex);
    }
}

private void reloadSSLConfigOnThreadPoolJMX(MBeanServer server, ObjectInstance tp) {
    try {
        logger.info("Invoking operation SSL reload on {}", tp.getObjectName());
        server.invoke(tp.getObjectName(), JMX_OPERATION_RELOAD_SSL_HOST_CONFIGS_NAME, new Object[]{}, new String[]{});
        logger.trace("Successfully invoked");
    } catch (Exception ex) {
        logger.error("Invoking SSL reload", ex);
    }
}

字符串
我正在重新加载所有ThreadPool SSL上下文,但实际上只需要一个:Tomcat:type=ThreadPool,name=https-jsse-nio-8443。我担心名称会改变,所以我涵盖了所有可能性以防万一。

vd2z7a6w

vd2z7a6w3#

我在Sping Boot 应用程序中解决了这个问题,方法是在bean中获取TomcatServletWebServerFactory,并向其中添加我自己的连接器定制器。

@Bean
public ServletWebServerFactory servletContainer() {

    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
    // --- CUSTOMIZE SSL PORT IN ORDER TO BE ABLE TO RELOAD THE SSL HOST CONFIG
    tomcat.addConnectorCustomizers(new DefaultSSLConnectorCustomizer());            
    return tomcat;
}

字符串
我的定制器提取了https的协议供以后使用

public class DefaultSSLConnectorCustomizer implements TomcatConnectorCustomizer {

private Http11NioProtocol protocol;

@Override
public void customize(Connector connector) {

    Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
    if ( connector.getSecure()) {
        //--- REMEMBER PROTOCOL WHICH WE NEED LATER IN ORDER TO RELOAD SSL CONFIG
        this.protocol = protocol;
    }
}

protected Http11NioProtocol getProtocol() {
    return protocol;
}


}
当我用新的私钥更新密钥库时,我会重新加载SSL主机配置。

@Component
public class TomcatUtil {

    public static final String DEFAULT_SSL_HOSTNAME_CONFIG_NAME = "_default_";

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private ServletWebServerFactory servletWebServerFactory;

    public TomcatUtil(ServletWebServerFactory servletWebServerFactory) {

        this.servletWebServerFactory = servletWebServerFactory;
    }

    public void reloadSSLHostConfig() {

        TomcatServletWebServerFactory tomcatFactoty = (TomcatServletWebServerFactory) servletWebServerFactory;
        Collection<TomcatConnectorCustomizer> customizers = tomcatFactoty.getTomcatConnectorCustomizers();
        for (TomcatConnectorCustomizer tomcatConnectorCustomizer : customizers) {

            if (tomcatConnectorCustomizer instanceof DefaultSSLConnectorCustomizer) {
                DefaultSSLConnectorCustomizer customizer = (DefaultSSLConnectorCustomizer) tomcatConnectorCustomizer;
                Http11NioProtocol protocol = customizer.getProtocol();
                try {
                    protocol.reloadSslHostConfig(DEFAULT_SSL_HOSTNAME_CONFIG_NAME);
                    logger.info("Reloaded SSL host configuration");
                } catch (IllegalArgumentException e) {
                    logger.warn("Cannot reload SSL host configuration", e);
                }
            }
        }

    }
}


最后

...
                renewServerCertificate();
                tomcatUtil.reloadSSLHostConfig();

jtw3ybtb

jtw3ybtb4#

从Sping Boot 3.2开始,可以热重载(至少对于Tomcat和Netty嵌入式Web服务器)。
要使用该功能,请执行以下操作:
1.定义一个SSL包(我们称之为“demo”)

spring.ssl.bundle.pem:
  demo:
    reload-on-update: true
    keystore:    
      certificate: "certs/demo.crt"
      private-key: "certs/demo.key"

字符串
1.然后将Web服务器指向它

server.ssl.bundle: "demo"


P.S.这里有一篇关于如何使用https://spring.io/blog/2023/11/07/ssl-hot-reload-in-spring-boot-3-2-0功能的好文章

相关问题