mirror of https://github.com/apache/druid.git
Add an option to enable HSTS in druid services (#13489)
* Add an option to enable HSTS * Fix code and add docs * Deduplicate headers * unused import * Fix spelling
This commit is contained in:
parent
2503095296
commit
17936e2920
|
@ -1823,6 +1823,7 @@ Druid uses Jetty to serve HTTP requests. Each query being processed consumes a s
|
|||
|`druid.server.http.maxQueryTimeout`|Maximum allowed value (in milliseconds) for `timeout` parameter. See [query-context](../querying/query-context.md) to know more about `timeout`. Query is rejected if the query context `timeout` is greater than this value. |Long.MAX_VALUE|
|
||||
|`druid.server.http.maxRequestHeaderSize`|Maximum size of a request header in bytes. Larger headers consume more memory and can make a server more vulnerable to denial of service attacks. |8 * 1024|
|
||||
|`druid.server.http.contentSecurityPolicy`|Content-Security-Policy header value to set on each non-POST response. Setting this property to an empty string, or omitting it, both result in the default `frame-ancestors: none` being set.|`frame-ancestors 'none'`|
|
||||
|`druid.server.http.enableHSTS`|If set to true, druid services will add strict transport security header `Strict-Transport-Security: max-age=63072000; includeSubDomains` to all HTTP responses|`false`|
|
||||
|
||||
##### Client Configuration
|
||||
|
||||
|
|
|
@ -131,6 +131,10 @@
|
|||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-proxy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
|
|
|
@ -67,7 +67,8 @@ public class ServerConfig
|
|||
@NotNull List<String> allowedHttpMethods,
|
||||
boolean showDetailedJettyErrors,
|
||||
@NotNull ErrorResponseTransformStrategy errorResponseTransformStrategy,
|
||||
@Nullable String contentSecurityPolicy
|
||||
@Nullable String contentSecurityPolicy,
|
||||
boolean enableHSTS
|
||||
)
|
||||
{
|
||||
this.numThreads = numThreads;
|
||||
|
@ -88,6 +89,7 @@ public class ServerConfig
|
|||
this.showDetailedJettyErrors = showDetailedJettyErrors;
|
||||
this.errorResponseTransformStrategy = errorResponseTransformStrategy;
|
||||
this.contentSecurityPolicy = contentSecurityPolicy;
|
||||
this.enableHSTS = enableHSTS;
|
||||
}
|
||||
|
||||
public ServerConfig()
|
||||
|
@ -161,6 +163,9 @@ public class ServerConfig
|
|||
@JsonProperty("contentSecurityPolicy")
|
||||
private String contentSecurityPolicy;
|
||||
|
||||
@JsonProperty
|
||||
private boolean enableHSTS = false;
|
||||
|
||||
@JsonProperty
|
||||
private boolean showDetailedJettyErrors = true;
|
||||
|
||||
|
@ -255,6 +260,11 @@ public class ServerConfig
|
|||
return contentSecurityPolicy;
|
||||
}
|
||||
|
||||
public boolean isEnableHSTS()
|
||||
{
|
||||
return enableHSTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
|
@ -282,7 +292,8 @@ public class ServerConfig
|
|||
unannouncePropagationDelay.equals(that.unannouncePropagationDelay) &&
|
||||
allowedHttpMethods.equals(that.allowedHttpMethods) &&
|
||||
errorResponseTransformStrategy.equals(that.errorResponseTransformStrategy) &&
|
||||
Objects.equals(contentSecurityPolicy, that.getContentSecurityPolicy());
|
||||
Objects.equals(contentSecurityPolicy, that.getContentSecurityPolicy()) &&
|
||||
enableHSTS == that.enableHSTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -306,7 +317,8 @@ public class ServerConfig
|
|||
allowedHttpMethods,
|
||||
errorResponseTransformStrategy,
|
||||
showDetailedJettyErrors,
|
||||
contentSecurityPolicy
|
||||
contentSecurityPolicy,
|
||||
enableHSTS
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -332,6 +344,7 @@ public class ServerConfig
|
|||
", errorResponseTransformStrategy=" + errorResponseTransformStrategy +
|
||||
", showDetailedJettyErrors=" + showDetailedJettyErrors +
|
||||
", contentSecurityPolicy=" + contentSecurityPolicy +
|
||||
", enableHSTS=" + enableHSTS +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
|
|
@ -163,7 +163,8 @@ public class CliIndexerServerModule implements Module
|
|||
oldConfig.getAllowedHttpMethods(),
|
||||
oldConfig.isShowDetailedJettyErrors(),
|
||||
oldConfig.getErrorResponseTransformStrategy(),
|
||||
oldConfig.getContentSecurityPolicy()
|
||||
oldConfig.getContentSecurityPolicy(),
|
||||
oldConfig.isEnableHSTS()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,12 @@ import com.google.inject.Injector;
|
|||
import com.google.inject.Key;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import org.apache.druid.java.util.common.ISE;
|
||||
import org.apache.druid.server.initialization.ServerConfig;
|
||||
import org.apache.druid.server.security.AllowHttpMethodsResourceFilter;
|
||||
import org.eclipse.jetty.rewrite.handler.HeaderPatternRule;
|
||||
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
|
@ -32,6 +36,7 @@ import org.eclipse.jetty.servlet.FilterMapping;
|
|||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
|
||||
import javax.ws.rs.HttpMethod;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -122,4 +127,25 @@ public class JettyServerInitUtils
|
|||
null
|
||||
);
|
||||
}
|
||||
|
||||
public static void maybeAddHSTSPatternRule(ServerConfig serverConfig, RewriteHandler rewriteHandler)
|
||||
{
|
||||
if (serverConfig.isEnableHSTS()) {
|
||||
rewriteHandler.addRule(getHSTSHeaderPattern());
|
||||
}
|
||||
}
|
||||
|
||||
public static void maybeAddHSTSRewriteHandler(ServerConfig serverConfig, HandlerList handlerList)
|
||||
{
|
||||
if (serverConfig.isEnableHSTS()) {
|
||||
RewriteHandler rewriteHandler = new RewriteHandler();
|
||||
rewriteHandler.addRule(getHSTSHeaderPattern());
|
||||
handlerList.addHandler(rewriteHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private static HeaderPatternRule getHSTSHeaderPattern()
|
||||
{
|
||||
return new HeaderPatternRule("*", "Strict-Transport-Security", "max-age=63072000; includeSubDomains");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import javax.servlet.ServletResponse;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
|
@ -48,7 +49,9 @@ import java.util.Set;
|
|||
*/
|
||||
public class StandardResponseHeaderFilterHolder implements ServletFilterHolder
|
||||
{
|
||||
private static final Set<String> STANDARD_HEADERS = ImmutableSet.of("Cache-Control", "Content-Security-Policy");
|
||||
private static final Set<String> STANDARD_HEADERS = ImmutableSet.of("Cache-Control",
|
||||
"Content-Security-Policy",
|
||||
"Strict-Transport-Security");
|
||||
private static final String DEFAULT_CONTENT_SECURITY_POLICY = "frame-ancestors 'none'";
|
||||
|
||||
private final String contentSecurityPolicy;
|
||||
|
|
|
@ -42,6 +42,7 @@ public class ServerConfigTest
|
|||
ServerConfig defaultConfig2 = OBJECT_MAPPER.readValue(defaultConfigJson, ServerConfig.class);
|
||||
Assert.assertEquals(defaultConfig, defaultConfig2);
|
||||
Assert.assertFalse(defaultConfig2.isEnableForwardedRequestCustomizer());
|
||||
Assert.assertFalse(defaultConfig2.isEnableHSTS());
|
||||
|
||||
ServerConfig modifiedConfig = new ServerConfig(
|
||||
999,
|
||||
|
@ -61,7 +62,8 @@ public class ServerConfigTest
|
|||
ImmutableList.of(HttpMethod.OPTIONS),
|
||||
true,
|
||||
new AllowedRegexErrorResponseTransformStrategy(ImmutableList.of(".*")),
|
||||
"my-cool-policy"
|
||||
"my-cool-policy",
|
||||
true
|
||||
);
|
||||
String modifiedConfigJson = OBJECT_MAPPER.writeValueAsString(modifiedConfig);
|
||||
ServerConfig modifiedConfig2 = OBJECT_MAPPER.readValue(modifiedConfigJson, ServerConfig.class);
|
||||
|
@ -74,6 +76,7 @@ public class ServerConfigTest
|
|||
Assert.assertTrue(modifiedConfig2.getAllowedHttpMethods().contains(HttpMethod.OPTIONS));
|
||||
Assert.assertEquals("my-cool-policy", modifiedConfig.getContentSecurityPolicy());
|
||||
Assert.assertEquals("my-cool-policy", modifiedConfig2.getContentSecurityPolicy());
|
||||
Assert.assertTrue(modifiedConfig2.isEnableHSTS());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -122,6 +122,7 @@ import org.apache.druid.server.security.Authenticator;
|
|||
import org.apache.druid.server.security.AuthenticatorMapper;
|
||||
import org.apache.druid.tasklogs.TaskLogStreamer;
|
||||
import org.apache.druid.tasklogs.TaskLogs;
|
||||
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
|
@ -449,10 +450,13 @@ public class CliOverlord extends ServerRunnable
|
|||
|
||||
root.addFilter(GuiceFilter.class, "/druid-ext/*", null);
|
||||
|
||||
RewriteHandler rewriteHandler = WebConsoleJettyServerInitializer.createWebConsoleRewriteHandler();
|
||||
JettyServerInitUtils.maybeAddHSTSPatternRule(serverConfig, rewriteHandler);
|
||||
|
||||
HandlerList handlerList = new HandlerList();
|
||||
handlerList.setHandlers(
|
||||
new Handler[]{
|
||||
WebConsoleJettyServerInitializer.createWebConsoleRewriteHandler(),
|
||||
rewriteHandler,
|
||||
JettyServerInitUtils.getJettyRequestLogHandler(),
|
||||
JettyServerInitUtils.wrapWithDefaultGzipHandler(
|
||||
root,
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.druid.server.security.AuthConfig;
|
|||
import org.apache.druid.server.security.AuthenticationUtils;
|
||||
import org.apache.druid.server.security.Authenticator;
|
||||
import org.apache.druid.server.security.AuthenticatorMapper;
|
||||
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
|
@ -131,10 +132,13 @@ class CoordinatorJettyServerInitializer implements JettyServerInitializer
|
|||
root.addServlet(new ServletHolder(injector.getInstance(OverlordProxyServlet.class)), "/druid/indexer/*");
|
||||
}
|
||||
|
||||
RewriteHandler rewriteHandler = WebConsoleJettyServerInitializer.createWebConsoleRewriteHandler();
|
||||
JettyServerInitUtils.maybeAddHSTSPatternRule(serverConfig, rewriteHandler);
|
||||
|
||||
HandlerList handlerList = new HandlerList();
|
||||
handlerList.setHandlers(
|
||||
new Handler[]{
|
||||
WebConsoleJettyServerInitializer.createWebConsoleRewriteHandler(),
|
||||
rewriteHandler,
|
||||
JettyServerInitUtils.getJettyRequestLogHandler(),
|
||||
JettyServerInitUtils.wrapWithDefaultGzipHandler(
|
||||
root,
|
||||
|
|
|
@ -108,6 +108,7 @@ class MiddleManagerJettyServerInitializer implements JettyServerInitializer
|
|||
new DefaultHandler()
|
||||
}
|
||||
);
|
||||
JettyServerInitUtils.maybeAddHSTSRewriteHandler(serverConfig, handlerList);
|
||||
server.setHandler(handlerList);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,8 @@ public class QueryJettyServerInitializer implements JettyServerInitializer
|
|||
handlerList.addHandler(handler);
|
||||
}
|
||||
|
||||
JettyServerInitUtils.maybeAddHSTSRewriteHandler(serverConfig, handlerList);
|
||||
|
||||
// Add Gzip handler at the very end
|
||||
handlerList.addHandler(JettyServerInitUtils.wrapWithDefaultGzipHandler(
|
||||
root,
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.apache.druid.server.security.Authenticator;
|
|||
import org.apache.druid.server.security.AuthenticatorMapper;
|
||||
import org.apache.druid.sql.avatica.DruidAvaticaJsonHandler;
|
||||
import org.apache.druid.sql.avatica.DruidAvaticaProtobufHandler;
|
||||
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
|
@ -146,10 +147,13 @@ public class RouterJettyServerInitializer implements JettyServerInitializer
|
|||
root.addFilter(GuiceFilter.class, "/druid/router/*", null);
|
||||
root.addFilter(GuiceFilter.class, "/druid-ext/*", null);
|
||||
|
||||
RewriteHandler rewriteHandler = WebConsoleJettyServerInitializer.createWebConsoleRewriteHandler();
|
||||
JettyServerInitUtils.maybeAddHSTSPatternRule(serverConfig, rewriteHandler);
|
||||
|
||||
final HandlerList handlerList = new HandlerList();
|
||||
handlerList.setHandlers(
|
||||
new Handler[]{
|
||||
WebConsoleJettyServerInitializer.createWebConsoleRewriteHandler(),
|
||||
rewriteHandler,
|
||||
JettyServerInitUtils.getJettyRequestLogHandler(),
|
||||
JettyServerInitUtils.wrapWithDefaultGzipHandler(
|
||||
root,
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.apache.druid.java.util.common.StringUtils;
|
|||
import org.apache.druid.server.security.AuthenticationUtils;
|
||||
import org.eclipse.jetty.rewrite.handler.RedirectPatternRule;
|
||||
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
|
@ -57,7 +56,7 @@ class WebConsoleJettyServerInitializer
|
|||
AuthenticationUtils.addNoopAuthorizationFilters(root, UNAUTHORIZED_PATHS_FOR_UI);
|
||||
}
|
||||
|
||||
static Handler createWebConsoleRewriteHandler()
|
||||
static RewriteHandler createWebConsoleRewriteHandler()
|
||||
{
|
||||
// redirect all legacy web consoles to current unified web console
|
||||
RewriteHandler rewrite = new RewriteHandler();
|
||||
|
|
Loading…
Reference in New Issue