YARN-707. Add user info in the YARN ClientToken. Contributed by Vinod Kumar Vavilapalli

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1517073 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jason Darrell Lowe 2013-08-23 22:11:54 +00:00
parent 9ee38f3a84
commit f1638fdf94
5 changed files with 63 additions and 22 deletions

View File

@ -43,6 +43,8 @@ Release 2.1.1-beta - UNRELEASED
YARN-589. Expose a REST API for monitoring the fair scheduler (Sandy Ryza). YARN-589. Expose a REST API for monitoring the fair scheduler (Sandy Ryza).
YARN-707. Add user info in the YARN ClientToken (vinodkv via jlowe)
OPTIMIZATIONS OPTIMIZATIONS
BUG FIXES BUG FIXES

View File

@ -39,6 +39,7 @@ public class ClientToAMTokenIdentifier extends TokenIdentifier {
public static final Text KIND_NAME = new Text("YARN_CLIENT_TOKEN"); public static final Text KIND_NAME = new Text("YARN_CLIENT_TOKEN");
private ApplicationAttemptId applicationAttemptId; private ApplicationAttemptId applicationAttemptId;
private Text applicationSubmitter = new Text();
// TODO: Add more information in the tokenID such that it is not // TODO: Add more information in the tokenID such that it is not
// transferrable, more secure etc. // transferrable, more secure etc.
@ -46,21 +47,27 @@ public class ClientToAMTokenIdentifier extends TokenIdentifier {
public ClientToAMTokenIdentifier() { public ClientToAMTokenIdentifier() {
} }
public ClientToAMTokenIdentifier(ApplicationAttemptId id) { public ClientToAMTokenIdentifier(ApplicationAttemptId id, String appSubmitter) {
this(); this();
this.applicationAttemptId = id; this.applicationAttemptId = id;
this.applicationSubmitter = new Text(appSubmitter);
} }
public ApplicationAttemptId getApplicationAttemptID() { public ApplicationAttemptId getApplicationAttemptID() {
return this.applicationAttemptId; return this.applicationAttemptId;
} }
public String getApplicationSubmitter() {
return this.applicationSubmitter.toString();
}
@Override @Override
public void write(DataOutput out) throws IOException { public void write(DataOutput out) throws IOException {
out.writeLong(this.applicationAttemptId.getApplicationId() out.writeLong(this.applicationAttemptId.getApplicationId()
.getClusterTimestamp()); .getClusterTimestamp());
out.writeInt(this.applicationAttemptId.getApplicationId().getId()); out.writeInt(this.applicationAttemptId.getApplicationId().getId());
out.writeInt(this.applicationAttemptId.getAttemptId()); out.writeInt(this.applicationAttemptId.getAttemptId());
this.applicationSubmitter.write(out);
} }
@Override @Override
@ -68,6 +75,7 @@ public void readFields(DataInput in) throws IOException {
this.applicationAttemptId = this.applicationAttemptId =
ApplicationAttemptId.newInstance( ApplicationAttemptId.newInstance(
ApplicationId.newInstance(in.readLong(), in.readInt()), in.readInt()); ApplicationId.newInstance(in.readLong(), in.readInt()), in.readInt());
this.applicationSubmitter.readFields(in);
} }
@Override @Override
@ -77,10 +85,11 @@ public Text getKind() {
@Override @Override
public UserGroupInformation getUser() { public UserGroupInformation getUser() {
if (this.applicationAttemptId == null) { if (this.applicationSubmitter == null) {
return null; return null;
} }
return UserGroupInformation.createRemoteUser(this.applicationAttemptId.toString()); return UserGroupInformation.createRemoteUser(this.applicationSubmitter
.toString());
} }
@InterfaceAudience.Private @InterfaceAudience.Private

View File

@ -722,7 +722,7 @@ public void transition(RMAppAttemptImpl appAttempt,
// create clientToAMToken // create clientToAMToken
appAttempt.clientToAMToken = appAttempt.clientToAMToken =
new Token<ClientToAMTokenIdentifier>(new ClientToAMTokenIdentifier( new Token<ClientToAMTokenIdentifier>(new ClientToAMTokenIdentifier(
appAttempt.applicationAttemptId), appAttempt.applicationAttemptId, appAttempt.user),
appAttempt.rmContext.getClientToAMTokenSecretManager()); appAttempt.rmContext.getClientToAMTokenSecretManager());
} }

View File

@ -367,7 +367,7 @@ private List<Token<?>> generateTokens(ApplicationAttemptId attemptId,
appToken.setService(new Text("appToken service")); appToken.setService(new Text("appToken service"));
ClientToAMTokenIdentifier clientToAMTokenId = ClientToAMTokenIdentifier clientToAMTokenId =
new ClientToAMTokenIdentifier(attemptId); new ClientToAMTokenIdentifier(attemptId, "user");
clientToAMTokenMgr.registerApplication(attemptId); clientToAMTokenMgr.registerApplication(attemptId);
Token<ClientToAMTokenIdentifier> clientToAMToken = Token<ClientToAMTokenIdentifier> clientToAMToken =
new Token<ClientToAMTokenIdentifier>(clientToAMTokenId, clientToAMTokenMgr); new Token<ClientToAMTokenIdentifier>(clientToAMTokenId, clientToAMTokenMgr);

View File

@ -115,7 +115,6 @@ private static class CustomAM extends AbstractService implements
private final byte[] secretKey; private final byte[] secretKey;
private InetSocketAddress address; private InetSocketAddress address;
private boolean pinged = false; private boolean pinged = false;
private ClientToAMTokenSecretManager secretManager;
public CustomAM(ApplicationAttemptId appId, byte[] secretKey) { public CustomAM(ApplicationAttemptId appId, byte[] secretKey) {
super("CustomAM"); super("CustomAM");
@ -132,12 +131,14 @@ public void ping() throws YarnException, IOException {
protected void serviceStart() throws Exception { protected void serviceStart() throws Exception {
Configuration conf = getConfig(); Configuration conf = getConfig();
secretManager = new ClientToAMTokenSecretManager(this.appAttemptId, secretKey);
Server server; Server server;
try { try {
server = server =
new RPC.Builder(conf).setProtocol(CustomProtocol.class) new RPC.Builder(conf)
.setNumHandlers(1).setSecretManager(secretManager) .setProtocol(CustomProtocol.class)
.setNumHandlers(1)
.setSecretManager(
new ClientToAMTokenSecretManager(this.appAttemptId, secretKey))
.setInstance(this).build(); .setInstance(this).build();
} catch (Exception e) { } catch (Exception e) {
throw new YarnRuntimeException(e); throw new YarnRuntimeException(e);
@ -146,14 +147,10 @@ protected void serviceStart() throws Exception {
this.address = NetUtils.getConnectAddress(server); this.address = NetUtils.getConnectAddress(server);
super.serviceStart(); super.serviceStart();
} }
public ClientToAMTokenSecretManager getClientToAMTokenSecretManager() {
return this.secretManager;
}
} }
@Test @Test
public void testClientToAMs() throws Exception { public void testClientToAMTokenss() throws Exception {
final Configuration conf = new Configuration(); final Configuration conf = new Configuration();
conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION,
@ -204,7 +201,7 @@ protected void doSecureLogin() throws IOException {
GetApplicationReportResponse reportResponse = GetApplicationReportResponse reportResponse =
rm.getClientRMService().getApplicationReport(request); rm.getClientRMService().getApplicationReport(request);
ApplicationReport appReport = reportResponse.getApplicationReport(); ApplicationReport appReport = reportResponse.getApplicationReport();
org.apache.hadoop.yarn.api.records.Token clientToAMToken = org.apache.hadoop.yarn.api.records.Token originalClientToAMToken =
appReport.getClientToAMToken(); appReport.getClientToAMToken();
ApplicationAttemptId appAttempt = app.getCurrentAppAttempt().getAppAttemptId(); ApplicationAttemptId appAttempt = app.getCurrentAppAttempt().getAppAttemptId();
@ -259,17 +256,47 @@ public RegisterApplicationMasterResponse run() {
Assert.assertFalse(am.pinged); Assert.assertFalse(am.pinged);
} }
// Verify denial for a malicious user
UserGroupInformation ugi = UserGroupInformation.createRemoteUser("me");
Token<ClientToAMTokenIdentifier> token = Token<ClientToAMTokenIdentifier> token =
ConverterUtils.convertFromYarn(clientToAMToken, am.address); ConverterUtils.convertFromYarn(originalClientToAMToken, am.address);
// Verify denial for a malicious user with tampered ID
verifyTokenWithTamperedID(conf, am, token);
// Verify denial for a malicious user with tampered user-name
verifyTokenWithTamperedUserName(conf, am, token);
// Now for an authenticated user
verifyValidToken(conf, am, token);
}
private void verifyTokenWithTamperedID(final Configuration conf,
final CustomAM am, Token<ClientToAMTokenIdentifier> token)
throws IOException {
// Malicious user, messes with appId // Malicious user, messes with appId
UserGroupInformation ugi = UserGroupInformation.createRemoteUser("me");
ClientToAMTokenIdentifier maliciousID = ClientToAMTokenIdentifier maliciousID =
new ClientToAMTokenIdentifier(BuilderUtils.newApplicationAttemptId( new ClientToAMTokenIdentifier(BuilderUtils.newApplicationAttemptId(
BuilderUtils.newApplicationId(app.getApplicationId() BuilderUtils.newApplicationId(am.appAttemptId.getApplicationId()
.getClusterTimestamp(), 42), 43)); .getClusterTimestamp(), 42), 43), UserGroupInformation
.getCurrentUser().getShortUserName());
verifyTamperedToken(conf, am, token, ugi, maliciousID);
}
private void verifyTokenWithTamperedUserName(final Configuration conf,
final CustomAM am, Token<ClientToAMTokenIdentifier> token)
throws IOException {
// Malicious user, messes with appId
UserGroupInformation ugi = UserGroupInformation.createRemoteUser("me");
ClientToAMTokenIdentifier maliciousID =
new ClientToAMTokenIdentifier(am.appAttemptId, "evilOrc");
verifyTamperedToken(conf, am, token, ugi, maliciousID);
}
private void verifyTamperedToken(final Configuration conf, final CustomAM am,
Token<ClientToAMTokenIdentifier> token, UserGroupInformation ugi,
ClientToAMTokenIdentifier maliciousID) {
Token<ClientToAMTokenIdentifier> maliciousToken = Token<ClientToAMTokenIdentifier> maliciousToken =
new Token<ClientToAMTokenIdentifier>(maliciousID.getBytes(), new Token<ClientToAMTokenIdentifier>(maliciousID.getBytes(),
token.getPassword(), token.getKind(), token.getPassword(), token.getKind(),
@ -309,8 +336,12 @@ public Void run() throws Exception {
+ "Mismatched response.")); + "Mismatched response."));
Assert.assertFalse(am.pinged); Assert.assertFalse(am.pinged);
} }
}
// Now for an authenticated user private void verifyValidToken(final Configuration conf, final CustomAM am,
Token<ClientToAMTokenIdentifier> token) throws IOException,
InterruptedException {
UserGroupInformation ugi;
ugi = UserGroupInformation.createRemoteUser("me"); ugi = UserGroupInformation.createRemoteUser("me");
ugi.addToken(token); ugi.addToken(token);
@ -326,5 +357,4 @@ public Void run() throws Exception {
} }
}); });
} }
} }