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:
parent
9ee38f3a84
commit
f1638fdf94
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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 {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user