Open blacknebula1 opened 1 year ago
Since I have the same problem: the corresponding config attributes for jetty are jetty.sslContext.sniRequired and jetty.ssl.sniHostCheck (source)
We can certainly consider adding a configuration property to disable the check. In the meantime, you can disable it with a JettyServerCustomizer
:
@Bean
JettyServerCustomizer disableSniHostCheck() {
return (server) -> {
for (Connector connector : server.getConnectors()) {
if (connector instanceof ServerConnector serverConnector) {
HttpConnectionFactory connectionFactory = serverConnector
.getConnectionFactory(HttpConnectionFactory.class);
if (connectionFactory != null) {
SecureRequestCustomizer secureRequestCustomizer = connectionFactory.getHttpConfiguration()
.getCustomizer(SecureRequestCustomizer.class);
if (secureRequestCustomizer != null) {
secureRequestCustomizer.setSniHostCheck(false);
}
}
}
}
};
}
When looking at this we should see if the other embedded web servers have similar configuration options and expand the scope of the issue as appropriate.
@wilkinsona your workaround seems to work for the primary app, but not for management. As my example shows, we have the primary app running on port 8443 while the management app runs on 8444. Do you have an idea how to override the management SecureRequestCustomizer by any chance?
If you wrap it in a WebServerFactoryCustomizer
, I think it'll be applied to be the main server and the management server:
@Bean
WebServerFactoryCustomizer<JettyServletWebServerFactory> disableSniHostCheck() {
return (factory) -> {
factory.addServerCustomizers((server) -> {
for (Connector connector : server.getConnectors()) {
if (connector instanceof ServerConnector serverConnector) {
HttpConnectionFactory connectionFactory = serverConnector
.getConnectionFactory(HttpConnectionFactory.class);
if (connectionFactory != null) {
SecureRequestCustomizer secureRequestCustomizer = connectionFactory.getHttpConfiguration()
.getCustomizer(SecureRequestCustomizer.class);
if (secureRequestCustomizer != null) {
secureRequestCustomizer.setSniHostCheck(false);
}
}
}
}
});
};
}
@wilkinsona still seeing the same issue on management with the above snippet. Seems that bean is hit before creating the management stuff.
Sorry, I think I've got it this time. The bean needs to be defined within a @ManagementContextConfiguration
:
@ManagementContextConfiguration(proxyBeanMethods = false)
class DisableSniHostCheckConfiguration {
@Bean
WebServerFactoryCustomizer<JettyServletWebServerFactory> disableSniHostCheck() {
return (factory) -> {
factory.addServerCustomizers((server) -> {
for (Connector connector : server.getConnectors()) {
if (connector instanceof ServerConnector serverConnector) {
HttpConnectionFactory connectionFactory = serverConnector
.getConnectionFactory(HttpConnectionFactory.class);
if (connectionFactory != null) {
SecureRequestCustomizer secureRequestCustomizer = connectionFactory.getHttpConfiguration()
.getCustomizer(SecureRequestCustomizer.class);
if (secureRequestCustomizer != null) {
secureRequestCustomizer.setSniHostCheck(false);
}
}
}
}
});
};
}
}
If this class is in a package that's picked up by component scanning, that will be sufficient for the main web server. For the Actuator's server you also need to create a META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports
file in src/main/resources
that lists the class:
com.example.actuatorservice.DisableSniHostCheckConfiguration
The above solution seems to do the trick.
We can certainly consider adding a configuration property to disable the check. In the meantime, you can disable it with a
JettyServerCustomizer
:@Bean JettyServerCustomizer disableSniHostCheck() { return (server) -> { for (Connector connector : server.getConnectors()) { if (connector instanceof ServerConnector serverConnector) { HttpConnectionFactory connectionFactory = serverConnector .getConnectionFactory(HttpConnectionFactory.class); if (connectionFactory != null) { SecureRequestCustomizer secureRequestCustomizer = connectionFactory.getHttpConfiguration() .getCustomizer(SecureRequestCustomizer.class); if (secureRequestCustomizer != null) { secureRequestCustomizer.setSniHostCheck(false); } } } } }; }
Had the same issue, after scrounging around for a solution for day or two, Andy's first workaround given above worked.. Thanks!
The above solution seems to do the trick.
Same for me, Thank you @wilkinsona
I'm not sure it's a good idea for Spring Boot to support properties that make it easier to disable important security features like hostname validation on SSL/TLS connections. I realize that it is sometimes necessary, but we should think about how easy we should make it.
Andy has shown that it's possible to do this custom configuration with a JettyServerCustomizer
now, but digging into the org.eclipse.jetty.server.Server
to get down to the SecureRequestCustomizer
is a bit cumbersome. Perhaps instead of adding support for a property we could improve the JettyServerCustomizer
or add a new type of customizer that makes it easier to get to the HttpConnectionFactory
or the SecureRequestCustomizer
.
I'm hitting this while trying to configure kubernetes liveness and readiness checks against my application. End to end encryption, kubernetes, and Spring Boot are all common enough that I'm surprised there isn't more discussion around it.
Configuring SSL on Jetty via Spring Boot is easy enough via configuration, but the 400 SNI error hits when kubernetes performs its liveness probe. It uses the IP address of the pod directly, which isn't an allowed host.
The provided workaround is very helpful, but it's still a bit of a gross solution to the problem.
Summary Need a way to disable sniHostCheck
Sample Repository https://github.com/blacknebula1/sni-host-check-example
Setup Java Version: 17.x Spring Version: 3.1.1
Description We are in the process of migrating to spring boot 3.x When we moved to spring boot 3, we noticed that unless the domain name in the request matches what is present in the keystore we get this error:
After doing some further digging into this issue, it appears the issue is only present when not using the fqdn found in the provided keystore.
The issue is only encountered on the main app when SecureRequestCustomizer is called using the default constructor on this class https://github.com/maharshi95/Jetty/blob/master/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java#L67
I noticed in SslServerCustomizer we are calling the default constructor, therefore enforcing sniHostCheck https://github.com/spring-projects/spring-boot/blob/a460f7474fa66253158415834f3e41d121641dda/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/SslServerCustomizer.java#L84
This sni host checking seems to be an issue on the main app as well as actuator when running on different ports.
Suggesting we provide some sort of config option that will allow us to access the app as well as actuator (running on a separate port) via IP address. something like this would be awesome
server.ssl.sni-host-check=false management.server.ssl.sni-host-check=false