Fix NodeManager to verify the application's user-name.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1390825 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Vinod Kumar Vavilapalli 2012-09-27 03:43:57 +00:00
parent 47dfcf45af
commit 40062e1aaa
8 changed files with 68 additions and 25 deletions

View File

@ -48,14 +48,16 @@ public class ContainerTokenIdentifier extends TokenIdentifier {
private ContainerId containerId; private ContainerId containerId;
private String nmHostAddr; private String nmHostAddr;
private String appSubmitter;
private Resource resource; private Resource resource;
private long expiryTimeStamp; private long expiryTimeStamp;
private int masterKeyId; private int masterKeyId;
public ContainerTokenIdentifier(ContainerId containerID, String hostName, public ContainerTokenIdentifier(ContainerId containerID, String hostName,
Resource r, long expiryTimeStamp, int masterKeyId) { String appSubmitter, Resource r, long expiryTimeStamp, int masterKeyId) {
this.containerId = containerID; this.containerId = containerID;
this.nmHostAddr = hostName; this.nmHostAddr = hostName;
this.appSubmitter = appSubmitter;
this.resource = r; this.resource = r;
this.expiryTimeStamp = expiryTimeStamp; this.expiryTimeStamp = expiryTimeStamp;
this.masterKeyId = masterKeyId; this.masterKeyId = masterKeyId;
@ -71,6 +73,10 @@ public class ContainerTokenIdentifier extends TokenIdentifier {
return this.containerId; return this.containerId;
} }
public String getApplicationSubmitter() {
return this.appSubmitter;
}
public String getNmHostAddress() { public String getNmHostAddress() {
return this.nmHostAddr; return this.nmHostAddr;
} }
@ -98,6 +104,7 @@ public class ContainerTokenIdentifier extends TokenIdentifier {
out.writeInt(applicationAttemptId.getAttemptId()); out.writeInt(applicationAttemptId.getAttemptId());
out.writeInt(this.containerId.getId()); out.writeInt(this.containerId.getId());
out.writeUTF(this.nmHostAddr); out.writeUTF(this.nmHostAddr);
out.writeUTF(this.appSubmitter);
out.writeInt(this.resource.getMemory()); out.writeInt(this.resource.getMemory());
out.writeLong(this.expiryTimeStamp); out.writeLong(this.expiryTimeStamp);
out.writeInt(this.masterKeyId); out.writeInt(this.masterKeyId);
@ -112,6 +119,7 @@ public class ContainerTokenIdentifier extends TokenIdentifier {
this.containerId = BuilderUtils.newContainerId(applicationAttemptId, in this.containerId = BuilderUtils.newContainerId(applicationAttemptId, in
.readInt()); .readInt());
this.nmHostAddr = in.readUTF(); this.nmHostAddr = in.readUTF();
this.appSubmitter = in.readUTF();
this.resource = BuilderUtils.newResource(in.readInt()); this.resource = BuilderUtils.newResource(in.readInt());
this.expiryTimeStamp = in.readLong(); this.expiryTimeStamp = in.readLong();
this.masterKeyId = in.readInt(); this.masterKeyId = in.readInt();

View File

@ -128,7 +128,8 @@ public class BaseContainerTokenSecretManager extends
public byte[] createPassword(ContainerTokenIdentifier identifier) { public byte[] createPassword(ContainerTokenIdentifier identifier) {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Creating password for " + identifier.getContainerID() 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(); this.readLock.lock();
try { try {
@ -155,7 +156,8 @@ public class BaseContainerTokenSecretManager extends
throws org.apache.hadoop.security.token.SecretManager.InvalidToken { throws org.apache.hadoop.security.token.SecretManager.InvalidToken {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Retrieving password for " + identifier.getContainerID() 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()); return createPassword(identifier.getBytes(), masterKey.getSecretKey());
} }
@ -173,11 +175,12 @@ public class BaseContainerTokenSecretManager extends
* *
* @param containerId * @param containerId
* @param nodeId * @param nodeId
* @param appSubmitter
* @param capability * @param capability
* @return the container-token * @return the container-token
*/ */
public ContainerToken createContainerToken(ContainerId containerId, public ContainerToken createContainerToken(ContainerId containerId,
NodeId nodeId, Resource capability) { NodeId nodeId, String appSubmitter, Resource capability) {
byte[] password; byte[] password;
ContainerTokenIdentifier tokenIdentifier; ContainerTokenIdentifier tokenIdentifier;
long expiryTimeStamp = long expiryTimeStamp =
@ -188,8 +191,8 @@ public class BaseContainerTokenSecretManager extends
try { try {
tokenIdentifier = tokenIdentifier =
new ContainerTokenIdentifier(containerId, nodeId.toString(), new ContainerTokenIdentifier(containerId, nodeId.toString(),
capability, expiryTimeStamp, this.currentMasterKey.getMasterKey() appSubmitter, capability, expiryTimeStamp, this.currentMasterKey
.getKeyId()); .getMasterKey().getKeyId());
password = this.createPassword(tokenIdentifier); password = this.createPassword(tokenIdentifier);
} finally { } finally {

View File

@ -329,7 +329,6 @@ public class ContainerManagerImpl extends CompositeService implements
+ remoteUgi.getTokenIdentifiers().size()); + remoteUgi.getTokenIdentifiers().size());
} }
// Get the tokenId from the remote user ugi // Get the tokenId from the remote user ugi
ContainerTokenIdentifier tokenId = ContainerTokenIdentifier tokenId =
selectContainerTokenIdentifier(remoteUgi); selectContainerTokenIdentifier(remoteUgi);
@ -341,8 +340,16 @@ public class ContainerManagerImpl extends CompositeService implements
+ containerIDStr); + containerIDStr);
} else { } 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 // 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() if (!this.context.getContainerTokenSecretManager()
.isValidStartContainerRequest(tokenId)) { .isValidStartContainerRequest(tokenId)) {
unauthorized = true; unauthorized = true;

View File

@ -231,7 +231,6 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent> {
RMApp application = null; RMApp application = null;
try { try {
String clientTokenStr = null; String clientTokenStr = null;
String user = UserGroupInformation.getCurrentUser().getShortUserName();
if (UserGroupInformation.isSecurityEnabled()) { if (UserGroupInformation.isSecurityEnabled()) {
Token<ClientTokenIdentifier> clientToken = new Token<ClientTokenIdentifier> clientToken = new
Token<ClientTokenIdentifier>( Token<ClientTokenIdentifier>(
@ -256,11 +255,12 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent> {
submissionContext); submissionContext);
// Create RMApp // Create RMApp
application = new RMAppImpl(applicationId, rmContext, application =
this.conf, submissionContext.getApplicationName(), user, new RMAppImpl(applicationId, rmContext, this.conf,
submissionContext.getQueue(), submissionContext, clientTokenStr, submissionContext.getApplicationName(),
appStore, this.scheduler, submissionContext.getUser(), submissionContext.getQueue(),
this.masterService, submitTime); submissionContext, clientTokenStr, appStore, this.scheduler,
this.masterService, submitTime);
// Sanity check - duplicate? // Sanity check - duplicate?
if (rmContext.getRMApps().putIfAbsent(applicationId, application) != if (rmContext.getRMApps().putIfAbsent(applicationId, application) !=

View File

@ -1197,7 +1197,7 @@ public class LeafQueue implements CSQueue {
if (UserGroupInformation.isSecurityEnabled()) { if (UserGroupInformation.isSecurityEnabled()) {
containerToken = containerToken =
containerTokenSecretManager.createContainerToken(containerId, nodeId, containerTokenSecretManager.createContainerToken(containerId, nodeId,
capability); application.getUser(), capability);
if (containerToken == null) { if (containerToken == null) {
return null; // Try again later. return null; // Try again later.
} }

View File

@ -161,7 +161,7 @@ public class AppSchedulable extends Schedulable {
if (UserGroupInformation.isSecurityEnabled()) { if (UserGroupInformation.isSecurityEnabled()) {
containerToken = containerToken =
containerTokenSecretManager.createContainerToken(containerId, nodeId, containerTokenSecretManager.createContainerToken(containerId, nodeId,
capability); application.getUser(), capability);
if (containerToken == null) { if (containerToken == null) {
return null; // Try again later. return null; // Try again later.
} }

View File

@ -539,7 +539,8 @@ public class FifoScheduler implements ResourceScheduler, Configurable {
if (UserGroupInformation.isSecurityEnabled()) { if (UserGroupInformation.isSecurityEnabled()) {
containerToken = containerToken =
this.rmContext.getContainerTokenSecretManager() this.rmContext.getContainerTokenSecretManager()
.createContainerToken(containerId, nodeId, capability); .createContainerToken(containerId, nodeId,
application.getUser(), capability);
if (containerToken == null) { if (containerToken == null) {
return i; // Try again later. return i; // Try again later.
} }

View File

@ -219,9 +219,10 @@ public class TestContainerManagerSecurity {
// Malice user modifies the resource amount // Malice user modifies the resource amount
Resource modifiedResource = BuilderUtils.newResource(2048); Resource modifiedResource = BuilderUtils.newResource(2048);
ContainerTokenIdentifier modifiedIdentifier = new ContainerTokenIdentifier( ContainerTokenIdentifier modifiedIdentifier =
dummyIdentifier.getContainerID(), dummyIdentifier.getNmHostAddress(), new ContainerTokenIdentifier(dummyIdentifier.getContainerID(),
modifiedResource, Long.MAX_VALUE, dummyIdentifier.getMasterKeyId()); dummyIdentifier.getNmHostAddress(), "testUser", modifiedResource,
Long.MAX_VALUE, dummyIdentifier.getMasterKeyId());
Token<ContainerTokenIdentifier> modifiedToken = new Token<ContainerTokenIdentifier>( Token<ContainerTokenIdentifier> modifiedToken = new Token<ContainerTokenIdentifier>(
modifiedIdentifier.getBytes(), containerToken.getPassword().array(), modifiedIdentifier.getBytes(), containerToken.getPassword().array(),
new Text(containerToken.getKind()), new Text(containerToken new Text(containerToken.getKind()), new Text(containerToken
@ -320,12 +321,14 @@ public class TestContainerManagerSecurity {
callWithIllegalContainerID(client, tokenId); callWithIllegalContainerID(client, tokenId);
callWithIllegalResource(client, tokenId); callWithIllegalResource(client, tokenId);
callWithIllegalUserName(client, tokenId);
return client; 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 /////////// Test calls with expired tokens
RPC.stopProxy(client); RPC.stopProxy(client);
@ -336,7 +339,7 @@ public class TestContainerManagerSecurity {
resourceManager.getRMContainerTokenSecretManager(); resourceManager.getRMContainerTokenSecretManager();
final ContainerTokenIdentifier newTokenId = final ContainerTokenIdentifier newTokenId =
new ContainerTokenIdentifier(tokenId.getContainerID(), new ContainerTokenIdentifier(tokenId.getContainerID(),
tokenId.getNmHostAddress(), tokenId.getResource(), tokenId.getNmHostAddress(), "testUser", tokenId.getResource(),
System.currentTimeMillis() - 1, System.currentTimeMillis() - 1,
containerTokenSecreteManager.getCurrentKey().getKeyId()); containerTokenSecreteManager.getCurrentKey().getKeyId());
byte[] passowrd = byte[] passowrd =
@ -346,9 +349,7 @@ public class TestContainerManagerSecurity {
token = new Token<ContainerTokenIdentifier>( token = new Token<ContainerTokenIdentifier>(
newTokenId.getBytes(), passowrd, new Text( newTokenId.getBytes(), passowrd, new Text(
containerToken.getKind()), new Text(containerToken.getService())); containerToken.getKind()), new Text(containerToken.getService()));
unauthorizedUser.addToken(token); unauthorizedUser.addToken(token);
unauthorizedUser.doAs(new PrivilegedAction<Void>() { unauthorizedUser.doAs(new PrivilegedAction<Void>() {
@Override @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( private ContainerLaunchContext createContainerLaunchContextForTest(
ContainerTokenIdentifier tokenId) { ContainerTokenIdentifier tokenId) {
ContainerLaunchContext context = ContainerLaunchContext context =