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:
parent
47dfcf45af
commit
40062e1aaa
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -231,7 +231,6 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent> {
|
|||
RMApp application = null;
|
||||
try {
|
||||
String clientTokenStr = null;
|
||||
String user = UserGroupInformation.getCurrentUser().getShortUserName();
|
||||
if (UserGroupInformation.isSecurityEnabled()) {
|
||||
Token<ClientTokenIdentifier> clientToken = new
|
||||
Token<ClientTokenIdentifier>(
|
||||
|
@ -256,10 +255,11 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent> {
|
|||
submissionContext);
|
||||
|
||||
// Create RMApp
|
||||
application = new RMAppImpl(applicationId, rmContext,
|
||||
this.conf, submissionContext.getApplicationName(), user,
|
||||
submissionContext.getQueue(), submissionContext, clientTokenStr,
|
||||
appStore, this.scheduler,
|
||||
application =
|
||||
new RMAppImpl(applicationId, rmContext, this.conf,
|
||||
submissionContext.getApplicationName(),
|
||||
submissionContext.getUser(), submissionContext.getQueue(),
|
||||
submissionContext, clientTokenStr, appStore, this.scheduler,
|
||||
this.masterService, submitTime);
|
||||
|
||||
// Sanity check - duplicate?
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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<ContainerTokenIdentifier> modifiedToken = new Token<ContainerTokenIdentifier>(
|
||||
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 =
|
||||
|
@ -347,8 +350,6 @@ public class TestContainerManagerSecurity {
|
|||
newTokenId.getBytes(), passowrd, new Text(
|
||||
containerToken.getKind()), new Text(containerToken.getService()));
|
||||
|
||||
|
||||
|
||||
unauthorizedUser.addToken(token);
|
||||
unauthorizedUser.doAs(new PrivilegedAction<Void>() {
|
||||
@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 =
|
||||
|
|
Loading…
Reference in New Issue