From 8b67a904d429eaf6c7f72a31d6e8f56cc7de961f Mon Sep 17 00:00:00 2001 From: JohnZZGithub Date: Thu, 23 May 2019 17:30:39 -0700 Subject: [PATCH] YARN-2774. support secure clusters in shared cache manager --- .../src/site/markdown/SecureMode.md | 21 +++++- .../hadoop/yarn/api/ClientSCMProtocolPB.java | 8 +++ .../hadoop/yarn/conf/YarnConfiguration.java | 19 +++++ .../yarn/server/api/SCMAdminProtocolPB.java | 4 ++ .../src/main/resources/yarn-default.xml | 39 ++++++++++ .../server/api/SCMUploaderProtocolPB.java | 8 +++ .../ClientProtocolService.java | 23 +++++- .../SCMAdminProtocolService.java | 24 ++++++- .../SharedCacheManager.java | 20 ++++++ .../SharedCacheUploaderService.java | 24 ++++++- .../security/SCMPolicyProvider.java | 71 +++++++++++++++++++ .../security/package-info.java | 19 +++++ .../TestClientSCMProtocolService.java | 32 ++++++++- .../TestSCMAdminProtocolService.java | 33 ++++++++- .../TestSharedCacheUploaderService.java | 35 ++++++++- 15 files changed, 368 insertions(+), 12 deletions(-) create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/security/SCMPolicyProvider.java create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/security/package-info.java diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/SecureMode.md b/hadoop-common-project/hadoop-common/src/site/markdown/SecureMode.md index 856861f29e3c2..0586454785875 100644 --- a/hadoop-common-project/hadoop-common/src/site/markdown/SecureMode.md +++ b/hadoop-common-project/hadoop-common/src/site/markdown/SecureMode.md @@ -42,7 +42,7 @@ It's recommended to have them share a Unix group, e.g. `hadoop`. See also "[Mapp | User:Group | Daemons | |:--------------|:----------------------------------------------------| | hdfs:hadoop | NameNode, Secondary NameNode, JournalNode, DataNode | -| yarn:hadoop | ResourceManager, NodeManager | +| yarn:hadoop | ResourceManager, NodeManager, SharedCacheManager | | mapred:hadoop | MapReduce JobHistory Server | ### Kerberos principals for Hadoop Daemons @@ -117,6 +117,18 @@ The NodeManager keytab file, on each host, should look like the following: 4 07/18/11 21:08:09 host/full.qualified.domain.name@REALM.TLD (AES-128 CTS mode with 96-bit SHA-1 HMAC) 4 07/18/11 21:08:09 host/full.qualified.domain.name@REALM.TLD (ArcFour with HMAC/md5) +The SharedCacheManager keytab file, on that host, should look like the following: + + $ klist -e -k -t /etc/security/keytab/scm.service.keytab + Keytab name: FILE:/etc/security/keytab/scm.service.keytab + KVNO Timestamp Principal + 4 07/18/11 21:08:09 scm/full.qualified.domain.name@REALM.TLD (AES-256 CTS mode with 96-bit SHA-1 HMAC) + 4 07/18/11 21:08:09 scm/full.qualified.domain.name@REALM.TLD (AES-128 CTS mode with 96-bit SHA-1 HMAC) + 4 07/18/11 21:08:09 scm/full.qualified.domain.name@REALM.TLD (ArcFour with HMAC/md5) + 4 07/18/11 21:08:09 host/full.qualified.domain.name@REALM.TLD (AES-256 CTS mode with 96-bit SHA-1 HMAC) + 4 07/18/11 21:08:09 host/full.qualified.domain.name@REALM.TLD (AES-128 CTS mode with 96-bit SHA-1 HMAC) + 4 07/18/11 21:08:09 host/full.qualified.domain.name@REALM.TLD (ArcFour with HMAC/md5) + #### MapReduce JobHistory Server The MapReduce JobHistory Server keytab file, on that host, should look like the following: @@ -333,6 +345,13 @@ The following settings allow configuring SSL access to the NameNode web UI (opti | `yarn.nodemanager.linux-container-executor.path` | `/path/to/bin/container-executor` | The path to the executable of Linux container executor. | | `yarn.nodemanager.webapp.https.address` | `0.0.0.0:8044` | The https adddress of the NM web application. | +### SharedCacheManager + +| Parameter | Value | Notes | +|:-----------------------------|:------------------------------------------|:----------------------------------------------------| +| `yarn.sharedcache.principal` | `scm/_HOST@REALM.TLD` | Kerberos principal name for the SharedCacheManager. | +| `yarn.sharedcache.keytab` | `/etc/security/keytab/scm.service.keytab` | Kerberos keytab file for the SharedCacheManager. | + ### Configuration for WebAppProxy The `WebAppProxy` provides a proxy between the web applications exported by an application and an end user. If security is enabled it will warn users before accessing a potentially unsafe web application. Authentication and authorization using the proxy is handled just like any other privileged web application. diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ClientSCMProtocolPB.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ClientSCMProtocolPB.java index b0a9fb5068022..91f5b43f8baea 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ClientSCMProtocolPB.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ClientSCMProtocolPB.java @@ -18,8 +18,16 @@ package org.apache.hadoop.yarn.api; import org.apache.hadoop.ipc.ProtocolInfo; +import org.apache.hadoop.security.KerberosInfo; +import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.proto.ClientSCMProtocol.ClientSCMProtocolService; +/** + * This is protocol interface used by shared cache client to interacte with + * shared cache manager. + */ +@KerberosInfo( + serverPrincipal = YarnConfiguration.SCM_PRINCIPAL) @ProtocolInfo(protocolName = "org.apache.hadoop.yarn.api.ClientSCMProtocolPB", protocolVersion = 1) public interface ClientSCMProtocolPB extends diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java index 6bbcdcb1e117b..d38aeb0d7848e 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java @@ -2425,6 +2425,18 @@ public static boolean isAclEnabled(Configuration conf) { YARN_SECURITY_SERVICE_AUTHORIZATION_APPLICATIONMASTER_NODEMANAGER_PROTOCOL = "security.applicationmaster-nodemanager.applicationmaster.protocol.acl"; + public static final String + YARN_SECURITY_SERVICE_AUTHORIZATION_SHAREDCACHEMANAGER_CLIENT_PROTOCOL = + "security.sharedcachemanager.client.protocol.acl"; + + public static final String + YARN_SECURITY_SERVICE_AUTHORIZATION_SHAREDCACHEMANAGER_ADMIN_PROTOCOL = + "security.sharedcachemanager.admin.protocol.acl"; + + public static final String + YARN_SECURITY_SERVICE_AUTHORIZATION_SHAREDCACHEMANAGER_UPLOADER_PROTOCOL = + "security.sharedcachemanager.uploader.protocol.acl"; + /** No. of milliseconds to wait between sending a SIGTERM and SIGKILL * to a running container */ public static final String NM_SLEEP_DELAY_BEFORE_SIGKILL_MS = @@ -3342,6 +3354,13 @@ public static boolean isAclEnabled(Configuration conf) { SHARED_CACHE_PREFIX + "nm.uploader.thread-count"; public static final int DEFAULT_SHARED_CACHE_NM_UPLOADER_THREAD_COUNT = 20; + /** The keytab for the shared cache manager.*/ + public static final String SCM_KEYTAB = + SHARED_CACHE_PREFIX + "keytab"; + + public static final String SCM_PRINCIPAL = + SHARED_CACHE_PREFIX + "principal"; + //////////////////////////////// // Federation Configs //////////////////////////////// diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/server/api/SCMAdminProtocolPB.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/server/api/SCMAdminProtocolPB.java index 93a2c67fb9cc3..46a020e4ef20c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/server/api/SCMAdminProtocolPB.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/server/api/SCMAdminProtocolPB.java @@ -20,10 +20,14 @@ import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; import org.apache.hadoop.ipc.ProtocolInfo; +import org.apache.hadoop.security.KerberosInfo; +import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.proto.SCMAdminProtocol.SCMAdminProtocolService; @Private @Unstable +@KerberosInfo( + serverPrincipal = YarnConfiguration.SCM_PRINCIPAL) @ProtocolInfo(protocolName = "org.apache.hadoop.yarn.server.api.SCMAdminProtocolPB", protocolVersion = 1) public interface SCMAdminProtocolPB extends diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml index 9741f6c36b1da..8ca6a6ee64bb9 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml @@ -2836,6 +2836,45 @@ 20 + + The Kerberos principal for the shared cache manager. + + yarn.sharedcache.principal + + + + + The Kerberos keytab for the shared cache manager. + + yarn.sharedcache.keytab + + + + + + ACL protocol used in shared cache manager to control client request. + + security.sharedcachemanager.client.protocol.acl + + + + + + ACL protocol used in shared cache manager for admin RPC request. + + security.sharedcachemanager.admin.protocol.acl + + + + + + ACL protocol used in shared cache manager for uploader requestion from + node manager. + + security.sharedcachemanager.uploader.protocol.acl + + + ACL protocol for use in the Timeline server. diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/SCMUploaderProtocolPB.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/SCMUploaderProtocolPB.java index 5099b7d667673..8a85951a8b6e2 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/SCMUploaderProtocolPB.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/SCMUploaderProtocolPB.java @@ -18,8 +18,16 @@ package org.apache.hadoop.yarn.server.api; import org.apache.hadoop.ipc.ProtocolInfo; +import org.apache.hadoop.security.KerberosInfo; +import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.proto.SCMUploaderProtocol.SCMUploaderProtocolService; +/** + * Protocol interface that provide uploading interface. The client should be + * node manager and the server is shared cache manager. + */ +@KerberosInfo( + serverPrincipal = YarnConfiguration.SCM_PRINCIPAL) @ProtocolInfo(protocolName = "org.apache.hadoop.yarn.server.api.SCMUploaderProtocolPB", protocolVersion = 1) public interface SCMUploaderProtocolPB extends diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/ClientProtocolService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/ClientProtocolService.java index 4275674aa4719..ace7f7752c7a2 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/ClientProtocolService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/ClientProtocolService.java @@ -21,12 +21,15 @@ import java.io.IOException; import java.net.InetSocketAddress; +import com.google.common.annotations.VisibleForTesting; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Evolving; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.fs.Path; import org.apache.hadoop.ipc.Server; import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authorize.PolicyProvider; import org.apache.hadoop.service.AbstractService; import org.apache.hadoop.yarn.api.ClientSCMProtocol; import org.apache.hadoop.yarn.api.protocolrecords.ReleaseSharedCacheResourceRequest; @@ -41,6 +44,7 @@ import org.apache.hadoop.yarn.ipc.YarnRPC; import org.apache.hadoop.yarn.server.sharedcache.SharedCacheUtil; import org.apache.hadoop.yarn.server.sharedcachemanager.metrics.ClientSCMMetrics; +import org.apache.hadoop.yarn.server.sharedcachemanager.security.SCMPolicyProvider; import org.apache.hadoop.yarn.server.sharedcachemanager.store.SCMStore; import org.apache.hadoop.yarn.server.sharedcachemanager.store.SharedCacheResourceReference; import org.slf4j.Logger; @@ -105,7 +109,13 @@ protected void serviceStart() throws Exception { conf.getInt(YarnConfiguration.SCM_CLIENT_SERVER_THREAD_COUNT, YarnConfiguration.DEFAULT_SCM_CLIENT_SERVER_THREAD_COUNT)); - // TODO (YARN-2774): Enable service authorization + // TODO: dynamically load ACLs + // Enable service authorization + if (conf.getBoolean( + CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION, + false)) { + refreshServiceAcls(conf, SCMPolicyProvider.getInstance()); + } this.server.start(); clientBindAddress = @@ -115,6 +125,12 @@ protected void serviceStart() throws Exception { super.serviceStart(); } + private void refreshServiceAcls(Configuration configuration, + PolicyProvider policyProvider) { + this.server.refreshServiceAclWithLoadedConfiguration(configuration, + policyProvider); + } + @Override protected void serviceStop() throws Exception { if (this.server != null) { @@ -190,4 +206,9 @@ private String getCacheEntryFilePath(String checksum, String filename) { return SharedCacheUtil.getCacheEntryPath(this.cacheDepth, this.cacheRoot, checksum) + Path.SEPARATOR_CHAR + filename; } + + @VisibleForTesting + protected Server getServer() { + return server; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SCMAdminProtocolService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SCMAdminProtocolService.java index e6a885bff5ed2..7887f928ba88e 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SCMAdminProtocolService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SCMAdminProtocolService.java @@ -21,12 +21,15 @@ import java.io.IOException; import java.net.InetSocketAddress; +import com.google.common.annotations.VisibleForTesting; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.ipc.Server; import org.apache.hadoop.security.AccessControlException; import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authorize.PolicyProvider; import org.apache.hadoop.service.AbstractService; import org.apache.hadoop.yarn.security.YarnAuthorizationProvider; import org.apache.hadoop.yarn.server.api.SCMAdminProtocol; @@ -38,6 +41,7 @@ import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; import org.apache.hadoop.yarn.ipc.RPCUtil; import org.apache.hadoop.yarn.ipc.YarnRPC; +import org.apache.hadoop.yarn.server.sharedcachemanager.security.SCMPolicyProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,7 +93,14 @@ protected void serviceStart() throws Exception { conf.getInt(YarnConfiguration.SCM_ADMIN_CLIENT_THREAD_COUNT, YarnConfiguration.DEFAULT_SCM_ADMIN_CLIENT_THREAD_COUNT)); - // TODO: Enable service authorization (see YARN-2774) + // TODO: dynamically load ACLs + // Enable service authorization + if (conf.getBoolean( + CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION, + false)) { + refreshServiceAcls( + conf, SCMPolicyProvider.getInstance()); + } this.server.start(); clientBindAddress = @@ -99,6 +110,12 @@ protected void serviceStart() throws Exception { super.serviceStart(); } + private void refreshServiceAcls(Configuration configuration, + PolicyProvider policyProvider) { + this.server.refreshServiceAclWithLoadedConfiguration(configuration, + policyProvider); + } + @Override protected void serviceStop() throws Exception { if (this.server != null) { @@ -141,4 +158,9 @@ public RunSharedCacheCleanerTaskResponse runCleanerTask( response.setAccepted(true); return response; } + + @VisibleForTesting + public Server getServer() { + return server; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SharedCacheManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SharedCacheManager.java index ca683f231bd38..5307a15637b8c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SharedCacheManager.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SharedCacheManager.java @@ -18,11 +18,15 @@ package org.apache.hadoop.yarn.server.sharedcachemanager; +import java.io.IOException; +import java.net.InetSocketAddress; + import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; import org.apache.hadoop.metrics2.source.JvmMetrics; +import org.apache.hadoop.security.SecurityUtil; import org.apache.hadoop.service.CompositeService; import org.apache.hadoop.util.ReflectionUtils; import org.apache.hadoop.util.ShutdownHookManager; @@ -63,6 +67,13 @@ public SharedCacheManager() { @Override protected void serviceInit(Configuration conf) throws Exception { + try { + doSecureLogin(conf); + } catch(IOException ie) { + throw new YarnRuntimeException( + "Shared cache manager failed to login", ie); + } + this.store = createSCMStoreService(conf); addService(store); @@ -130,6 +141,15 @@ private SCMWebServer createSCMWebServer(SharedCacheManager scm) { return new SCMWebServer(scm); } + protected void doSecureLogin(Configuration conf) throws IOException { + InetSocketAddress socAddr = conf.getSocketAddr( + YarnConfiguration.SCM_ADMIN_ADDRESS, + YarnConfiguration.DEFAULT_SCM_ADMIN_ADDRESS, + YarnConfiguration.DEFAULT_SCM_ADMIN_PORT); + SecurityUtil.login(conf, YarnConfiguration.SCM_KEYTAB, + YarnConfiguration.SCM_PRINCIPAL, socAddr.getHostName()); + } + @Override protected void serviceStop() throws Exception { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SharedCacheUploaderService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SharedCacheUploaderService.java index dd87b679cb4f0..57fe70774d08f 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SharedCacheUploaderService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/SharedCacheUploaderService.java @@ -21,8 +21,11 @@ import java.io.IOException; import java.net.InetSocketAddress; +import com.google.common.annotations.VisibleForTesting; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.ipc.Server; +import org.apache.hadoop.security.authorize.PolicyProvider; import org.apache.hadoop.service.AbstractService; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.exceptions.YarnException; @@ -35,6 +38,7 @@ import org.apache.hadoop.yarn.server.api.protocolrecords.SCMUploaderNotifyRequest; import org.apache.hadoop.yarn.server.api.protocolrecords.SCMUploaderNotifyResponse; import org.apache.hadoop.yarn.server.sharedcachemanager.metrics.SharedCacheUploaderMetrics; +import org.apache.hadoop.yarn.server.sharedcachemanager.security.SCMPolicyProvider; import org.apache.hadoop.yarn.server.sharedcachemanager.store.SCMStore; /** @@ -81,7 +85,14 @@ protected void serviceStart() throws Exception { conf.getInt(YarnConfiguration.SCM_UPLOADER_SERVER_THREAD_COUNT, YarnConfiguration.DEFAULT_SCM_UPLOADER_SERVER_THREAD_COUNT)); - // TODO (YARN-2774): Enable service authorization + // TODO: dynamically load ACLs + // Enable service authorization + if (conf.getBoolean( + CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION, + false)) { + refreshServiceAcls( + conf, SCMPolicyProvider.getInstance()); + } this.server.start(); bindAddress = @@ -91,6 +102,12 @@ protected void serviceStart() throws Exception { super.serviceStart(); } + private void refreshServiceAcls(Configuration configuration, + PolicyProvider policyProvider) { + this.server.refreshServiceAclWithLoadedConfiguration(configuration, + policyProvider); + } + @Override protected void serviceStop() throws Exception { if (this.server != null) { @@ -137,4 +154,9 @@ public SCMUploaderCanUploadResponse canUpload( response.setUploadable(true); return response; } + + @VisibleForTesting + protected Server getServer() { + return server; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/security/SCMPolicyProvider.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/security/SCMPolicyProvider.java new file mode 100644 index 0000000000000..90472c1289a65 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/security/SCMPolicyProvider.java @@ -0,0 +1,71 @@ +/** + * 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.hadoop.yarn.server.sharedcachemanager.security; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.security.authorize.PolicyProvider; +import org.apache.hadoop.security.authorize.Service; +import org.apache.hadoop.yarn.api.ClientSCMProtocolPB; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.server.api.SCMAdminProtocolPB; +import org.apache.hadoop.yarn.server.api.SCMUploaderProtocolPB; + + +/** + * {@link PolicyProvider} for shared cache manager protocols. + */ +@InterfaceAudience.Private +@InterfaceStability.Unstable +public class SCMPolicyProvider extends PolicyProvider { + + private static SCMPolicyProvider scmPolicyProvider = + new SCMPolicyProvider(); + + @InterfaceAudience.Private + @InterfaceStability.Unstable + public static SCMPolicyProvider getInstance() { + return scmPolicyProvider; + } + + private static final Service[] SCM_SERVICES = new Service[] { + new Service(YarnConfiguration. + YARN_SECURITY_SERVICE_AUTHORIZATION_SHAREDCACHEMANAGER_CLIENT_PROTOCOL, + ClientSCMProtocolPB.class), + new Service(YarnConfiguration. + YARN_SECURITY_SERVICE_AUTHORIZATION_SHAREDCACHEMANAGER_ADMIN_PROTOCOL, + SCMAdminProtocolPB.class), + new Service(YarnConfiguration. + YARN_SECURITY_SERVICE_AUTHORIZATION_SHAREDCACHEMANAGER_UPLOADER_PROTOCOL, + SCMUploaderProtocolPB.class), + }; + + @Override + public Service[] getServices() { + return copyServiceArray(SCM_SERVICES); + } + + private Service[] copyServiceArray(Service[] services) { + Service[] res = new Service[services.length]; + for (int i = 0; i < res.length; ++i) { + res[i] = new Service( + services[i].getServiceKey(), services[i].getProtocol()); + } + return res; + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/security/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/security/package-info.java new file mode 100644 index 0000000000000..142f50bd7174c --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/main/java/org/apache/hadoop/yarn/server/sharedcachemanager/security/package-info.java @@ -0,0 +1,19 @@ +/* + * 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. + */ +/** + * This package contains security related classes for shared cache manager. + */ +package org.apache.hadoop.yarn.server.sharedcachemanager.security; \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestClientSCMProtocolService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestClientSCMProtocolService.java index ca4bdce7cf19d..d16b607010e48 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestClientSCMProtocolService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestClientSCMProtocolService.java @@ -18,9 +18,8 @@ package org.apache.hadoop.yarn.server.sharedcachemanager; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION; +import static org.junit.Assert.*; import static org.mockito.Mockito.spy; import java.io.File; @@ -29,8 +28,12 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; +import org.apache.hadoop.ipc.Server; import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authorize.AccessControlList; +import org.apache.hadoop.security.authorize.ServiceAuthorizationManager; import org.apache.hadoop.yarn.api.ClientSCMProtocol; +import org.apache.hadoop.yarn.api.ClientSCMProtocolPB; import org.apache.hadoop.yarn.api.protocolrecords.ReleaseSharedCacheResourceRequest; import org.apache.hadoop.yarn.api.protocolrecords.UseSharedCacheResourceRequest; import org.apache.hadoop.yarn.api.records.ApplicationId; @@ -84,6 +87,11 @@ public void startUp() { conf.set(YarnConfiguration.SCM_STORE_CLASS, InMemorySCMStore.class.getName()); conf.set(YarnConfiguration.SHARED_CACHE_ROOT, testDir.getPath()); + conf.set(HADOOP_SECURITY_AUTHORIZATION, Boolean.toString(true)); + startInternal(conf); + } + + private void startInternal(Configuration conf) { AppChecker appChecker = spy(new DummyAppChecker()); store = new InMemorySCMStore(appChecker); store.init(conf); @@ -107,6 +115,10 @@ public void startUp() { @After public void cleanUp() { + stopInternal(); + } + + private void stopInternal() { if (store != null) { store.stop(); store = null; @@ -123,6 +135,20 @@ public void cleanUp() { } } + @Test + public void testSecurityAuthorization() { + Server server = service.getServer(); + ServiceAuthorizationManager serviceAuthorizationManager = + server.getServiceAuthorizationManager(); + AccessControlList aclList = + serviceAuthorizationManager.getProtocolsAcls(ClientSCMProtocolPB.class); + assertTrue("ClientSCMProtocolPB is null!", aclList != null); + assertTrue( + "ACL List is not all allowed by default", aclList.isAllAllowed()); + assertTrue( + "ACL List is not * by default", aclList.getAclString().equals("*")); + } + @Test public void testUse_MissingEntry() throws Exception { long misses = ClientSCMMetrics.getInstance().getCacheMisses(); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestSCMAdminProtocolService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestSCMAdminProtocolService.java index e183ffa5cfba1..2a2a4a259b5cc 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestSCMAdminProtocolService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestSCMAdminProtocolService.java @@ -18,7 +18,9 @@ package org.apache.hadoop.yarn.server.sharedcachemanager; +import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.mock; @@ -33,7 +35,11 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; +import org.apache.hadoop.ipc.Server; +import org.apache.hadoop.security.authorize.AccessControlList; +import org.apache.hadoop.security.authorize.ServiceAuthorizationManager; import org.apache.hadoop.yarn.server.api.SCMAdminProtocol; +import org.apache.hadoop.yarn.server.api.SCMAdminProtocolPB; import org.apache.hadoop.yarn.server.api.protocolrecords.RunSharedCacheCleanerTaskRequest; import org.apache.hadoop.yarn.server.api.protocolrecords.RunSharedCacheCleanerTaskResponse; import org.apache.hadoop.yarn.server.api.protocolrecords.impl.pb.RunSharedCacheCleanerTaskResponsePBImpl; @@ -45,10 +51,10 @@ import org.apache.hadoop.yarn.server.sharedcachemanager.store.InMemorySCMStore; import org.apache.hadoop.yarn.server.sharedcachemanager.store.SCMStore; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; + /** * Basic unit tests for the SCM Admin Protocol Service and SCMAdmin. */ @@ -68,7 +74,11 @@ public void startUp() { Configuration conf = new Configuration(); conf.set(YarnConfiguration.SCM_STORE_CLASS, InMemorySCMStore.class.getName()); + conf.set(HADOOP_SECURITY_AUTHORIZATION, Boolean.toString(true)); + startInternal(conf); + } + private void startInternal(Configuration conf) { cleaner = mock(CleanerService.class); service = spy(new SCMAdminProtocolService(cleaner)); @@ -97,6 +107,10 @@ protected SCMAdminProtocol createSCMAdminProtocol() throws IOException { @After public void cleanUpTest() { + stopInternal(); + } + + private void stopInternal() { if (service != null) { service.stop(); } @@ -112,7 +126,7 @@ public void testRunCleanerTask() throws Exception { RunSharedCacheCleanerTaskRequest request = recordFactory.newRecordInstance(RunSharedCacheCleanerTaskRequest.class); RunSharedCacheCleanerTaskResponse response = SCMAdminProxy.runCleanerTask(request); - Assert.assertTrue("cleaner task request isn't accepted", response.getAccepted()); + assertTrue("cleaner task request isn't accepted", response.getAccepted()); verify(service, times(1)).runCleanerTask(any(RunSharedCacheCleanerTaskRequest.class)); } @@ -132,4 +146,19 @@ public void testRunCleanerTaskCLI() throws Exception { verify(mockAdmin, times(2)).runCleanerTask( any(RunSharedCacheCleanerTaskRequest.class)); } + + @Test + public void testSecurityAuthorization() { + Server server = service.getServer(); + ServiceAuthorizationManager serviceAuthorizationManager = + server.getServiceAuthorizationManager(); + AccessControlList aclList = serviceAuthorizationManager.getProtocolsAcls( + SCMAdminProtocolPB.class); + assertTrue( + "SCMAdminProtocolPB is null!", aclList != null); + assertTrue( + "ACL List is not all allowed by default", aclList.isAllAllowed()); + assertTrue( + "ACL List is not * by default", aclList.getAclString().equals("*")); + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestSharedCacheUploaderService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestSharedCacheUploaderService.java index 048523e8457d4..7fb25aa7aaa78 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestSharedCacheUploaderService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-sharedcachemanager/src/test/java/org/apache/hadoop/yarn/server/sharedcachemanager/TestSharedCacheUploaderService.java @@ -18,6 +18,7 @@ package org.apache.hadoop.yarn.server.sharedcachemanager; +import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -31,11 +32,15 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; +import org.apache.hadoop.ipc.Server; +import org.apache.hadoop.security.authorize.AccessControlList; +import org.apache.hadoop.security.authorize.ServiceAuthorizationManager; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; import org.apache.hadoop.yarn.ipc.YarnRPC; import org.apache.hadoop.yarn.server.api.SCMUploaderProtocol; +import org.apache.hadoop.yarn.server.api.SCMUploaderProtocolPB; import org.apache.hadoop.yarn.server.api.protocolrecords.SCMUploaderNotifyRequest; import org.apache.hadoop.yarn.server.sharedcachemanager.metrics.SharedCacheUploaderMetrics; import org.apache.hadoop.yarn.server.sharedcachemanager.store.InMemorySCMStore; @@ -73,8 +78,8 @@ public static void cleanupTestDirs() throws IOException { private SharedCacheUploaderService service; private SCMUploaderProtocol proxy; private SCMStore store; - private final RecordFactory recordFactory = RecordFactoryProvider - .getRecordFactory(null); + private final RecordFactory recordFactory = + RecordFactoryProvider.getRecordFactory(null); @Before public void startUp() { @@ -82,6 +87,11 @@ public void startUp() { conf.set(YarnConfiguration.SCM_STORE_CLASS, InMemorySCMStore.class.getName()); conf.set(YarnConfiguration.SHARED_CACHE_ROOT, testDir.getPath()); + conf.set(HADOOP_SECURITY_AUTHORIZATION, Boolean.toString(true)); + startInternal(conf); + } + + private void startInternal(Configuration conf) { AppChecker appChecker = spy(new DummyAppChecker()); store = new InMemorySCMStore(appChecker); store.init(conf); @@ -97,14 +107,18 @@ public void startUp() { conf.getSocketAddr(YarnConfiguration.SCM_UPLOADER_SERVER_ADDRESS, YarnConfiguration.DEFAULT_SCM_UPLOADER_SERVER_ADDRESS, YarnConfiguration.DEFAULT_SCM_UPLOADER_SERVER_PORT); - proxy = (SCMUploaderProtocol) rpc.getProxy( SCMUploaderProtocol.class, scmAddress, conf); + } @After public void cleanUp() { + stopInternal(); + } + + private void stopInternal() { if (store != null) { store.stop(); } @@ -185,4 +199,19 @@ public void testNotify_entryExists_sameName() throws Exception { accepted); } + + @Test + public void testSecurityAuthorization() { + Server server = service.getServer(); + ServiceAuthorizationManager serviceAuthorizationManager = + server.getServiceAuthorizationManager(); + AccessControlList aclList = serviceAuthorizationManager.getProtocolsAcls( + SCMUploaderProtocolPB.class); + assertTrue( + "SCMUploaderProtocolPB is null!", aclList != null); + assertTrue( + "ACL List is not all allowed by default", aclList.isAllAllowed()); + assertTrue( + "ACL List is not * by default", aclList.getAclString().equals("*")); + } }