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..9931386 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,13 @@ 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."); } + // Create the secretManager if need be. + NMContainerTokenSecretManager containerTokenSecretManager = null; + LOG.info("Creating ContainerTokenSecretManager"); + 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..d46948e 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 @@ -299,15 +299,18 @@ protected void registerWithRM() throws YarnRemoteException { } 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); + LOG.info("Security is Enabled."); + } + 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) { + if (LOG.isDebugEnabled()) { + LOG.info("updating secret keys now : " + masterKey); } + this.context.getContainerTokenSecretManager().setMasterKey(masterKey); } LOG.info("Registered with ResourceManager as " + this.nodeId @@ -470,13 +473,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 c79d7c9..01487fc 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; @@ -299,6 +301,19 @@ private ContainerTokenIdentifier selectContainerTokenIdentifier( return resultId; } + private ContainerTokenIdentifier selectContainerTokenIdentifier( + org.apache.hadoop.yarn.api.records.Container container) { + 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); + } + return tokenId; + } + /** * Authorize the request. * @@ -316,10 +331,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. "); @@ -331,30 +342,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() @@ -374,7 +390,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()); @@ -475,13 +491,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/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..e96278d 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 @@ -65,8 +65,10 @@ public NMContainerTokenSecretManager(Configuration conf) { */ @Private public synchronized void setMasterKey(MasterKey masterKeyRecord) { - LOG.info("Rolling master-key for container-tokens, got key with id " - + masterKeyRecord.getKeyId()); + if (LOG.isDebugEnabled()) { + LOG.info("Rolling master-key for container-tokens, got key with id " + + masterKeyRecord.getKeyId()); + } if (super.currentMasterKey == null) { super.currentMasterKey = new MasterKeyData(masterKeyRecord); } else { 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..1488582 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 @@ -190,11 +190,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 +279,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( diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/amlauncher/AMLauncher.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/amlauncher/AMLauncher.java index a9d40eb..645b84e 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/amlauncher/AMLauncher.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/amlauncher/AMLauncher.java @@ -189,48 +189,44 @@ private void setupTokensAndEnv( environment.put(ApplicationConstants.MAX_APP_ATTEMPTS_ENV, String.valueOf(rmContext.getRMApps().get( applicationId).getMaxAppAttempts())); - - if (UserGroupInformation.isSecurityEnabled()) { - // TODO: Security enabled/disabled info should come from RM. - Credentials credentials = new Credentials(); + Credentials credentials = new Credentials(); - DataInputByteBuffer dibb = new DataInputByteBuffer(); - if (container.getContainerTokens() != null) { - // TODO: Don't do this kind of checks everywhere. - dibb.reset(container.getContainerTokens()); - credentials.readTokenStorageStream(dibb); - } + DataInputByteBuffer dibb = new DataInputByteBuffer(); + if (container.getContainerTokens() != null) { + // TODO: Don't do this kind of checks everywhere. + dibb.reset(container.getContainerTokens()); + credentials.readTokenStorageStream(dibb); + } - ApplicationTokenIdentifier id = new ApplicationTokenIdentifier( - application.getAppAttemptId()); - Token appMasterToken = - new Token(id, - this.rmContext.getApplicationTokenSecretManager()); - InetSocketAddress serviceAddr = conf.getSocketAddr( - YarnConfiguration.RM_SCHEDULER_ADDRESS, - YarnConfiguration.DEFAULT_RM_SCHEDULER_ADDRESS, - YarnConfiguration.DEFAULT_RM_SCHEDULER_PORT); - // normally the client should set the service after acquiring the token, - // but this token is directly provided to the AMs - SecurityUtil.setTokenService(appMasterToken, serviceAddr); + ApplicationTokenIdentifier id = new ApplicationTokenIdentifier( + application.getAppAttemptId()); + Token appMasterToken = + new Token(id, + this.rmContext.getApplicationTokenSecretManager()); + InetSocketAddress serviceAddr = conf.getSocketAddr( + YarnConfiguration.RM_SCHEDULER_ADDRESS, + YarnConfiguration.DEFAULT_RM_SCHEDULER_ADDRESS, + YarnConfiguration.DEFAULT_RM_SCHEDULER_PORT); + // normally the client should set the service after acquiring the token, + // but this token is directly provided to the AMs + SecurityUtil.setTokenService(appMasterToken, serviceAddr); - // Add the ApplicationMaster token - credentials.addToken(appMasterToken.getService(), appMasterToken); - DataOutputBuffer dob = new DataOutputBuffer(); - credentials.writeTokenStorageToStream(dob); - container.setContainerTokens( - ByteBuffer.wrap(dob.getData(), 0, dob.getLength())); + // Add the ApplicationMaster token + credentials.addToken(appMasterToken.getService(), appMasterToken); + DataOutputBuffer dob = new DataOutputBuffer(); + credentials.writeTokenStorageToStream(dob); + container.setContainerTokens( + ByteBuffer.wrap(dob.getData(), 0, dob.getLength())); - SecretKey clientSecretKey = - this.rmContext.getClientToAMTokenSecretManager().getMasterKey( + SecretKey clientSecretKey = + this.rmContext.getClientToAMTokenSecretManager().getMasterKey( application.getAppAttemptId()); - String encoded = - Base64.encodeBase64URLSafeString(clientSecretKey.getEncoded()); - environment.put( - ApplicationConstants.APPLICATION_CLIENT_SECRET_ENV_NAME, - encoded); - } + String encoded = + Base64.encodeBase64URLSafeString(clientSecretKey.getEncoded()); + environment.put( + ApplicationConstants.APPLICATION_CLIENT_SECRET_ENV_NAME, + encoded); } @SuppressWarnings("unchecked") 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-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 46fffb4..6f83206 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 @@ -38,7 +38,6 @@ import org.apache.commons.logging.Log; 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; @@ -110,8 +109,6 @@ public static void setup() throws AccessControlException, localFS.delete(new Path(localDir.getAbsolutePath()), true); localDir.mkdir(); - 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); @@ -126,7 +123,7 @@ public static void teardown() { yarnCluster.stop(); } - @Test + @Test (timeout = 1000000) public void testAuthenticatedUser() throws IOException, InterruptedException { @@ -179,7 +176,7 @@ public Void run() throws Exception { resourceManager.getClientRMService().forceKillApplication(request); } - @Test + @Test (timeout = 1000000) public void testMaliceUser() throws IOException, InterruptedException { LOG.info("Running test for malice user"); @@ -265,7 +262,7 @@ public Void run() { resourceManager.getClientRMService().forceKillApplication(request); } - @Test + @Test (timeout=100000) public void testUnauthorizedUser() throws IOException, InterruptedException { LOG.info("\n\nRunning test for malice user"); @@ -316,8 +313,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; } @@ -335,10 +332,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. @@ -357,13 +355,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 { @@ -539,15 +536,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 { @@ -562,20 +558,17 @@ void callWithIllegalResource(ContainerManager client, "\nExpected resource " + tokenId.getResource().toString() + " but found " + container.getResource().toString())); } + 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 { @@ -596,7 +589,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..e4bfb66 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,37 @@ public class TestRMNMSecretKeys { - @Test + static Log LOG = LogFactory.getLog(TestRMNMSecretKeys.class); + + @Test(timeout = 10000) public void testNMUpdation() throws Exception { YarnConfiguration conf = new YarnConfiguration(); - conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, - "kerberos"); - UserGroupInformation.setConfiguration(conf); + // validating RM NM keys for Unsecured environment + validateRMNMKeyExchange(conf); + if (isSecurityEnabled(conf)) { + validateRMNMKeyExchange(conf); + } + } + + private boolean isSecurityEnabled(YarnConfiguration conf) { + boolean securityEnabled = true; + try { + conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, + "kerberos"); + UserGroupInformation.setConfiguration(conf); + } catch (Throwable e) { + LOG.error("Security is not enabled ", e); + securityEnabled = false; + } + return securityEnabled; + } + + 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 +91,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 +110,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 +128,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(); + } }