Provisioning support for ZooKeeper Authorization (#5701)

Review comments implemented
This commit is contained in:
varaga 2018-06-15 22:02:01 +01:00 committed by Jonathan Wei
parent 8c6651022d
commit b4b1b2a020
4 changed files with 68 additions and 19 deletions

View File

@ -42,6 +42,9 @@ We recommend just setting the base ZK path and the ZK service host, but all ZK p
|--------|-----------|-------|
|`druid.zk.paths.base`|Base Zookeeper path.|`/druid`|
|`druid.zk.service.host`|The ZooKeeper hosts to connect to. This is a REQUIRED property and therefore a host address must be supplied.|none|
|`druid.zk.service.user`|The username to authenticate with ZooKeeper. This is an optional property.|none|
|`druid.zk.service.pwd`|The [Password Provider](../operations/password-provider.html) or the string password to authenticate with ZooKeeper. This is an optional property.|none|
|`druid.zk.service.authScheme`|digest is the only authentication scheme supported. |digest|
#### Zookeeper Behavior

View File

@ -19,10 +19,13 @@
package io.druid.curator;
import javax.validation.constraints.Min;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import javax.validation.constraints.Min;
import io.druid.metadata.DefaultPasswordProvider;
import io.druid.metadata.PasswordProvider;
/**
*/
@ -41,6 +44,15 @@ public class CuratorConfig
@JsonProperty("acl")
private boolean enableAcl = false;
@JsonProperty("user")
private String zkUser;
@JsonProperty("pwd")
private PasswordProvider zkPwd = new DefaultPasswordProvider("");
@JsonProperty("authScheme")
private String authScheme = "digest";
public String getZkHosts()
{
return zkHosts;
@ -82,4 +94,20 @@ public class CuratorConfig
Preconditions.checkNotNull(enableAcl, "enableAcl");
this.enableAcl = enableAcl;
}
public String getZkUser()
{
return zkUser;
}
public String getZkPwd()
{
return zkPwd.getPassword();
}
public String getAuthScheme()
{
return authScheme;
}
}

View File

@ -19,13 +19,9 @@
package io.druid.curator;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.Provides;
import io.druid.guice.JsonConfigProvider;
import io.druid.guice.LazySingleton;
import io.druid.java.util.common.lifecycle.Lifecycle;
import io.druid.java.util.common.logger.Logger;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.apache.curator.ensemble.EnsembleProvider;
import org.apache.curator.ensemble.exhibitor.DefaultExhibitorRestClient;
import org.apache.curator.ensemble.exhibitor.ExhibitorEnsembleProvider;
@ -33,13 +29,23 @@ import org.apache.curator.ensemble.exhibitor.Exhibitors;
import org.apache.curator.ensemble.fixed.FixedEnsembleProvider;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.CuratorFrameworkFactory.Builder;
import org.apache.curator.framework.api.ACLProvider;
import org.apache.curator.framework.imps.DefaultACLProvider;
import org.apache.curator.retry.BoundedExponentialBackoffRetry;
import org.apache.curator.shaded.com.google.common.base.Strings;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import java.util.List;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.Provides;
import io.druid.guice.JsonConfigProvider;
import io.druid.guice.LazySingleton;
import io.druid.java.util.common.StringUtils;
import io.druid.java.util.common.lifecycle.Lifecycle;
import io.druid.java.util.common.logger.Logger;
/**
*/
@ -70,15 +76,20 @@ public class CuratorModule implements Module
CuratorConfig config, EnsembleProvider ensembleProvider, Lifecycle lifecycle
)
{
final CuratorFramework framework =
CuratorFrameworkFactory.builder()
.ensembleProvider(ensembleProvider)
.sessionTimeoutMs(config.getZkSessionTimeoutMs())
.retryPolicy(new BoundedExponentialBackoffRetry(
BASE_SLEEP_TIME_MS, MAX_SLEEP_TIME_MS, MAX_RETRIES))
.compressionProvider(new PotentiallyGzippedCompressionProvider(config.getEnableCompression()))
.aclProvider(config.getEnableAcl() ? new SecuredACLProvider() : new DefaultACLProvider())
.build();
final Builder builder = CuratorFrameworkFactory.builder();
if (!Strings.isNullOrEmpty(config.getZkUser()) && !Strings.isNullOrEmpty(config.getZkPwd())) {
builder.authorization(
config.getAuthScheme(),
StringUtils.format("%s:%s", config.getZkUser(), config.getZkPwd()).getBytes(StandardCharsets.UTF_8)
);
}
final CuratorFramework framework = builder
.ensembleProvider(ensembleProvider)
.sessionTimeoutMs(config.getZkSessionTimeoutMs())
.retryPolicy(new BoundedExponentialBackoffRetry(BASE_SLEEP_TIME_MS, MAX_SLEEP_TIME_MS, MAX_RETRIES))
.compressionProvider(new PotentiallyGzippedCompressionProvider(config.getEnableCompression()))
.aclProvider(config.getEnableAcl() ? new SecuredACLProvider() : new DefaultACLProvider())
.build();
lifecycle.addHandler(
new Lifecycle.Handler()

View File

@ -19,10 +19,11 @@
package io.druid.curator;
import io.druid.guice.JsonConfigTesterBase;
import org.junit.Assert;
import org.junit.Test;
import io.druid.guice.JsonConfigTesterBase;
public class CuratorConfigTest extends JsonConfigTesterBase<CuratorConfig>
{
@Test
@ -30,10 +31,16 @@ public class CuratorConfigTest extends JsonConfigTesterBase<CuratorConfig>
{
propertyValues.put(getPropertyKey("host"), "fooHost");
propertyValues.put(getPropertyKey("acl"), "true");
propertyValues.put(getPropertyKey("user"), "test-zk-user");
propertyValues.put(getPropertyKey("pwd"), "test-zk-pwd");
propertyValues.put(getPropertyKey("authScheme"), "auth");
testProperties.putAll(propertyValues);
configProvider.inject(testProperties, configurator);
CuratorConfig config = configProvider.get().get();
Assert.assertEquals("fooHost", config.getZkHosts());
Assert.assertEquals(true, config.getEnableAcl());
Assert.assertEquals("test-zk-user", config.getZkUser());
Assert.assertEquals("test-zk-pwd", config.getZkPwd());
Assert.assertEquals("auth", config.getAuthScheme());
}
}