diff --git hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java index c7cada8..4746b0c 100644 --- hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java +++ hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java @@ -447,10 +447,19 @@ public RpcDetailedMetrics getRpcDetailedMetrics() { * Refresh the service authorization ACL for the service handled by this server. */ public void refreshServiceAcl(Configuration conf, PolicyProvider provider) { - serviceAuthorizationManager.refresh(conf, provider); + serviceAuthorizationManager.refresh(conf, provider, false); } /** + * Refresh the service authorization ACL for the service handled by this + * server. If useRemoteConfiguration is set as true, refresh the service using + * the remoteConfiguration + */ + public void refreshServiceAcl(Configuration conf, PolicyProvider provider, + boolean useRemoteConfiguration) { + serviceAuthorizationManager.refresh(conf, provider, useRemoteConfiguration); + } + /** * Returns a handle to the serviceAuthorizationManager (required in tests) * @return instance of ServiceAuthorizationManager for this server */ diff --git hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authorize/ServiceAuthorizationManager.java hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authorize/ServiceAuthorizationManager.java index 8523f38..bce58a2 100644 --- hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authorize/ServiceAuthorizationManager.java +++ hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authorize/ServiceAuthorizationManager.java @@ -112,15 +112,16 @@ public void authorize(UserGroupInformation user, } public synchronized void refresh(Configuration conf, - PolicyProvider provider) { + PolicyProvider provider, boolean useRemoteConfiguration) { // Get the system property 'hadoop.policy.file' String policyFile = System.getProperty("hadoop.policy.file", HADOOP_POLICY_FILE); // Make a copy of the original config, and load the policy file Configuration policyConf = new Configuration(conf); - policyConf.addResource(policyFile); - + if (! useRemoteConfiguration) { + policyConf.addResource(policyFile); + } final Map, AccessControlList> newAcls = new IdentityHashMap, AccessControlList>(); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java index 0bd893a..ddf9220 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java @@ -38,6 +38,8 @@ public class YarnConfiguration extends Configuration { public static final String CS_CONFIGURATION_FILE= "capacity-scheduler.xml"; + public static final String HADOOP_POLICY_CONFIGURATION_FILE = + "hadoop-policy.xml"; private static final String YARN_DEFAULT_XML_FILE = "yarn-default.xml"; private static final String YARN_SITE_XML_FILE = "yarn-site.xml"; diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/TestRMFailover.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/TestRMFailover.java index b568c25..5935340 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/TestRMFailover.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/TestRMFailover.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; +import java.security.PrivilegedExceptionAction; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -39,19 +40,29 @@ import org.apache.hadoop.ha.ClientBaseWithFixes; import org.apache.hadoop.ha.HAServiceProtocol; import org.apache.hadoop.ha.proto.HAServiceProtocolProtos; +import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.service.Service.STATE; +import org.apache.hadoop.yarn.api.ApplicationClientProtocol; +import org.apache.hadoop.yarn.api.protocolrecords.GetNewApplicationRequest; +import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationRequest; import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext; +import org.apache.hadoop.yarn.api.records.ContainerLaunchContext; +import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.client.api.YarnClient; import org.apache.hadoop.yarn.conf.HAUtil; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.exceptions.ApplicationNotFoundException; import org.apache.hadoop.yarn.exceptions.YarnException; +import org.apache.hadoop.yarn.ipc.YarnRPC; import org.apache.hadoop.yarn.server.MiniYARNCluster; import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshQueuesRequest; +import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshServiceAclsRequest; import org.apache.hadoop.yarn.server.resourcemanager.AdminService; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacitySchedulerConfiguration; import org.apache.hadoop.yarn.server.webproxy.WebAppProxyServer; +import org.apache.hadoop.yarn.util.Records; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -337,6 +348,77 @@ public void testAdminRefreshQueuesWithRemoteConfigurationSwitchOn() Assert.assertEquals(maxAppsAfter, 5000); Assert.assertTrue(maxAppsAfter != maxAppsBefore); } + + @Test + public void testServiceAclsRefreshOnHAWithRemoteConfigurationSwitchOff() + throws IOException { + Configuration.addDefaultResource("config-with-security.xml"); + Configuration confWithSecurity = new YarnConfiguration(conf); + cluster.init(confWithSecurity); + cluster.start(); + getAdminService(0).transitionToActive(req); + assertFalse("RM never turned active", -1 == cluster.getActiveRMIndex()); + + // clean the remoteDirectory + cleanRemoteDirectory(); + + try { + getAdminService(0).refreshServiceAcls( + RefreshServiceAclsRequest.newInstance()); + } catch (Exception ex) { + fail("The HA is enabled, but RM_HA_REMOTE_CONFIGURATION_ENABLED" + + " is set as false. Should not get any exception" + ex.getMessage()); + } + } + + @Test + public void testServiceAclsRefreshOnHAWithRemoteConfigurationSwitchOn() + throws IOException, YarnException, InterruptedException { + // switch RM_HA_REMOTE_CONFIGURATION_ENABLED to true + conf.setBoolean(YarnConfiguration.RM_HA_REMOTE_CONFIGURATION_ENABLED, true); + Configuration.addDefaultResource("config-with-security.xml"); + Configuration confWithSecurity = new YarnConfiguration(conf); + cluster.init(confWithSecurity); + cluster.start(); + getAdminService(0).transitionToActive(req); + assertFalse("RM never turned active", -1 == cluster.getActiveRMIndex()); + + // clean the remoteDirectory + cleanRemoteDirectory(); + + RefreshServiceAclsRequest request = RefreshServiceAclsRequest.newInstance(); + try { + getAdminService(0).refreshServiceAcls(request); + fail("The HA is enabled. The remote configuration has not been set." + + " Should get an exception here"); + } catch (Exception ex) { + Assert.assertTrue(ex.getMessage().contains( + "Can not find Configuration: hadoop-policy.xml")); + } + + Configuration conf = new Configuration(); + conf.set("security.applicationclient.protocol.acl", "alice,bob users,wheel"); + String hadoopConfFile = writeConfigurationXML(conf, "hadoop-policy.xml"); + + // upload the file into Remote File System + uploadToRemoteFileSystem(new Path(hadoopConfFile)); + + getAdminService(0).refreshServiceAcls(request); + + try { + submitApplicationByUser("tester"); + fail("Submit Application by user tester should fail"); + } catch (Exception ex) { + // Expected + } + + try { + submitApplicationByUser("alice"); + } catch (Exception ex) { + fail("Submit Application by user alice should not fail"); + } + } + private String writeConfigurationXML(Configuration conf, String confXMLName) throws IOException { DataOutputStream output = null; @@ -375,4 +457,38 @@ private void cleanRemoteDirectory() throws IOException { } } } + + private void submitApplicationByUser(String user) throws Exception { + ApplicationClientProtocol rmClient; + final YarnRPC rpc = YarnRPC.create(conf); + UserGroupInformation owner = UserGroupInformation + .createRemoteUser(user); + rmClient = + owner.doAs(new PrivilegedExceptionAction() { + + @Override + public ApplicationClientProtocol run() throws Exception { + return (ApplicationClientProtocol) rpc.getProxy( + ApplicationClientProtocol.class, + cluster.getConfig().getSocketAddr( + YarnConfiguration.RM_ADDRESS, + YarnConfiguration.DEFAULT_RM_ADDRESS, + YarnConfiguration.DEFAULT_RM_PORT), cluster.getConfig()); + } + }); + ApplicationId applicationId = rmClient.getNewApplication( + GetNewApplicationRequest.newInstance()).getApplicationId(); + ApplicationSubmissionContext appContext = + Records.newRecord(ApplicationSubmissionContext.class); + appContext.setApplicationId(applicationId); + ContainerLaunchContext amContainer = + Records.newRecord(ContainerLaunchContext.class); + appContext.setAMContainerSpec(amContainer); + Resource capability = Records.newRecord(Resource.class); + capability.setMemory(10); + capability.setVirtualCores(1); + appContext.setResource(capability); + rmClient + .submitApplication(SubmitApplicationRequest.newInstance(appContext)); + } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/AdminService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/AdminService.java index 10d6856..f389ae7 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/AdminService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/AdminService.java @@ -92,6 +92,7 @@ private AccessControlList adminAcl; private RemoteConfiguration remoteConfiguration = null; + private boolean remoteConfigurationEnabled = false; private final RecordFactory recordFactory = @@ -161,7 +162,8 @@ protected void startServer() throws Exception { if (conf.getBoolean( CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION, false)) { - refreshServiceAcls(conf, new RMPolicyProvider()); + refreshServiceAcls(conf, new RMPolicyProvider(), + this.rmContext.isHAEnabled() && this.remoteConfigurationEnabled); } if (rmContext.isHAEnabled()) { @@ -427,9 +429,9 @@ public RefreshAdminAclsResponse refreshAdminAcls( @Override public RefreshServiceAclsResponse refreshServiceAcls( - RefreshServiceAclsRequest request) throws YarnException { - Configuration conf = new Configuration(); - if (!conf.getBoolean( + RefreshServiceAclsRequest request) throws YarnException, IOException { + String argName = "refreshServiceAcls"; + if (!getConfig().getBoolean( CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION, false)) { throw RPCUtil.getRemoteException( @@ -438,26 +440,43 @@ public RefreshServiceAclsResponse refreshServiceAcls( ") not enabled.")); } - PolicyProvider policyProvider = new RMPolicyProvider(); - - refreshServiceAcls(conf, policyProvider); - if (isRMActive()) { - rmContext.getClientRMService().refreshServiceAcls(conf, policyProvider); - rmContext.getApplicationMasterService().refreshServiceAcls( - conf, policyProvider); - rmContext.getResourceTrackerService().refreshServiceAcls( - conf, policyProvider); - } else { - LOG.warn("ResourceManager is not active. Not refreshing ACLs for " + - "Clients, ApplicationMasters and NodeManagers"); + if (!isRMActive()) { + RMAuditLogger.logFailure(UserGroupInformation.getCurrentUser() + .getShortUserName(), argName, + adminAcl.toString(), "AdminService", + "ResourceManager is not active. Can not refresh Service ACLs."); + throwStandbyException(); } - - return recordFactory.newRecordInstance(RefreshServiceAclsResponse.class); + + PolicyProvider policyProvider = new RMPolicyProvider(); + RefreshServiceAclsResponse response = recordFactory + .newRecordInstance(RefreshServiceAclsResponse.class); + Configuration conf = + getConfiguration(YarnConfiguration.HADOOP_POLICY_CONFIGURATION_FILE); + refreshServiceAcls(conf, policyProvider, this.rmContext.isHAEnabled() + && remoteConfigurationEnabled); + rmContext.getClientRMService().refreshServiceAcls( + getConfiguration(YarnConfiguration.HADOOP_POLICY_CONFIGURATION_FILE), + policyProvider, + this.rmContext.isHAEnabled() && remoteConfigurationEnabled); + rmContext.getApplicationMasterService().refreshServiceAcls( + getConfiguration(YarnConfiguration.HADOOP_POLICY_CONFIGURATION_FILE), + policyProvider, + this.rmContext.isHAEnabled() && remoteConfigurationEnabled); + rmContext.getResourceTrackerService().refreshServiceAcls( + getConfiguration(YarnConfiguration.HADOOP_POLICY_CONFIGURATION_FILE), + policyProvider, + this.rmContext.isHAEnabled() && remoteConfigurationEnabled); + RMAuditLogger.logSuccess(UserGroupInformation.getCurrentUser() + .getShortUserName(), argName, + "AdminService"); + return response; } void refreshServiceAcls(Configuration configuration, - PolicyProvider policyProvider) { - this.server.refreshServiceAcl(configuration, policyProvider); + PolicyProvider policyProvider, boolean useRemoteConfiguration) { + this.server.refreshServiceAcl(configuration, policyProvider, + useRemoteConfiguration); } @Override diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java index 57605c0..a8cdb5a 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java @@ -102,6 +102,7 @@ private final AllocateResponse resync = recordFactory.newRecordInstance(AllocateResponse.class); private final RMContext rmContext; + private boolean remoteConfigurationEnabled; public ApplicationMasterService(RMContext rmContext, YarnScheduler scheduler) { super(ApplicationMasterService.class.getName()); @@ -132,12 +133,15 @@ protected void serviceStart() throws Exception { serverConf, this.rmContext.getAMRMTokenSecretManager(), serverConf.getInt(YarnConfiguration.RM_SCHEDULER_CLIENT_THREAD_COUNT, YarnConfiguration.DEFAULT_RM_SCHEDULER_CLIENT_THREAD_COUNT)); - + this.remoteConfigurationEnabled = + conf.getBoolean(YarnConfiguration.RM_HA_REMOTE_CONFIGURATION_ENABLED, + YarnConfiguration.DEFAULT_RM_HA_REMOTE_CONFIGURATION_ENABLED); // Enable service authorization? if (conf.getBoolean( CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION, false)) { - refreshServiceAcls(conf, new RMPolicyProvider()); + refreshServiceAcls(conf, new RMPolicyProvider(), + this.rmContext.isHAEnabled() && this.remoteConfigurationEnabled); } this.server.start(); @@ -577,8 +581,9 @@ public void unregisterAttempt(ApplicationAttemptId attemptId) { } public void refreshServiceAcls(Configuration configuration, - PolicyProvider policyProvider) { - this.server.refreshServiceAcl(configuration, policyProvider); + PolicyProvider policyProvider, boolean useRemoteConfiguration) { + this.server.refreshServiceAcl(configuration, policyProvider, + useRemoteConfiguration); } @Override diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java index 1df67f8..33a7aac 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java @@ -128,6 +128,7 @@ private final ApplicationACLsManager applicationsACLsManager; private final QueueACLsManager queueACLsManager; + private boolean remoteConfigurationEnabled; public ClientRMService(RMContext rmContext, YarnScheduler scheduler, RMAppManager rmAppManager, ApplicationACLsManager applicationACLsManager, @@ -159,11 +160,15 @@ protected void serviceStart() throws Exception { conf.getInt(YarnConfiguration.RM_CLIENT_THREAD_COUNT, YarnConfiguration.DEFAULT_RM_CLIENT_THREAD_COUNT)); + this.remoteConfigurationEnabled = + conf.getBoolean(YarnConfiguration.RM_HA_REMOTE_CONFIGURATION_ENABLED, + YarnConfiguration.DEFAULT_RM_HA_REMOTE_CONFIGURATION_ENABLED); // Enable service authorization? if (conf.getBoolean( CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION, false)) { - refreshServiceAcls(conf, new RMPolicyProvider()); + refreshServiceAcls(conf, new RMPolicyProvider(), + this.rmContext.isHAEnabled() && this.remoteConfigurationEnabled); } this.server.start(); @@ -703,8 +708,9 @@ private String getRenewerForToken(Token token) } void refreshServiceAcls(Configuration configuration, - PolicyProvider policyProvider) { - this.server.refreshServiceAcl(configuration, policyProvider); + PolicyProvider policyProvider, boolean useReomteConfiguration) { + this.server.refreshServiceAcl(configuration, policyProvider, + useReomteConfiguration); } private boolean isAllowedDelegationTokenOp() throws IOException { diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceTrackerService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceTrackerService.java index f80ce85..377d2c1 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceTrackerService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceTrackerService.java @@ -92,6 +92,7 @@ private int minAllocMb; private int minAllocVcores; + private boolean remoteConfigurationEnabled; static { resync.setNodeAction(NodeAction.RESYNC); @@ -157,11 +158,15 @@ protected void serviceStart() throws Exception { conf.getInt(YarnConfiguration.RM_RESOURCE_TRACKER_CLIENT_THREAD_COUNT, YarnConfiguration.DEFAULT_RM_RESOURCE_TRACKER_CLIENT_THREAD_COUNT)); + this.remoteConfigurationEnabled = + conf.getBoolean(YarnConfiguration.RM_HA_REMOTE_CONFIGURATION_ENABLED, + YarnConfiguration.DEFAULT_RM_HA_REMOTE_CONFIGURATION_ENABLED); // Enable service authorization? if (conf.getBoolean( CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION, false)) { - refreshServiceAcls(conf, new RMPolicyProvider()); + refreshServiceAcls(conf, new RMPolicyProvider(), + this.rmContext.isHAEnabled() && this.remoteConfigurationEnabled); } this.server.start(); @@ -414,7 +419,8 @@ public static Node resolve(String hostName) { } void refreshServiceAcls(Configuration configuration, - PolicyProvider policyProvider) { - this.server.refreshServiceAcl(configuration, policyProvider); + PolicyProvider policyProvider, boolean useRemoteConfiguration) { + this.server.refreshServiceAcl(configuration, policyProvider, + useRemoteConfiguration); } }