对SSL证书进行任何更改(在其密钥库中),我们需要重新启动spring boot应用程序。我想定期(可能是每年)更新我的密钥库条目,但希望避免重新启动JVM。要实现它需要什么。我想知道编写自定义KeyManager是否可以接受?
答案 0 :(得分:3)
不幸的是,这是不可能的。
这里有几个解决方案。
您可以重新启动Tomcat
连接器,即更改8843
文件后可以重新启动jssecacert
。
但我认为它仍然是一个黑客。
Nginx
,Apache
这是一种方法。您的应用程序应位于某个反向代理(例如nginx
)之后。这将为您提供额外的灵活性并减少应用程序的负担。 Nginx
会处理https
并将其翻译为普通http
。无论如何,您必须重新启动nginx
,但nginx
重新启动速度非常快,以至于不会停机。此外,您可以配置脚本来为您执行此操作。
答案 1 :(得分:0)
在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
。我只是担心名称会更改,所以我会介绍所有可能性,以防万一。
答案 2 :(得分:0)
我已经通过在Spring Boot应用程序中解决了这个问题
TomcatServletWebServerFactory
在bean中,然后向其中添加我自己的连接器定制器。
@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();