diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/launcher/ContainerLauncherImpl.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/launcher/ContainerLauncherImpl.java index 459fd56..b483486 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/launcher/ContainerLauncherImpl.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/launcher/ContainerLauncherImpl.java @@ -350,15 +350,14 @@ protected ContainerManager getCMProxy(ContainerId containerID, final InetSocketAddress cmAddr = NetUtils.createSocketAddr(containerManagerBindAddr); - UserGroupInformation user = UserGroupInformation.getCurrentUser(); - - if (UserGroupInformation.isSecurityEnabled()) { - Token token = - ProtoUtils.convertFromProtoFormat(containerToken, cmAddr); - // the user in createRemoteUser in this context has to be ContainerID - user = UserGroupInformation.createRemoteUser(containerID.toString()); - user.addToken(token); - } + + // the user in createRemoteUser in this context has to be ContainerID + UserGroupInformation user = + UserGroupInformation.createRemoteUser(containerID.toString()); + + Token token = + ProtoUtils.convertFromProtoFormat(containerToken, cmAddr); + user.addToken(token); ContainerManager proxy = user .doAs(new PrivilegedAction() { diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeManager.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeManager.java index b5abecd..ba9de1f 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeManager.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeManager.java @@ -135,13 +135,11 @@ public void init(Configuration conf) { conf.setBoolean(Dispatcher.DISPATCHER_EXIT_ON_ERROR_KEY, true); - // Create the secretManager if need be. - NMContainerTokenSecretManager containerTokenSecretManager = null; if (UserGroupInformation.isSecurityEnabled()) { - LOG.info("Security is enabled on NodeManager. " - + "Creating ContainerTokenSecretManager"); - containerTokenSecretManager = new NMContainerTokenSecretManager(conf); + LOG.info("Security is Enabled."); } + NMContainerTokenSecretManager containerTokenSecretManager = null; + containerTokenSecretManager = new NMContainerTokenSecretManager(conf); this.context = createNMContext(containerTokenSecretManager); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdaterImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdaterImpl.java index 284cd94..6aeb600 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdaterImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdaterImpl.java @@ -193,16 +193,12 @@ protected void rebootNodeStatusUpdater() { throw new AvroRuntimeException(e); } } - - private boolean isSecurityEnabled() { - return UserGroupInformation.isSecurityEnabled(); - } @Private protected boolean isTokenKeepAliveEnabled(Configuration conf) { return conf.getBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, YarnConfiguration.DEFAULT_LOG_AGGREGATION_ENABLED) - && isSecurityEnabled(); + && UserGroupInformation.isSecurityEnabled(); } protected ResourceTracker getRMClient() { @@ -298,16 +294,13 @@ protected void registerWithRM() throws YarnRemoteException { "Recieved SHUTDOWN signal from Resourcemanager ,Registration of NodeManager failed"); } - if (UserGroupInformation.isSecurityEnabled()) { - MasterKey masterKey = regNMResponse.getMasterKey(); - // do this now so that its set before we start heartbeating to RM - LOG.info("Security enabled - updating secret keys now"); - // It is expected that status updater is started by this point and - // RM gives the shared secret in registration during - // StatusUpdater#start(). - if (masterKey != null) { - this.context.getContainerTokenSecretManager().setMasterKey(masterKey); - } + MasterKey masterKey = regNMResponse.getMasterKey(); + // do this now so that its set before we start heartbeating to RM + // It is expected that status updater is started by this point and + // RM gives the shared secret in registration during + // StatusUpdater#start(). + if (masterKey != null) { + this.context.getContainerTokenSecretManager().setMasterKey(masterKey); } LOG.info("Registered with ResourceManager as " + this.nodeId @@ -438,10 +431,8 @@ public void run() { NodeHeartbeatRequest request = recordFactory .newRecordInstance(NodeHeartbeatRequest.class); request.setNodeStatus(nodeStatus); - if (isSecurityEnabled()) { - request.setLastKnownMasterKey(NodeStatusUpdaterImpl.this.context - .getContainerTokenSecretManager().getCurrentKey()); - } + request.setLastKnownMasterKey(NodeStatusUpdaterImpl.this.context + .getContainerTokenSecretManager().getCurrentKey()); while (!isStopped) { try { rmRetryCount++; @@ -470,13 +461,11 @@ public void run() { //get next heartbeat interval from response nextHeartBeatInterval = response.getNextHeartBeatInterval(); // See if the master-key has rolled over - if (isSecurityEnabled()) { - MasterKey updatedMasterKey = response.getMasterKey(); - if (updatedMasterKey != null) { - // Will be non-null only on roll-over on RM side - context.getContainerTokenSecretManager().setMasterKey( - updatedMasterKey); - } + MasterKey updatedMasterKey = response.getMasterKey(); + if (updatedMasterKey != null) { + // Will be non-null only on roll-over on RM side + context.getContainerTokenSecretManager().setMasterKey( + updatedMasterKey); } if (response.getNodeAction() == NodeAction.SHUTDOWN) { diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java index 6889110..a56df71 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java @@ -20,6 +20,8 @@ import static org.apache.hadoop.yarn.service.Service.STATE.STARTED; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; @@ -40,7 +42,6 @@ import org.apache.hadoop.security.token.Token; import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.util.StringUtils; -import org.apache.hadoop.yarn.YarnException; import org.apache.hadoop.yarn.api.ContainerManager; import org.apache.hadoop.yarn.api.protocolrecords.GetContainerStatusRequest; import org.apache.hadoop.yarn.api.protocolrecords.GetContainerStatusResponse; @@ -57,6 +58,7 @@ import org.apache.hadoop.yarn.event.AsyncDispatcher; import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.exceptions.YarnRemoteException; +import org.apache.hadoop.yarn.exceptions.impl.pb.YarnRemoteExceptionPBImpl; import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; import org.apache.hadoop.yarn.ipc.RPCUtil; @@ -300,6 +302,21 @@ private ContainerTokenIdentifier selectContainerTokenIdentifier( return resultId; } + private ContainerTokenIdentifier selectContainerTokenIdentifier( + org.apache.hadoop.yarn.api.records.Container container) + throws YarnRemoteException { + ContainerTokenIdentifier tokenId = new ContainerTokenIdentifier(); + try { + ByteBuffer buffer = container.getContainerToken().getIdentifier(); + tokenId.readFields(new DataInputStream(new ByteArrayInputStream(buffer + .array()))); + } catch (Exception e) { + LOG.error("Invalid container token received :" + e); + throw new YarnRemoteExceptionPBImpl(e); + } + return tokenId; + } + /** * Authorize the request. * @@ -317,10 +334,6 @@ private void authorizeRequest(String containerIDStr, UserGroupInformation remoteUgi) throws YarnRemoteException { - if (!UserGroupInformation.isSecurityEnabled()) { - return; - } - boolean unauthorized = false; StringBuilder messageBuilder = new StringBuilder("Unauthorized request to start container. "); @@ -332,30 +345,35 @@ private void authorizeRequest(String containerIDStr, } else if (launchContext != null) { // Verify other things also for startContainer() request. - if (LOG.isDebugEnabled()) { - LOG.debug("Number of TokenIdentifiers in the UGI from RPC: " - + remoteUgi.getTokenIdentifiers().size()); - } + ContainerTokenIdentifier tokenId = null; - // Get the tokenId from the remote user ugi - ContainerTokenIdentifier tokenId = - selectContainerTokenIdentifier(remoteUgi); + if (UserGroupInformation.isSecurityEnabled()) { + if (LOG.isDebugEnabled()) { + LOG.debug("Number of TokenIdentifiers in the UGI from RPC: " + + remoteUgi.getTokenIdentifiers().size()); + } + // Get the tokenId from the remote user ugi + tokenId = selectContainerTokenIdentifier(remoteUgi); + } else { + tokenId = selectContainerTokenIdentifier(container); + } if (tokenId == null) { unauthorized = true; messageBuilder - .append("\nContainerTokenIdentifier cannot be null! Null found for " - + containerIDStr); + .append("\nContainerTokenIdentifier cannot be null! Null found for " + + containerIDStr); } else { // Is the container coming in with correct user-name? - if (!tokenId.getApplicationSubmitter().equals(launchContext.getUser())) { + if (!launchContext.getUser().equals(tokenId.getApplicationSubmitter())) { unauthorized = true; messageBuilder.append("\n Expected user-name " + tokenId.getApplicationSubmitter() + " but found " + launchContext.getUser()); } + // Is the container being relaunched? Or RPC layer let startCall with // tokens generated off old-secret through? if (!this.context.getContainerTokenSecretManager() @@ -375,7 +393,7 @@ private void authorizeRequest(String containerIDStr, } Resource resource = tokenId.getResource(); - if (!resource.equals(container.getResource())) { + if (resource == null || !resource.equals(container.getResource())) { unauthorized = true; messageBuilder.append("\nExpected resource " + resource + " but found " + container.getResource()); @@ -476,13 +494,16 @@ public StartContainerResponse startContainer(StartContainerRequest request) // TODO: Validate the request dispatcher.getEventHandler().handle( new ApplicationContainerInitEvent(container)); + + ContainerTokenIdentifier tokenId = null; if (UserGroupInformation.isSecurityEnabled()) { - ContainerTokenIdentifier tokenId = - selectContainerTokenIdentifier(remoteUgi); - this.context.getContainerTokenSecretManager().startContainerSuccessful( - tokenId); + tokenId = selectContainerTokenIdentifier(remoteUgi); + } else { + tokenId = selectContainerTokenIdentifier(lauchContainer); } + this.context.getContainerTokenSecretManager().startContainerSuccessful( + tokenId); NMAuditLogger.logSuccess(launchContext.getUser(), AuditConstants.START_CONTAINER, "ContainerManageImpl", applicationID, containerID); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/application/ApplicationImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/application/ApplicationImpl.java index 4e4cf0a..e9dda5d 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/application/ApplicationImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/application/ApplicationImpl.java @@ -28,7 +28,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.security.Credentials; -import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.yarn.api.records.ApplicationAccessType; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ContainerId; @@ -394,9 +393,8 @@ public ApplicationState transition(ApplicationImpl app, public void transition(ApplicationImpl app, ApplicationEvent event) { // Inform the ContainerTokenSecretManager - if (UserGroupInformation.isSecurityEnabled()) { - app.context.getContainerTokenSecretManager().appFinished(app.appId); - } + app.context.getContainerTokenSecretManager().appFinished(app.appId); + // Inform the logService app.dispatcher.getEventHandler().handle( new LogHandlerAppFinishedEvent(app.appId)); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/security/NMContainerTokenSecretManager.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/security/NMContainerTokenSecretManager.java index bc70f26..f1ca726 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/security/NMContainerTokenSecretManager.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/security/NMContainerTokenSecretManager.java @@ -27,7 +27,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.token.SecretManager; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ContainerId; @@ -35,6 +34,8 @@ import org.apache.hadoop.yarn.server.api.records.MasterKey; import org.apache.hadoop.yarn.server.security.BaseContainerTokenSecretManager; +import com.google.common.annotations.VisibleForTesting; + /** * The NM maintains only two master-keys. The current key that RM knows and the * key from the previous rolling-interval. @@ -134,10 +135,6 @@ public synchronized void setMasterKey(MasterKey masterKeyRecord) { */ public synchronized void startContainerSuccessful( ContainerTokenIdentifier tokenId) { - if (!UserGroupInformation.isSecurityEnabled()) { - return; - } - int keyId = tokenId.getMasterKeyId(); if (currentMasterKey.getMasterKey().getKeyId() == keyId) { addKeyForContainerId(tokenId.getContainerID(), currentMasterKey); @@ -185,4 +182,16 @@ private synchronized void addKeyForContainerId(ContainerId containerId, public synchronized void appFinished(ApplicationId appId) { this.oldMasterKeys.remove(appId); } + + @Private + @VisibleForTesting + public synchronized boolean containsMasterKey(ApplicationId appId, + ContainerId containerId) { + if (this.oldMasterKeys.containsKey(appId) + && this.oldMasterKeys.get(appId).containsKey(containerId)) { + return true; + } else { + return false; + } + } } \ No newline at end of file diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/application/TestApplication.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/application/TestApplication.java index 1050a9e..b781144 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/application/TestApplication.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/application/TestApplication.java @@ -25,10 +25,13 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import junit.framework.Assert; + import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.yarn.api.records.ApplicationAccessType; import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; @@ -37,6 +40,9 @@ import org.apache.hadoop.yarn.api.records.ContainerLaunchContext; import org.apache.hadoop.yarn.event.DrainDispatcher; import org.apache.hadoop.yarn.event.EventHandler; +import org.apache.hadoop.yarn.security.ContainerTokenIdentifier; +import org.apache.hadoop.yarn.server.api.records.MasterKey; +import org.apache.hadoop.yarn.server.api.records.impl.pb.MasterKeyPBImpl; import org.apache.hadoop.yarn.server.nodemanager.Context; import org.apache.hadoop.yarn.server.nodemanager.containermanager.AuxServicesEvent; import org.apache.hadoop.yarn.server.nodemanager.containermanager.AuxServicesEventType; @@ -54,11 +60,13 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.loghandler.event.LogHandlerEventType; import org.apache.hadoop.yarn.server.nodemanager.containermanager.monitor.ContainersMonitorEvent; import org.apache.hadoop.yarn.server.nodemanager.containermanager.monitor.ContainersMonitorEventType; +import org.apache.hadoop.yarn.server.nodemanager.security.NMContainerTokenSecretManager; import org.apache.hadoop.yarn.server.security.ApplicationACLsManager; import org.apache.hadoop.yarn.util.BuilderUtils; import org.junit.Test; import org.mockito.ArgumentMatcher; + public class TestApplication { /** @@ -257,6 +265,10 @@ public void testAppFinishedOnRunningContainers() { AuxServicesEventType.APPLICATION_STOP, wa.appId))); wa.appResourcesCleanedup(); + for ( Container container : wa.containers) { + Assert.assertFalse(wa.context.getContainerTokenSecretManager() + .containsMasterKey(wa.appId, container.getContainer().getId())); + } assertEquals(ApplicationState.FINISHED, wa.app.getApplicationState()); } finally { @@ -293,6 +305,10 @@ public void testAppFinishedOnCompletedContainers() { LocalizationEventType.DESTROY_APPLICATION_RESOURCES, wa.app))); wa.appResourcesCleanedup(); + for ( Container container : wa.containers) { + Assert.assertFalse(wa.context.getContainerTokenSecretManager() + .containsMasterKey(wa.appId, container.getContainer().getId())); + } assertEquals(ApplicationState.FINISHED, wa.app.getApplicationState()); } finally { if (wa != null) @@ -429,8 +445,10 @@ public boolean matches(Object argument) { final Application app; WrappedApplication(int id, long timestamp, String user, int numContainers) { + Configuration conf = new Configuration(); + dispatcher = new DrainDispatcher(); - dispatcher.init(new Configuration()); + dispatcher.init(conf); localizerBus = mock(EventHandler.class); launcherBus = mock(EventHandler.class); @@ -448,6 +466,15 @@ public boolean matches(Object argument) { context = mock(Context.class); + when(context.getContainerTokenSecretManager()).thenReturn( + new NMContainerTokenSecretManager(conf)); + + // Setting master key + MasterKey masterKey = new MasterKeyPBImpl(); + masterKey.setKeyId(123); + masterKey.setBytes(ByteBuffer.wrap(new byte[]{(new Integer(123).byteValue())})); + context.getContainerTokenSecretManager().setMasterKey(masterKey); + this.user = user; this.appId = BuilderUtils.newApplicationId(timestamp, id); @@ -455,7 +482,12 @@ public boolean matches(Object argument) { new Configuration()), this.user, appId, null, context); containers = new ArrayList(); for (int i = 0; i < numContainers; i++) { - containers.add(createMockedContainer(this.appId, i)); + Container container = createMockedContainer(this.appId, i); + containers.add(container); + context.getContainerTokenSecretManager().startContainerSuccessful( + new ContainerTokenIdentifier(container.getContainer().getId(), "", + "", null, System.currentTimeMillis() + 1000, masterKey.getKeyId())); + Assert.assertTrue(context.getContainerTokenSecretManager().containsMasterKey(appId, container.getContainer().getId())); } dispatcher.start(); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/krb5.conf hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/krb5.conf new file mode 100644 index 0000000..121ac6d --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/krb5.conf @@ -0,0 +1,28 @@ +# +# 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. +# +[libdefaults] + default_realm = APACHE.ORG + udp_preference_limit = 1 + extra_addresses = 127.0.0.1 +[realms] + APACHE.ORG = { + admin_server = localhost:88 + kdc = localhost:88 + } +[domain_realm] + localhost = APACHE.ORG 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 c4f0b4c..385af0e 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 @@ -43,7 +43,6 @@ import org.apache.hadoop.yarn.server.api.records.MasterKey; import org.apache.hadoop.yarn.server.api.records.NodeAction; import org.apache.hadoop.yarn.server.api.records.NodeStatus; -import org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore.RMState; import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNode; import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNodeEvent; import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNodeEventType; @@ -190,11 +189,9 @@ public RegisterNodeManagerResponse registerNodeManager( return response; } - if (isSecurityEnabled()) { - MasterKey nextMasterKeyForNode = - this.containerTokenSecretManager.getCurrentKey(); - response.setMasterKey(nextMasterKeyForNode); - } + MasterKey nextMasterKeyForNode = + this.containerTokenSecretManager.getCurrentKey(); + response.setMasterKey(nextMasterKeyForNode); RMNode rmNode = new RMNodeImpl(nodeId, rmContext, host, cmPort, httpPort, resolve(host), capability); @@ -281,26 +278,24 @@ public NodeHeartbeatResponse nodeHeartbeat(NodeHeartbeatRequest request) getResponseId() + 1, NodeAction.NORMAL, null, null, null, nextHeartBeatInterval); rmNode.updateNodeHeartbeatResponseForCleanup(nodeHeartBeatResponse); + // Check if node's masterKey needs to be updated and if the currentKey has // roller over, send it across - if (isSecurityEnabled()) { - - boolean shouldSendMasterKey = false; - - MasterKey nextMasterKeyForNode = - this.containerTokenSecretManager.getNextKey(); - if (nextMasterKeyForNode != null) { - // nextMasterKeyForNode can be null if there is no outstanding key that - // is in the activation period. - MasterKey nodeKnownMasterKey = request.getLastKnownMasterKey(); - if (nodeKnownMasterKey.getKeyId() != nextMasterKeyForNode.getKeyId()) { - shouldSendMasterKey = true; - } - } - if (shouldSendMasterKey) { - nodeHeartBeatResponse.setMasterKey(nextMasterKeyForNode); + boolean shouldSendMasterKey = false; + + MasterKey nextMasterKeyForNode = + this.containerTokenSecretManager.getNextKey(); + if (nextMasterKeyForNode != null) { + // nextMasterKeyForNode can be null if there is no outstanding key that + // is in the activation period. + MasterKey nodeKnownMasterKey = request.getLastKnownMasterKey(); + if (nodeKnownMasterKey.getKeyId() != nextMasterKeyForNode.getKeyId()) { + shouldSendMasterKey = true; } } + if (shouldSendMasterKey) { + nodeHeartBeatResponse.setMasterKey(nextMasterKeyForNode); + } // 4. Send status to RMNode, saving the latest response. this.rmContext.getDispatcher().getEventHandler().handle( @@ -324,8 +319,4 @@ void refreshServiceAcls(Configuration configuration, PolicyProvider policyProvider) { this.server.refreshServiceAcl(configuration, policyProvider); } - - protected boolean isSecurityEnabled() { - return UserGroupInformation.isSecurityEnabled(); - } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java index eaa15f5..eb1b1d9 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java @@ -366,18 +366,15 @@ public RMAppAttemptImpl(ApplicationAttemptId appAttemptId, this.scheduler = scheduler; this.masterService = masterService; - if (UserGroupInformation.isSecurityEnabled()) { - - this.rmContext.getClientToAMTokenSecretManager().registerApplication( + this.rmContext.getClientToAMTokenSecretManager().registerApplication( appAttemptId); - Token token = - new Token(new ClientTokenIdentifier( + Token token = + new Token(new ClientTokenIdentifier( appAttemptId), this.rmContext.getClientToAMTokenSecretManager()); - this.clientToken = - BuilderUtils.newClientToken(token.getIdentifier(), token.getKind() + this.clientToken = + BuilderUtils.newClientToken(token.getIdentifier(), token.getKind() .toString(), token.getPassword(), token.getService().toString()); - } ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); this.readLock = lock.readLock(); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java index 64f7114..f4108c6 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java @@ -1296,16 +1296,13 @@ private Resource assignContainer(Resource clusterResource, FiCaSchedulerNode nod unreserve(application, priority, node, rmContainer); } - // Create container tokens in secure-mode - if (UserGroupInformation.isSecurityEnabled()) { - ContainerToken containerToken = - createContainerToken(application, container); - if (containerToken == null) { - // Something went wrong... - return Resources.none(); - } - container.setContainerToken(containerToken); + ContainerToken containerToken = + createContainerToken(application, container); + if (containerToken == null) { + // Something went wrong... + return Resources.none(); } + container.setContainerToken(containerToken); // Inform the application RMContainer allocatedContainer = diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AppSchedulable.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AppSchedulable.java index 4bd6e2b..c1896c3 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AppSchedulable.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AppSchedulable.java @@ -25,7 +25,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; -import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.yarn.api.records.Container; import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.api.records.ContainerToken; @@ -35,8 +34,8 @@ import org.apache.hadoop.yarn.api.records.ResourceRequest; import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; -import org.apache.hadoop.yarn.server.resourcemanager.resource.DefaultResourceCalculator; import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager; +import org.apache.hadoop.yarn.server.resourcemanager.resource.DefaultResourceCalculator; import org.apache.hadoop.yarn.server.resourcemanager.resource.Resources; import org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainer; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.NodeType; @@ -159,16 +158,11 @@ public Container createContainer( NodeId nodeId = node.getRMNode().getNodeID(); ContainerId containerId = BuilderUtils.newContainerId(application .getApplicationAttemptId(), application.getNewContainerId()); - ContainerToken containerToken = null; - - // If security is enabled, send the container-tokens too. - if (UserGroupInformation.isSecurityEnabled()) { - containerToken = - containerTokenSecretManager.createContainerToken(containerId, nodeId, + ContainerToken containerToken = + containerTokenSecretManager.createContainerToken(containerId, nodeId, application.getUser(), capability); - if (containerToken == null) { - return null; // Try again later. - } + if (containerToken == null) { + return null; // Try again later. } // Create the container diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fifo/FifoScheduler.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fifo/FifoScheduler.java index 2024e74..c822bf3 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fifo/FifoScheduler.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fifo/FifoScheduler.java @@ -552,15 +552,12 @@ private int assignContainer(FiCaSchedulerNode node, FiCaSchedulerApp application .getApplicationAttemptId(), application.getNewContainerId()); ContainerToken containerToken = null; - // If security is enabled, send the container-tokens too. - if (UserGroupInformation.isSecurityEnabled()) { - containerToken = - this.rmContext.getContainerTokenSecretManager() + containerToken = + this.rmContext.getContainerTokenSecretManager() .createContainerToken(containerId, nodeId, - application.getUser(), capability); - if (containerToken == null) { - return i; // Try again later. - } + application.getUser(), capability); + if (containerToken == null) { + return i; // Try again later. } // Create the container diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java index 5d65dcf..93d514c 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java @@ -20,8 +20,6 @@ import static org.junit.Assert.fail; -import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; @@ -39,14 +37,11 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.CommonConfigurationKeysPublic; -import org.apache.hadoop.fs.FileContext; -import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.UnsupportedFileSystemException; import org.apache.hadoop.io.DataInputBuffer; import org.apache.hadoop.io.Text; import org.apache.hadoop.ipc.RPC; import org.apache.hadoop.net.NetUtils; -import org.apache.hadoop.security.AccessControlException; import org.apache.hadoop.security.SecurityUtil; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.token.Token; @@ -86,8 +81,6 @@ import org.apache.hadoop.yarn.server.resourcemanager.security.RMContainerTokenSecretManager; import org.apache.hadoop.yarn.util.BuilderUtils; import org.apache.hadoop.yarn.util.Records; -import org.junit.AfterClass; -import org.junit.BeforeClass; import org.junit.Test; public class TestContainerManagerSecurity { @@ -95,39 +88,51 @@ static Log LOG = LogFactory.getLog(TestContainerManagerSecurity.class); static final RecordFactory recordFactory = RecordFactoryProvider .getRecordFactory(null); - private static FileContext localFS = null; - private static final File localDir = new File("target", - TestContainerManagerSecurity.class.getName() + "-localDir") - .getAbsoluteFile(); private static MiniYARNCluster yarnCluster; static final Configuration conf = new Configuration(); - @BeforeClass - public static void setup() throws AccessControlException, - FileNotFoundException, UnsupportedFileSystemException, IOException { - localFS = FileContext.getLocalFSFileContext(); - localFS.delete(new Path(localDir.getAbsolutePath()), true); - localDir.mkdir(); - + @Test (timeout = 1000000) + public void testContainerManagerWithSecurityEnabled() throws Exception { conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, "kerberos"); - // Set AM expiry interval to be very long. - conf.setLong(YarnConfiguration.RM_AM_EXPIRY_INTERVAL_MS, 100000L); - UserGroupInformation.setConfiguration(conf); - yarnCluster = new MiniYARNCluster(TestContainerManagerSecurity.class - .getName(), 1, 1, 1); - yarnCluster.init(conf); - yarnCluster.start(); + testContainerManager(); } - - @AfterClass - public static void teardown() { - yarnCluster.stop(); + + @Test (timeout=1000000) + public void testContainerManagerWithSecurityDisabled() throws Exception { + conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, + "simple"); + testContainerManager(); } - - @Test - public void testAuthenticatedUser() throws IOException, + + private void testContainerManager() throws Exception { + try { + yarnCluster = new MiniYARNCluster(TestContainerManagerSecurity.class + .getName(), 1, 1, 1); + conf.setLong(YarnConfiguration.RM_AM_EXPIRY_INTERVAL_MS, 100000L); + UserGroupInformation.setConfiguration(conf); + yarnCluster.init(conf); + yarnCluster.start(); + + // Testing for authenticated user + testAuthenticatedUser(); + + // Testing for malicious user + testMaliceUser(); + + // Testing for unauthorized user + testUnauthorizedUser(); + + } finally { + if (yarnCluster != null) { + yarnCluster.stop(); + yarnCluster = null; + } + } + } + + private void testAuthenticatedUser() throws IOException, InterruptedException, YarnRemoteException { LOG.info("Running test for authenticated user"); @@ -179,8 +184,7 @@ public Void run() throws Exception { resourceManager.getClientRMService().forceKillApplication(request); } - @Test - public void testMaliceUser() throws IOException, InterruptedException, + private void testMaliceUser() throws IOException, InterruptedException, YarnRemoteException { LOG.info("Running test for malice user"); @@ -266,8 +270,7 @@ public Void run() { resourceManager.getClientRMService().forceKillApplication(request); } - @Test - public void testUnauthorizedUser() throws IOException, InterruptedException, + private void testUnauthorizedUser() throws IOException, InterruptedException, YarnRemoteException { LOG.info("\n\nRunning test for malice user"); @@ -318,8 +321,8 @@ public ContainerManager run() { LOG.info("Going to contact NM: unauthorized request"); callWithIllegalContainerID(client, tokenId); - callWithIllegalResource(client, tokenId); - callWithIllegalUserName(client, tokenId); + callWithIllegalResource(client, tokenId, allocatedContainer); + callWithIllegalUserName(client, tokenId, allocatedContainer); return client; } @@ -337,10 +340,11 @@ public ContainerManager run() { resourceManager.getRMContainerTokenSecretManager(); final ContainerTokenIdentifier newTokenId = new ContainerTokenIdentifier(tokenId.getContainerID(), - tokenId.getNmHostAddress(), "testUser", tokenId.getResource(), - System.currentTimeMillis() - 1, - containerTokenSecreteManager.getCurrentKey().getKeyId()); - byte[] passowrd = + tokenId.getNmHostAddress(), tokenId.getApplicationSubmitter(), + tokenId.getResource(), + System.currentTimeMillis() - 1, + containerTokenSecreteManager.getCurrentKey().getKeyId()); + final byte[] passowrd = containerTokenSecreteManager.createPassword( newTokenId); // Create a valid token by using the key from the RM. @@ -359,13 +363,12 @@ public Void run() { LOG.info("Going to contact NM with expired token"); ContainerLaunchContext context = createContainerLaunchContextForTest(newTokenId); - Container container = - BuilderUtils.newContainer(newTokenId.getContainerID(), null, null, - BuilderUtils.newResource(newTokenId.getResource().getMemory(), - newTokenId.getResource().getVirtualCores()), null, null, 0); - StartContainerRequest request = Records.newRecord(StartContainerRequest.class); + StartContainerRequest request = + Records.newRecord(StartContainerRequest.class); request.setContainerLaunchContext(context); - request.setContainer(container); + allocatedContainer.setContainerToken(BuilderUtils.newContainerToken( + allocatedContainer.getNodeId(), passowrd, newTokenId)); + request.setContainer(allocatedContainer); //Calling startContainer with an expired token. try { @@ -454,17 +457,19 @@ private AMRMProtocol submitAndRegisterApplication( // Ask for a container from the RM final InetSocketAddress schedulerAddr = resourceManager.getApplicationMasterService().getBindAddress(); - ApplicationTokenIdentifier appTokenIdentifier = new ApplicationTokenIdentifier( - appAttempt.getAppAttemptId()); - ApplicationTokenSecretManager appTokenSecretManager = - new ApplicationTokenSecretManager(conf); - appTokenSecretManager.setMasterKey(resourceManager - .getApplicationTokenSecretManager().getMasterKey()); - Token appToken = - new Token(appTokenIdentifier, - appTokenSecretManager); - SecurityUtil.setTokenService(appToken, schedulerAddr); - currentUser.addToken(appToken); + if (UserGroupInformation.isSecurityEnabled()) { + ApplicationTokenIdentifier appTokenIdentifier = new ApplicationTokenIdentifier( + appAttempt.getAppAttemptId()); + ApplicationTokenSecretManager appTokenSecretManager = + new ApplicationTokenSecretManager(conf); + appTokenSecretManager.setMasterKey(resourceManager + .getApplicationTokenSecretManager().getMasterKey()); + Token appToken = + new Token(appTokenIdentifier, + appTokenSecretManager); + SecurityUtil.setTokenService(appToken, schedulerAddr); + currentUser.addToken(appToken); + } AMRMProtocol scheduler = currentUser .doAs(new PrivilegedAction() { @@ -544,15 +549,14 @@ void callWithIllegalContainerID(ContainerManager client, } void callWithIllegalResource(ContainerManager client, - ContainerTokenIdentifier tokenId) { + ContainerTokenIdentifier tokenId, Container container) { StartContainerRequest request = recordFactory .newRecordInstance(StartContainerRequest.class); // Authenticated but unauthorized, due to wrong resource ContainerLaunchContext context = createContainerLaunchContextForTest(tokenId); - Container container = - BuilderUtils.newContainer(tokenId.getContainerID(), null, null, - BuilderUtils.newResource(2048, 1), null, null, 0); + Resource rsrc = container.getResource(); + container.setResource(BuilderUtils.newResource(2048, 1)); request.setContainerLaunchContext(context); request.setContainer(container); try { @@ -570,20 +574,17 @@ void callWithIllegalResource(ContainerManager client, LOG.info("Got IOException: ",e); fail("IOException is not expected."); } + container.setResource(rsrc); } void callWithIllegalUserName(ContainerManager client, - ContainerTokenIdentifier tokenId) { + ContainerTokenIdentifier tokenId, Container container) { StartContainerRequest request = recordFactory .newRecordInstance(StartContainerRequest.class); // Authenticated but unauthorized, due to wrong resource ContainerLaunchContext context = createContainerLaunchContextForTest(tokenId); context.setUser("Saruman"); // Set a different user-name. - Container container = - BuilderUtils.newContainer(tokenId.getContainerID(), null, null, - BuilderUtils.newResource(tokenId.getResource().getMemory(), tokenId - .getResource().getVirtualCores()), null, null, 0); request.setContainerLaunchContext(context); request.setContainer(container); try { @@ -607,7 +608,8 @@ private ContainerLaunchContext createContainerLaunchContextForTest( ContainerTokenIdentifier tokenId) { ContainerLaunchContext context = BuilderUtils.newContainerLaunchContext( - "testUser", new HashMap(), + tokenId.getApplicationSubmitter(), + new HashMap(), new HashMap(), new ArrayList(), new HashMap(), null, new HashMap()); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestRMNMSecretKeys.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestRMNMSecretKeys.java index 9d0fb0c..60a73a6 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestRMNMSecretKeys.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestRMNMSecretKeys.java @@ -1,20 +1,20 @@ /** -* 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. -*/ + * 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; @@ -22,6 +22,8 @@ import junit.framework.Assert; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.yarn.conf.YarnConfiguration; @@ -37,17 +39,27 @@ public class TestRMNMSecretKeys { - @Test + static Log LOG = LogFactory.getLog(TestRMNMSecretKeys.class); + + @Test(timeout = 1000000) public void testNMUpdation() throws Exception { YarnConfiguration conf = new YarnConfiguration(); + // validating RM NM keys for Unsecured environment + validateRMNMKeyExchange(conf); + + // validating RM NM keys for secured environment conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, - "kerberos"); + "kerberos"); UserGroupInformation.setConfiguration(conf); + validateRMNMKeyExchange(conf); + } + + private void validateRMNMKeyExchange(YarnConfiguration conf) throws Exception { // Default rolling and activation intervals are large enough, no need to // intervene - final DrainDispatcher dispatcher = new DrainDispatcher(); ResourceManager rm = new ResourceManager() { + @Override protected void doSecureLogin() throws IOException { // Do nothing. @@ -69,15 +81,15 @@ protected Dispatcher createDispatcher() { NodeHeartbeatResponse response = nm.nodeHeartbeat(true); Assert.assertNull( - "First heartbeat after registration shouldn't get any key updates!", - response.getMasterKey()); + "First heartbeat after registration shouldn't get any key updates!", + response.getMasterKey()); dispatcher.await(); response = nm.nodeHeartbeat(true); Assert - .assertNull( - "Even second heartbeat after registration shouldn't get any key updates!", - response.getMasterKey()); + .assertNull( + "Even second heartbeat after registration shouldn't get any key updates!", + response.getMasterKey()); dispatcher.await(); // Let's force a roll-over @@ -88,17 +100,17 @@ protected Dispatcher createDispatcher() { // Heartbeats after roll-over and before activation should be fine. response = nm.nodeHeartbeat(true); Assert.assertNotNull( - "Heartbeats after roll-over and before activation should not err out.", - response.getMasterKey()); + "Heartbeats after roll-over and before activation should not err out.", + response.getMasterKey()); Assert.assertEquals( - "Roll-over should have incremented the key-id only by one!", - masterKey.getKeyId() + 1, response.getMasterKey().getKeyId()); + "Roll-over should have incremented the key-id only by one!", + masterKey.getKeyId() + 1, response.getMasterKey().getKeyId()); dispatcher.await(); response = nm.nodeHeartbeat(true); Assert.assertNull( - "Second heartbeat after roll-over shouldn't get any key updates!", - response.getMasterKey()); + "Second heartbeat after roll-over shouldn't get any key updates!", + response.getMasterKey()); dispatcher.await(); // Let's force activation @@ -106,15 +118,17 @@ protected Dispatcher createDispatcher() { response = nm.nodeHeartbeat(true); Assert.assertNull("Activation shouldn't cause any key updates!", - response.getMasterKey()); + response.getMasterKey()); dispatcher.await(); response = nm.nodeHeartbeat(true); - Assert.assertNull( - "Even second heartbeat after activation shouldn't get any key updates!", - response.getMasterKey()); + Assert + .assertNull( + "Even second heartbeat after activation shouldn't get any key updates!", + response.getMasterKey()); dispatcher.await(); rm.stop(); + } }