diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/ContainerTokenIdentifier.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/ContainerTokenIdentifier.java index e58f584e827..68f727d2be8 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/ContainerTokenIdentifier.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/ContainerTokenIdentifier.java @@ -48,14 +48,16 @@ public class ContainerTokenIdentifier extends TokenIdentifier { private ContainerId containerId; private String nmHostAddr; + private String appSubmitter; private Resource resource; private long expiryTimeStamp; private int masterKeyId; public ContainerTokenIdentifier(ContainerId containerID, String hostName, - Resource r, long expiryTimeStamp, int masterKeyId) { + String appSubmitter, Resource r, long expiryTimeStamp, int masterKeyId) { this.containerId = containerID; this.nmHostAddr = hostName; + this.appSubmitter = appSubmitter; this.resource = r; this.expiryTimeStamp = expiryTimeStamp; this.masterKeyId = masterKeyId; @@ -71,6 +73,10 @@ public class ContainerTokenIdentifier extends TokenIdentifier { return this.containerId; } + public String getApplicationSubmitter() { + return this.appSubmitter; + } + public String getNmHostAddress() { return this.nmHostAddr; } @@ -98,6 +104,7 @@ public class ContainerTokenIdentifier extends TokenIdentifier { out.writeInt(applicationAttemptId.getAttemptId()); out.writeInt(this.containerId.getId()); out.writeUTF(this.nmHostAddr); + out.writeUTF(this.appSubmitter); out.writeInt(this.resource.getMemory()); out.writeLong(this.expiryTimeStamp); out.writeInt(this.masterKeyId); @@ -112,6 +119,7 @@ public class ContainerTokenIdentifier extends TokenIdentifier { this.containerId = BuilderUtils.newContainerId(applicationAttemptId, in .readInt()); this.nmHostAddr = in.readUTF(); + this.appSubmitter = in.readUTF(); this.resource = BuilderUtils.newResource(in.readInt()); this.expiryTimeStamp = in.readLong(); this.masterKeyId = in.readInt(); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/security/BaseContainerTokenSecretManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/security/BaseContainerTokenSecretManager.java index 16f4b6f2340..ade32b44c00 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/security/BaseContainerTokenSecretManager.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/security/BaseContainerTokenSecretManager.java @@ -128,7 +128,8 @@ public class BaseContainerTokenSecretManager extends public byte[] createPassword(ContainerTokenIdentifier identifier) { if (LOG.isDebugEnabled()) { LOG.debug("Creating password for " + identifier.getContainerID() - + " to be run on NM " + identifier.getNmHostAddress()); + + " for user " + identifier.getUser() + " to be run on NM " + + identifier.getNmHostAddress()); } this.readLock.lock(); try { @@ -155,7 +156,8 @@ public class BaseContainerTokenSecretManager extends throws org.apache.hadoop.security.token.SecretManager.InvalidToken { if (LOG.isDebugEnabled()) { LOG.debug("Retrieving password for " + identifier.getContainerID() - + " to be run on NM " + identifier.getNmHostAddress()); + + " for user " + identifier.getUser() + " to be run on NM " + + identifier.getNmHostAddress()); } return createPassword(identifier.getBytes(), masterKey.getSecretKey()); } @@ -173,11 +175,12 @@ public class BaseContainerTokenSecretManager extends * * @param containerId * @param nodeId + * @param appSubmitter * @param capability * @return the container-token */ public ContainerToken createContainerToken(ContainerId containerId, - NodeId nodeId, Resource capability) { + NodeId nodeId, String appSubmitter, Resource capability) { byte[] password; ContainerTokenIdentifier tokenIdentifier; long expiryTimeStamp = @@ -188,8 +191,8 @@ public class BaseContainerTokenSecretManager extends try { tokenIdentifier = new ContainerTokenIdentifier(containerId, nodeId.toString(), - capability, expiryTimeStamp, this.currentMasterKey.getMasterKey() - .getKeyId()); + appSubmitter, capability, expiryTimeStamp, this.currentMasterKey + .getMasterKey().getKeyId()); password = this.createPassword(tokenIdentifier); } finally { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java b/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 f9650fbdc2d..7ca6a2cbd32 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java @@ -329,7 +329,6 @@ public class ContainerManagerImpl extends CompositeService implements + remoteUgi.getTokenIdentifiers().size()); } - // Get the tokenId from the remote user ugi ContainerTokenIdentifier tokenId = selectContainerTokenIdentifier(remoteUgi); @@ -341,8 +340,16 @@ public class ContainerManagerImpl extends CompositeService implements + containerIDStr); } else { + // Is the container coming in with correct user-name? + if (!tokenId.getApplicationSubmitter().equals(launchContext.getUser())) { + 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 + // tokens generated off old-secret through? if (!this.context.getContainerTokenSecretManager() .isValidStartContainerRequest(tokenId)) { unauthorized = true; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java index ad28d6c9104..8f631b06042 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java @@ -231,7 +231,6 @@ public class RMAppManager implements EventHandler { RMApp application = null; try { String clientTokenStr = null; - String user = UserGroupInformation.getCurrentUser().getShortUserName(); if (UserGroupInformation.isSecurityEnabled()) { Token clientToken = new Token( @@ -256,11 +255,12 @@ public class RMAppManager implements EventHandler { submissionContext); // Create RMApp - application = new RMAppImpl(applicationId, rmContext, - this.conf, submissionContext.getApplicationName(), user, - submissionContext.getQueue(), submissionContext, clientTokenStr, - appStore, this.scheduler, - this.masterService, submitTime); + application = + new RMAppImpl(applicationId, rmContext, this.conf, + submissionContext.getApplicationName(), + submissionContext.getUser(), submissionContext.getQueue(), + submissionContext, clientTokenStr, appStore, this.scheduler, + this.masterService, submitTime); // Sanity check - duplicate? if (rmContext.getRMApps().putIfAbsent(applicationId, application) != diff --git a/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 b/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 7e7bbeea46d..d222b9061a8 100644 --- a/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 +++ b/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 @@ -1197,7 +1197,7 @@ public class LeafQueue implements CSQueue { if (UserGroupInformation.isSecurityEnabled()) { containerToken = containerTokenSecretManager.createContainerToken(containerId, nodeId, - capability); + application.getUser(), capability); if (containerToken == null) { return null; // Try again later. } diff --git a/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 b/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 7b46d846d2b..3f97c96f457 100644 --- a/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 +++ b/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 @@ -161,7 +161,7 @@ public class AppSchedulable extends Schedulable { if (UserGroupInformation.isSecurityEnabled()) { containerToken = containerTokenSecretManager.createContainerToken(containerId, nodeId, - capability); + application.getUser(), capability); if (containerToken == null) { return null; // Try again later. } diff --git a/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 b/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 aebf989a6e5..a69374c47b6 100644 --- a/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 +++ b/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 @@ -539,7 +539,8 @@ public class FifoScheduler implements ResourceScheduler, Configurable { if (UserGroupInformation.isSecurityEnabled()) { containerToken = this.rmContext.getContainerTokenSecretManager() - .createContainerToken(containerId, nodeId, capability); + .createContainerToken(containerId, nodeId, + application.getUser(), capability); if (containerToken == null) { return i; // Try again later. } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java index 1c7933ae275..0523a3fb89d 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java @@ -219,9 +219,10 @@ public class TestContainerManagerSecurity { // Malice user modifies the resource amount Resource modifiedResource = BuilderUtils.newResource(2048); - ContainerTokenIdentifier modifiedIdentifier = new ContainerTokenIdentifier( - dummyIdentifier.getContainerID(), dummyIdentifier.getNmHostAddress(), - modifiedResource, Long.MAX_VALUE, dummyIdentifier.getMasterKeyId()); + ContainerTokenIdentifier modifiedIdentifier = + new ContainerTokenIdentifier(dummyIdentifier.getContainerID(), + dummyIdentifier.getNmHostAddress(), "testUser", modifiedResource, + Long.MAX_VALUE, dummyIdentifier.getMasterKeyId()); Token modifiedToken = new Token( modifiedIdentifier.getBytes(), containerToken.getPassword().array(), new Text(containerToken.getKind()), new Text(containerToken @@ -320,12 +321,14 @@ public class TestContainerManagerSecurity { callWithIllegalContainerID(client, tokenId); callWithIllegalResource(client, tokenId); + callWithIllegalUserName(client, tokenId); return client; } }); - /////////// End of testing for illegal containerIDs and illegal Resources + // ///////// End of testing for illegal containerIDs, illegal Resources and + // illegal users /////////// Test calls with expired tokens RPC.stopProxy(client); @@ -336,7 +339,7 @@ public class TestContainerManagerSecurity { resourceManager.getRMContainerTokenSecretManager(); final ContainerTokenIdentifier newTokenId = new ContainerTokenIdentifier(tokenId.getContainerID(), - tokenId.getNmHostAddress(), tokenId.getResource(), + tokenId.getNmHostAddress(), "testUser", tokenId.getResource(), System.currentTimeMillis() - 1, containerTokenSecreteManager.getCurrentKey().getKeyId()); byte[] passowrd = @@ -346,9 +349,7 @@ public class TestContainerManagerSecurity { token = new Token( newTokenId.getBytes(), passowrd, new Text( containerToken.getKind()), new Text(containerToken.getService())); - - - + unauthorizedUser.addToken(token); unauthorizedUser.doAs(new PrivilegedAction() { @Override @@ -567,6 +568,29 @@ public class TestContainerManagerSecurity { } } + void callWithIllegalUserName(ContainerManager client, + ContainerTokenIdentifier tokenId) { + 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. + request.setContainerLaunchContext(context); + try { + client.startContainer(request); + fail("Connection initiation with unauthorized " + + "access is expected to fail."); + } catch (YarnRemoteException e) { + LOG.info("Got exception : ", e); + Assert.assertTrue(e.getMessage().contains( + "Unauthorized request to start container. ")); + Assert.assertTrue(e.getMessage().contains( + "Expected user-name " + tokenId.getApplicationSubmitter() + + " but found " + context.getUser())); + } + } + private ContainerLaunchContext createContainerLaunchContextForTest( ContainerTokenIdentifier tokenId) { ContainerLaunchContext context =