From e17c5946b29e86a0af7937cfbdef45023838e2d0 Mon Sep 17 00:00:00 2001 From: karthik Date: Tue, 20 Jun 2017 10:45:27 -0700 Subject: [PATCH] DRILL 5671 - Set secure ACLs (Access Control List) for Drill ZK nodes in a secure cluster --- .../org/apache/drill/exec/ExecConstants.java | 1 + .../exec/coord/zk/ZKACLProviderFactory.java | 44 ++++++++++ .../exec/coord/zk/ZKClusterCoordinator.java | 4 + .../exec/coord/zk/ZKSecureACLProvider.java | 80 +++++++++++++++++++ .../src/main/resources/drill-module.conf | 3 +- 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKACLProviderFactory.java create mode 100644 exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKSecureACLProvider.java diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java b/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java index 5b82d1f713e..3ec72b282c0 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java @@ -39,6 +39,7 @@ public interface ExecConstants { String ZK_TIMEOUT = "drill.exec.zk.timeout"; String ZK_ROOT = "drill.exec.zk.root"; String ZK_REFRESH = "drill.exec.zk.refresh"; + String ZK_SECURE_ACL = "drill.exec.zk.use.secure_acl"; String BIT_RETRY_TIMES = "drill.exec.rpc.bit.server.retry.count"; String BIT_RETRY_DELAY = "drill.exec.rpc.bit.server.retry.delay"; String BIT_TIMEOUT = "drill.exec.bit.timeout" ; diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKACLProviderFactory.java b/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKACLProviderFactory.java new file mode 100644 index 00000000000..cfd849e7947 --- /dev/null +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKACLProviderFactory.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.drill.exec.coord.zk; + +import org.apache.curator.framework.api.ACLProvider; +import org.apache.curator.framework.imps.DefaultACLProvider; +import org.apache.drill.common.config.DrillConfig; +import org.apache.drill.exec.ExecConstants; + + +public class ZKACLProviderFactory { + + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ZKACLProviderFactory.class); + + public static ACLProvider getACLProvider(DrillConfig config, String clusterId, String zkRoot) { + if (config.getBoolean(ExecConstants.ZK_SECURE_ACL)) { + if (config.getBoolean(ExecConstants.USER_AUTHENTICATION_ENABLED)){ + logger.trace("ZKACLProviderFactory: Using secure ZK ACL"); + return new ZKSecureACLProvider(clusterId, zkRoot); + } else { + logger.warn("ZKACLProviderFactory : Secure ZK ACL enabled but user authentication is disabled." + + " User authentication is required for secure ZK ACL. Using default un-secure ACL."); + } + } + logger.trace("ZKACLProviderFactory: Using un-secure default ZK ACL"); + return new DefaultACLProvider(); + } +} diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKClusterCoordinator.java b/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKClusterCoordinator.java index b14a1512c20..282946b1c60 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKClusterCoordinator.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKClusterCoordinator.java @@ -35,6 +35,8 @@ import org.apache.curator.RetryPolicy; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.api.ACLProvider; +import org.apache.curator.framework.imps.DefaultACLProvider; import org.apache.curator.framework.state.ConnectionState; import org.apache.curator.framework.state.ConnectionStateListener; import org.apache.curator.retry.RetryNTimes; @@ -94,6 +96,7 @@ public ZKClusterCoordinator(DrillConfig config, String connect) throws IOExcepti logger.debug("Connect {}, zkRoot {}, clusterId: " + clusterId, connect, zkRoot); this.serviceName = clusterId; + ACLProvider aclProvider = ZKACLProviderFactory.getACLProvider(config, clusterId, zkRoot); RetryPolicy rp = new RetryNTimes(config.getInt(ExecConstants.ZK_RETRY_TIMES), config.getInt(ExecConstants.ZK_RETRY_DELAY)); curator = CuratorFrameworkFactory.builder() @@ -101,6 +104,7 @@ public ZKClusterCoordinator(DrillConfig config, String connect) throws IOExcepti .connectionTimeoutMs(config.getInt(ExecConstants.ZK_TIMEOUT)) .retryPolicy(rp) .connectString(connect) + .aclProvider(aclProvider) .build(); curator.getConnectionStateListenable().addListener(new InitialConnectionListener()); curator.start(); diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKSecureACLProvider.java b/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKSecureACLProvider.java new file mode 100644 index 00000000000..c20426982dc --- /dev/null +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/coord/zk/ZKSecureACLProvider.java @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.drill.exec.coord.zk; + +import com.google.common.collect.ImmutableList; +import org.apache.curator.framework.api.ACLProvider; +import org.apache.zookeeper.ZooDefs.Ids; +import org.apache.zookeeper.data.ACL; + +import java.util.List; + +/** + * ZKSecureACLProvider restricts access to znodes created by Drill in a secure installation. + * + * The cluster discovery znode i.e. the znode containing the list of Drillbits is + * readable by anyone. + * + * For all other znodes, only the creator of the znode, i.e the Drillbit user, has full access. + * + */ + +public class ZKSecureACLProvider implements ACLProvider { + + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ZKSecureACLProvider.class); + + /** + * DEFAULT_ACL gives the creator of a znode full-access to it + */ + static ImmutableList DEFAULT_ACL = new ImmutableList.Builder() + .addAll(Ids.CREATOR_ALL_ACL.iterator()) + .build(); + /** + * DRILL_CLUSTER_ACL gives the creator full access and everyone else only read access. + * Used on the Drillbit discovery znode (znode path //) + * i.e. the node that contains the list of Drillbits in the cluster. + */ + static ImmutableList DRILL_CLUSTER_ACL = new ImmutableList.Builder() + .addAll(Ids.READ_ACL_UNSAFE.iterator()) + .addAll(Ids.CREATOR_ALL_ACL.iterator()) + .build(); + final String clusterName; + final String drillZkRoot; + final String drillClusterPath; + + public ZKSecureACLProvider(String clusterName, String drillZKRoot) { + this.clusterName = clusterName; + this.drillZkRoot = drillZKRoot; + this.drillClusterPath = "/" + this.drillZkRoot + "/" + this.clusterName ; + } + + public List getDefaultAcl() { + return DEFAULT_ACL; + } + + public List getAclForPath(String path) { + logger.trace("ZKSecureACLProvider: getAclForPath " + path); + if(path.equals(drillClusterPath)) { + logger.trace("ZKSecureACLProvider: getAclForPath drillClusterPath " + drillClusterPath); + return DRILL_CLUSTER_ACL; + } + return DEFAULT_ACL; + } + +} diff --git a/exec/java-exec/src/main/resources/drill-module.conf b/exec/java-exec/src/main/resources/drill-module.conf index 146df1f4a03..ca3c5ada9e7 100644 --- a/exec/java-exec/src/main/resources/drill-module.conf +++ b/exec/java-exec/src/main/resources/drill-module.conf @@ -112,7 +112,8 @@ drill.exec: { retry: { count: 7200, delay: 500 - } + }, + use.secure_acl: false }, http: { enabled: true,