From 305ecc2a782e189d35af2deea9c29ebceb46c1cc Mon Sep 17 00:00:00 2001 From: vvc11 Date: Mon, 19 Feb 2018 02:21:02 +0530 Subject: [PATCH] adding a properties endpoint in status resource (#5276) * adding a properties endpoint in status resource * checkstyle fixes * more checkstyle corrections * correcting the resource filter for properties endpoint * adding feature of hiding sensitive properties * checkstyle changes * review changes for adding default hidden properties and using jackson for arrays value * making review changes --- .../druid/_common/common.runtime.properties | 5 ++++ .../io/druid/client/DruidServerConfig.java | 12 ++++++++ .../java/io/druid/server/StatusResource.java | 30 +++++++++++++++++++ .../http/security/ConfigResourceFilter.java | 1 + .../jetty/JettyServerModule.java | 8 ++--- .../io/druid/server/StatusResourceTest.java | 19 ++++++++++++ .../status.resource.test.runtime.properties | 11 +++++++ 7 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 server/src/test/resources/status.resource.test.runtime.properties diff --git a/examples/conf-quickstart/druid/_common/common.runtime.properties b/examples/conf-quickstart/druid/_common/common.runtime.properties index ee5b284b527..2bc2b72f6c9 100644 --- a/examples/conf-quickstart/druid/_common/common.runtime.properties +++ b/examples/conf-quickstart/druid/_common/common.runtime.properties @@ -121,3 +121,8 @@ druid.emitter.logging.logLevel=info # ommiting this will lead to index double as float at the storage layer druid.indexing.doubleStorage=double + +# +# Security +# +druid.server.hiddenProperties=["druid.s3.accessKey","druid.s3.secretKey","druid.metadata.storage.connector.password"] diff --git a/server/src/main/java/io/druid/client/DruidServerConfig.java b/server/src/main/java/io/druid/client/DruidServerConfig.java index 9ad46882621..566369d25e4 100644 --- a/server/src/main/java/io/druid/client/DruidServerConfig.java +++ b/server/src/main/java/io/druid/client/DruidServerConfig.java @@ -20,8 +20,11 @@ package io.druid.client; import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Sets; import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.Set; /** */ @@ -37,6 +40,10 @@ public class DruidServerConfig @JsonProperty private int priority = DruidServer.DEFAULT_PRIORITY; + @JsonProperty + @NotNull + private Set hiddenProperties = Sets.newHashSet("druid.s3.accessKey", "druid.s3.secretKey", "druid.metadata.storage.connector.password"); + public long getMaxSize() { return maxSize; @@ -51,4 +58,9 @@ public class DruidServerConfig { return priority; } + + public Set getHiddenProperties() + { + return hiddenProperties; + } } diff --git a/server/src/main/java/io/druid/server/StatusResource.java b/server/src/main/java/io/druid/server/StatusResource.java index 432e5b58a59..f08ba8b63a8 100644 --- a/server/src/main/java/io/druid/server/StatusResource.java +++ b/server/src/main/java/io/druid/server/StatusResource.java @@ -21,12 +21,16 @@ package io.druid.server; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Maps; import com.sun.jersey.spi.container.ResourceFilters; +import io.druid.client.DruidServerConfig; import io.druid.initialization.DruidModule; import io.druid.initialization.Initialization; import io.druid.java.util.common.StringUtils; +import io.druid.server.http.security.ConfigResourceFilter; import io.druid.server.http.security.StateResourceFilter; +import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; @@ -34,12 +38,38 @@ import javax.ws.rs.core.MediaType; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; /** */ @Path("/status") public class StatusResource { + + private final Properties properties; + + private final DruidServerConfig druidServerConfig; + + @Inject + public StatusResource(Properties properties, DruidServerConfig druidServerConfig) + { + this.properties = properties; + this.druidServerConfig = druidServerConfig; + } + + @GET + @Path("/properties") + @ResourceFilters(ConfigResourceFilter.class) + @Produces(MediaType.APPLICATION_JSON) + public Map getProperties() + { + Map allProperties = Maps.fromProperties(properties); + Set hidderProperties = druidServerConfig.getHiddenProperties(); + return Maps.filterEntries(allProperties, (entry) -> !hidderProperties.contains(entry.getKey())); + } + @GET @ResourceFilters(StateResourceFilter.class) @Produces(MediaType.APPLICATION_JSON) diff --git a/server/src/main/java/io/druid/server/http/security/ConfigResourceFilter.java b/server/src/main/java/io/druid/server/http/security/ConfigResourceFilter.java index da50a0b0f5b..94a99d8d060 100644 --- a/server/src/main/java/io/druid/server/http/security/ConfigResourceFilter.java +++ b/server/src/main/java/io/druid/server/http/security/ConfigResourceFilter.java @@ -74,6 +74,7 @@ public class ConfigResourceFilter extends AbstractResourceFilter { return requestPath.startsWith("druid/worker/v1") || requestPath.startsWith("druid/indexer/v1") || + requestPath.startsWith("status/properties") || requestPath.startsWith("druid/coordinator/v1/config"); } } diff --git a/server/src/main/java/io/druid/server/initialization/jetty/JettyServerModule.java b/server/src/main/java/io/druid/server/initialization/jetty/JettyServerModule.java index 4eb92b253ed..e3b7368f5f5 100644 --- a/server/src/main/java/io/druid/server/initialization/jetty/JettyServerModule.java +++ b/server/src/main/java/io/druid/server/initialization/jetty/JettyServerModule.java @@ -33,10 +33,6 @@ import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.Singleton; import com.google.inject.multibindings.Multibinder; -import io.druid.java.util.emitter.service.ServiceEmitter; -import io.druid.java.util.emitter.service.ServiceMetricEvent; -import io.druid.java.util.metrics.AbstractMonitor; -import io.druid.java.util.metrics.MonitorUtils; import com.sun.jersey.api.core.DefaultResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.guice.JerseyServletModule; @@ -53,6 +49,10 @@ import io.druid.java.util.common.ISE; import io.druid.java.util.common.RE; import io.druid.java.util.common.lifecycle.Lifecycle; import io.druid.java.util.common.logger.Logger; +import io.druid.java.util.emitter.service.ServiceEmitter; +import io.druid.java.util.emitter.service.ServiceMetricEvent; +import io.druid.java.util.metrics.AbstractMonitor; +import io.druid.java.util.metrics.MonitorUtils; import io.druid.server.DruidNode; import io.druid.server.StatusResource; import io.druid.server.initialization.ServerConfig; diff --git a/server/src/test/java/io/druid/server/StatusResourceTest.java b/server/src/test/java/io/druid/server/StatusResourceTest.java index fc54bf829a3..f0572e94498 100644 --- a/server/src/test/java/io/druid/server/StatusResourceTest.java +++ b/server/src/test/java/io/druid/server/StatusResourceTest.java @@ -19,14 +19,22 @@ package io.druid.server; +import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import com.google.inject.Guice; +import com.google.inject.Injector; +import io.druid.guice.PropertiesModule; import io.druid.initialization.DruidModule; import io.druid.initialization.InitializationTest; import org.junit.Assert; import org.junit.Test; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; import static io.druid.server.StatusResource.ModuleVersion; @@ -55,5 +63,16 @@ public class StatusResourceTest Assert.assertTrue("Status resource should contain module " + moduleName, contains); } } + + @Test + public void testPropertiesWithRestrictedConfigs() + { + Injector injector = Guice.createInjector(Collections.singletonList(new PropertiesModule(Collections.singletonList( + "status.resource.test.runtime.properties")))); + Map returnedProperties = injector.getInstance(StatusResource.class).getProperties(); + Set hiddenProperties = Sets.newHashSet(); + Splitter.on(",").split(returnedProperties.get("druid.server.hiddenProperties")).forEach(hiddenProperties::add); + hiddenProperties.forEach((property) -> Assert.assertNull(returnedProperties.get(property))); + } } diff --git a/server/src/test/resources/status.resource.test.runtime.properties b/server/src/test/resources/status.resource.test.runtime.properties new file mode 100644 index 00000000000..f009be7d385 --- /dev/null +++ b/server/src/test/resources/status.resource.test.runtime.properties @@ -0,0 +1,11 @@ +druid.server.hiddenProperties=["druid.s3.accessKey","druid.s3.secretKey","druid.metadata.storage.connector.password"] +druid.storage.type=s3 +druid.storage.bucket=your-bucket +druid.storage.baseKey=druid/segments +druid.s3.accessKey=s3accesskey +druid.s3.secretKey=s3secretkey + +druid.metadata.storage.type=mysql +druid.metadata.storage.connector.connectURI=jdbc:mysql://db.example.com:3306/druid +druid.metadata.storage.connector.user=druiduser +druid.metadata.storage.connector.password=password123