问题
Does Spring Boot support Server Name Indication (SNI)? Specifically, is it possible for a Spring Boot (2.2.2.RELEASE) application running an embedded Tomcat server and packaged as an executable jar file to support multiple SSL certificates/domains based on the hostname of the incoming request?
It appears Tomcat supports SNI (as of Tomcat 8.5), but I'm not sure how to implement SNI in my Spring Boot app.
回答1:
I was able to verify that Spring Boot running an embedded Tomcat server supports Server Name Indication (SNI) using the following config:
application.properties
abc.com.key-store=${user.dir}/abc.com.p12
xyz.com.key-store=${user.dir}/xyz.com.p12
ApplicationConfig.java
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration
public class ApplicationConfig {
@Autowired
private Environment env;
@Bean
public ServletWebServerFactory servletContainer() throws Exception {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
// Override TomcatServletWebServerFactory methods (if needed)
};
// add SSL Connector
tomcat.addAdditionalTomcatConnectors(createSSLConnectorForMultipleHosts());
return tomcat;
}
private Connector createSSLConnectorForMultipleHosts() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
/**
* Tomcat 9.0.x server SSL Connector for multiple hosts
*
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true"
defaultSSLHostConfigName="*.abc.com">
<SSLHostConfig hostName="*.abc.com">
<Certificate certificateKeystoreFile="conf/abc.com.p12"
type="RSA" />
</SSLHostConfig>
<SSLHostConfig hostName="*.xyz.com">
<Certificate certificateKeystoreFile="conf/xyz.com.p12"
type="RSA" />
</SSLHostConfig>
</Connector>
*/
try {
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(8443);
connector.setAttribute("SSLEnabled", "true");
connector.setAttribute("defaultSSLHostConfigName", "*.abc.com");
// *.abc.com
SSLHostConfig sslHostConfig = new SSLHostConfig();
sslHostConfig.setHostName("*.abc.com");
SSLHostConfigCertificate sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
sslHostConfigCertificate.setCertificateKeystoreFile(env.getProperty("abc.com.key-store"));
sslHostConfig.addCertificate(sslHostConfigCertificate);
connector.addSslHostConfig(sslHostConfig);
// *.xyz.com
sslHostConfig = new SSLHostConfig();
sslHostConfig.setHostName("*.xyz.com");
sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
sslHostConfigCertificate.setCertificateKeystoreFile(env.getProperty("xyz.com.key-store"));
sslHostConfig.addCertificate(sslHostConfigCertificate);
connector.addSslHostConfig(sslHostConfig);
return connector;
}
catch (Exception ex) {
throw new IllegalStateException("Exception creating SSL Connector: ", ex);
}
}
}
回答2:
Spring supports tomcat connector configuration. I did not run this code but this will give you some idea. You can try something like this:
@Bean
public ServletWebServerFactory servletContainer() throws Exception {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(createConnector());
return tomcat;
}
public Connector createConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11AprProtocol");
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(8443);
connector.addSslHostConfig(getSSLHostConfig());
return connector;
}
private SSLHostConfig getSSLHostConfig() {
SSLHostConfig sslHostConfig = new SSLHostConfig();
sslHostConfig.setHostName("abc.com");
sslHostConfig.setCertificateFile("abc.crt");
sslHostConfig.setCaCertificateFile("xyz.crt");
return sslHostConfig;
}
来源:https://stackoverflow.com/questions/60514176/does-spring-boot-support-server-name-indication-sni