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
This commit is contained in:
vvc11 2018-02-19 02:21:02 +05:30 committed by Slim
parent deeda0dff2
commit 305ecc2a78
7 changed files with 82 additions and 4 deletions

View File

@ -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"]

View File

@ -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<String> 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<String> getHiddenProperties()
{
return hiddenProperties;
}
}

View File

@ -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<String, String> getProperties()
{
Map<String, String> allProperties = Maps.fromProperties(properties);
Set<String> hidderProperties = druidServerConfig.getHiddenProperties();
return Maps.filterEntries(allProperties, (entry) -> !hidderProperties.contains(entry.getKey()));
}
@GET
@ResourceFilters(StateResourceFilter.class)
@Produces(MediaType.APPLICATION_JSON)

View File

@ -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");
}
}

View File

@ -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;

View File

@ -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<String, String> returnedProperties = injector.getInstance(StatusResource.class).getProperties();
Set<String> hiddenProperties = Sets.newHashSet();
Splitter.on(",").split(returnedProperties.get("druid.server.hiddenProperties")).forEach(hiddenProperties::add);
hiddenProperties.forEach((property) -> Assert.assertNull(returnedProperties.get(property)));
}
}

View File

@ -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