diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/AppContext.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/AppContext.java index f08e437..946d9c6 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/AppContext.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/AppContext.java @@ -27,6 +27,7 @@ import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.event.EventHandler; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenSecretManager; import org.apache.hadoop.yarn.util.Clock; @@ -58,4 +59,6 @@ ClusterInfo getClusterInfo(); Set getBlacklistedNodes(); + + ClientToAMTokenSecretManager getClientToAMTokenSecretManager(); } diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/MRAppMaster.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/MRAppMaster.java index da0ca66..1d17dbb 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/MRAppMaster.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/MRAppMaster.java @@ -128,6 +128,7 @@ import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; import org.apache.hadoop.yarn.security.ApplicationTokenIdentifier; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenSecretManager; import org.apache.hadoop.yarn.util.Clock; import org.apache.hadoop.yarn.util.ConverterUtils; import org.apache.hadoop.yarn.util.SystemClock; @@ -884,9 +885,12 @@ protected void serviceStop() throws Exception { private final Map jobs = new ConcurrentHashMap(); private final Configuration conf; private final ClusterInfo clusterInfo = new ClusterInfo(); + private final ClientToAMTokenSecretManager clientToAMTokenSecretManager; public RunningAppContext(Configuration config) { this.conf = config; + this.clientToAMTokenSecretManager = + new ClientToAMTokenSecretManager(appAttemptID, null); } @Override @@ -943,6 +947,11 @@ public ClusterInfo getClusterInfo() { public Set getBlacklistedNodes() { return ((RMContainerRequestor) containerAllocator).getBlacklistedNodes(); } + + @Override + public ClientToAMTokenSecretManager getClientToAMTokenSecretManager() { + return clientToAMTokenSecretManager; + } } @SuppressWarnings("unchecked") diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/MRClientSecurityInfo.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/MRClientSecurityInfo.java index 2b8efea..b4ed52f 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/MRClientSecurityInfo.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/MRClientSecurityInfo.java @@ -27,7 +27,7 @@ import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.security.token.TokenInfo; import org.apache.hadoop.security.token.TokenSelector; -import org.apache.hadoop.yarn.security.client.ClientTokenSelector; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenSelector; public class MRClientSecurityInfo extends SecurityInfo { @@ -51,7 +51,7 @@ public TokenInfo getTokenInfo(Class protocol, Configuration conf) { @Override public Class> value() { - return ClientTokenSelector.class; + return ClientToAMTokenSelector.class; } }; } diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/client/MRClientService.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/client/MRClientService.java index 58e5504..4bb3969 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/client/MRClientService.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/client/MRClientService.java @@ -23,7 +23,6 @@ import java.util.Arrays; import java.util.Collection; -import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -79,14 +78,11 @@ import org.apache.hadoop.mapreduce.v2.app.security.authorize.MRAMPolicyProvider; import org.apache.hadoop.mapreduce.v2.app.webapp.AMWebApp; import org.apache.hadoop.net.NetUtils; -import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authorize.PolicyProvider; import org.apache.hadoop.service.AbstractService; -import org.apache.hadoop.yarn.api.ApplicationConstants; import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; import org.apache.hadoop.yarn.ipc.YarnRPC; -import org.apache.hadoop.yarn.security.client.ClientToAMTokenSecretManager; import org.apache.hadoop.yarn.webapp.WebApp; import org.apache.hadoop.yarn.webapp.WebApps; @@ -117,19 +113,9 @@ protected void serviceStart() throws Exception { YarnRPC rpc = YarnRPC.create(conf); InetSocketAddress address = new InetSocketAddress(0); - ClientToAMTokenSecretManager secretManager = null; - if (UserGroupInformation.isSecurityEnabled()) { - String secretKeyStr = - System - .getenv(ApplicationConstants.APPLICATION_CLIENT_SECRET_ENV_NAME); - byte[] bytes = Base64.decodeBase64(secretKeyStr); - secretManager = - new ClientToAMTokenSecretManager( - this.appContext.getApplicationAttemptId(), bytes); - } server = rpc.getServer(MRClientProtocol.class, protocolHandler, address, - conf, secretManager, + conf, appContext.getClientToAMTokenSecretManager(), conf.getInt(MRJobConfig.MR_AM_JOB_CLIENT_THREAD_COUNT, MRJobConfig.DEFAULT_MR_AM_JOB_CLIENT_THREAD_COUNT), MRJobConfig.MR_AM_JOB_CLIENT_PORT_RANGE); diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/rm/RMCommunicator.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/rm/RMCommunicator.java index a4459d1..fb2cca3 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/rm/RMCommunicator.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/rm/RMCommunicator.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.net.InetSocketAddress; +import java.nio.ByteBuffer; import java.security.PrivilegedAction; import java.util.Map; import java.util.concurrent.ConcurrentLinkedQueue; @@ -154,6 +155,9 @@ protected void register() { maxContainerCapability = response.getMaximumResourceCapability(); this.context.getClusterInfo().setMaxContainerCapability( maxContainerCapability); + if (UserGroupInformation.isSecurityEnabled()) { + setClientToAMToken(response.getClientToAMTokenMasterKey()); + } this.applicationACLs = response.getApplicationACLs(); LOG.info("maxContainerCapability: " + maxContainerCapability.getMemory()); } catch (Exception are) { @@ -162,6 +166,11 @@ protected void register() { } } + private void setClientToAMToken(ByteBuffer clientToAMTokenMasterKey) { + byte[] key = clientToAMTokenMasterKey.array(); + context.getClientToAMTokenSecretManager().setMasterKey(key); + } + protected void unregister() { try { FinalApplicationStatus finishState = FinalApplicationStatus.UNDEFINED; diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/MockAppContext.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/MockAppContext.java index 16f5e91..f4fc42f 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/MockAppContext.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/MockAppContext.java @@ -28,6 +28,7 @@ import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.util.Clock; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenSecretManager; import com.google.common.collect.Maps; @@ -125,4 +126,8 @@ public void setBlacklistedNodes(Set blacklistedNodes) { this.blacklistedNodes = blacklistedNodes; } + public ClientToAMTokenSecretManager getClientToAMTokenSecretManager() { + // Not implemented + return null; + } } diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/TestRuntimeEstimators.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/TestRuntimeEstimators.java index 985955c..1c450fb 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/TestRuntimeEstimators.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/TestRuntimeEstimators.java @@ -72,6 +72,7 @@ import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenSecretManager; import org.apache.hadoop.yarn.util.Clock; import org.apache.hadoop.yarn.util.SystemClock; import org.junit.Assert; @@ -855,5 +856,10 @@ public ClusterInfo getClusterInfo() { public Set getBlacklistedNodes() { return null; } + + public ClientToAMTokenSecretManager getClientToAMTokenSecretManager() { + // Not Implemented + return null; + } } } diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/JobHistory.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/JobHistory.java index 9a95394..2c1f3a2 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/JobHistory.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/JobHistory.java @@ -47,6 +47,7 @@ import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenSecretManager; import org.apache.hadoop.yarn.util.Clock; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -306,6 +307,12 @@ public ClusterInfo getClusterInfo() { // TODO AppContext - Not Required @Override public Set getBlacklistedNodes() { + // Not Implemented + return null; + } + @Override + public ClientToAMTokenSecretManager getClientToAMTokenSecretManager() { + // Not implemented. return null; } } diff --git hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ClientServiceDelegate.java hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ClientServiceDelegate.java index 6620e73..b57e82f 100644 --- hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ClientServiceDelegate.java +++ hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ClientServiceDelegate.java @@ -74,7 +74,7 @@ import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; import org.apache.hadoop.yarn.ipc.YarnRPC; -import org.apache.hadoop.yarn.security.client.ClientTokenIdentifier; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenIdentifier; import org.apache.hadoop.yarn.util.ProtoUtils; public class ClientServiceDelegate { @@ -180,8 +180,9 @@ private MRClientProtocol getProxy() throws IOException { serviceAddr = NetUtils.createSocketAddrForHost( application.getHost(), application.getRpcPort()); if (UserGroupInformation.isSecurityEnabled()) { - org.apache.hadoop.yarn.api.records.Token clientToken = application.getClientToken(); - Token token = + org.apache.hadoop.yarn.api.records.Token clientToken = + application.getClientToAMToken(); + Token token = ProtoUtils.convertFromProtoFormat(clientToken, serviceAddr); newUgi.addToken(token); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationConstants.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationConstants.java index 9600142..a5d99a7 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationConstants.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationConstants.java @@ -28,10 +28,6 @@ * TODO: Investigate the semantics and security of each cross-boundary refs. */ public interface ApplicationConstants { - - // TODO: They say tokens via env isn't good. - public static final String APPLICATION_CLIENT_SECRET_ENV_NAME = - "AppClientSecretEnv"; /** * The environment variable for APP_SUBMIT_TIME. Set in AppMaster environment diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/RegisterApplicationMasterResponse.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/RegisterApplicationMasterResponse.java index 15504d2..94b0dae 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/RegisterApplicationMasterResponse.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/RegisterApplicationMasterResponse.java @@ -18,6 +18,7 @@ package org.apache.hadoop.yarn.api.protocolrecords; +import java.nio.ByteBuffer; import java.util.Map; import org.apache.hadoop.classification.InterfaceAudience.Private; @@ -84,4 +85,18 @@ public static RegisterApplicationMasterResponse newInstance( @Private @Unstable public abstract void setApplicationACLs(Map acls); + + /** + * Set ClientToAMToken master key. + */ + @Public + @Stable + public abstract void setClientToAMTokenMasterKey(ByteBuffer key); + + /** + * Get ClientToAMToken master key. + */ + @Public + @Stable + public abstract ByteBuffer getClientToAMTokenMasterKey(); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/RegisterApplicationMasterResponsePBImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/RegisterApplicationMasterResponsePBImpl.java index cca989b..fefae93 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/RegisterApplicationMasterResponsePBImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/RegisterApplicationMasterResponsePBImpl.java @@ -19,6 +19,7 @@ package org.apache.hadoop.yarn.api.protocolrecords.impl.pb; +import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -34,6 +35,8 @@ import org.apache.hadoop.yarn.proto.YarnServiceProtos.RegisterApplicationMasterResponseProtoOrBuilder; import org.apache.hadoop.yarn.util.ProtoUtils; +import com.google.protobuf.ByteString; + public class RegisterApplicationMasterResponsePBImpl extends RegisterApplicationMasterResponse { @@ -200,7 +203,23 @@ public void setApplicationACLs( this.applicationACLS.clear(); this.applicationACLS.putAll(appACLs); } - + + @Override + public void setClientToAMTokenMasterKey(ByteBuffer key) { + if (key == null) { + return; + } + maybeInitBuilder(); + builder.setClientToAmTokenMasterKey(ByteString.copyFrom(key)); + } + + @Override + public ByteBuffer getClientToAMTokenMasterKey() { + ByteBuffer key = + ByteBuffer.wrap(builder.getClientToAmTokenMasterKey().toByteArray()); + return key; + } + private Resource convertFromProtoFormat(ResourceProto resource) { return new ResourcePBImpl(resource); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ApplicationReport.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ApplicationReport.java index 500eea8..ce11dbe 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ApplicationReport.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ApplicationReport.java @@ -54,7 +54,7 @@ @Stable public static ApplicationReport newInstance(ApplicationId applicationId, ApplicationAttemptId applicationAttemptId, String user, String queue, - String name, String host, int rpcPort, Token clientToken, + String name, String host, int rpcPort, Token clientToAMToken, YarnApplicationState state, String diagnostics, String url, long startTime, long finishTime, FinalApplicationStatus finalStatus, ApplicationResourceUsageReport appResources, String origTrackingUrl, @@ -67,7 +67,7 @@ public static ApplicationReport newInstance(ApplicationId applicationId, report.setName(name); report.setHost(host); report.setRpcPort(rpcPort); - report.setClientToken(clientToken); + report.setClientToAMToken(clientToAMToken); report.setYarnApplicationState(state); report.setDiagnostics(diagnostics); report.setTrackingUrl(url); @@ -172,13 +172,13 @@ public static ApplicationReport newInstance(ApplicationId applicationId, * Get the client token for communicating with the * ApplicationMaster. *

- * ClientToken is the security token used by the AMs to verify + * ClientToAMToken is the security token used by the AMs to verify * authenticity of any client. *

* *

* The ResourceManager, provides a secure token (via - * {@link ApplicationReport#getClientToken()}) which is verified by the + * {@link ApplicationReport#getClientToAMToken()}) which is verified by the * ApplicationMaster when the client directly talks to an AM. *

* @return client token for communicating with the @@ -186,11 +186,11 @@ public static ApplicationReport newInstance(ApplicationId applicationId, */ @Public @Stable - public abstract Token getClientToken(); + public abstract Token getClientToAMToken(); @Private @Unstable - public abstract void setClientToken(Token clientToken); + public abstract void setClientToAMToken(Token clientToAMToken); /** * Get the YarnApplicationState of the application. diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/ApplicationReportPBImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/ApplicationReportPBImpl.java index ad8a791..d0da50d 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/ApplicationReportPBImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/ApplicationReportPBImpl.java @@ -42,7 +42,7 @@ private ApplicationId applicationId; private ApplicationAttemptId currentApplicationAttemptId; - private Token clientToken = null; + private Token clientToAMToken = null; public ApplicationReportPBImpl() { builder = ApplicationReportProto.newBuilder(); @@ -160,16 +160,16 @@ public int getRpcPort() { } @Override - public Token getClientToken() { + public Token getClientToAMToken() { ApplicationReportProtoOrBuilder p = viaProto ? proto : builder; - if (this.clientToken != null) { - return this.clientToken; + if (this.clientToAMToken != null) { + return this.clientToAMToken; } - if (!p.hasClientToken()) { + if (!p.hasClientToAmToken()) { return null; } - this.clientToken = convertFromProtoFormat(p.getClientToken()); - return this.clientToken; + this.clientToAMToken = convertFromProtoFormat(p.getClientToAmToken()); + return this.clientToAMToken; } @Override @@ -309,11 +309,11 @@ public void setRpcPort(int rpcPort) { } @Override - public void setClientToken(Token clientToken) { + public void setClientToAMToken(Token clientToAMToken) { maybeInitBuilder(); - if (clientToken == null) - builder.clearClientToken(); - this.clientToken = clientToken; + if (clientToAMToken == null) + builder.clearClientToAmToken(); + this.clientToAMToken = clientToAMToken; } @Override @@ -412,10 +412,10 @@ private void mergeLocalToBuilder() { builder.getCurrentApplicationAttemptId())) { builder.setCurrentApplicationAttemptId(convertToProtoFormat(this.currentApplicationAttemptId)); } - if (this.clientToken != null - && !((TokenPBImpl) this.clientToken).getProto().equals( - builder.getClientToken())) { - builder.setClientToken(convertToProtoFormat(this.clientToken)); + if (this.clientToAMToken != null + && !((TokenPBImpl) this.clientToAMToken).getProto().equals( + builder.getClientToAmToken())) { + builder.setClientToAmToken(convertToProtoFormat(this.clientToAMToken)); } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_protos.proto hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_protos.proto index acc9c27..f8709b5 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_protos.proto +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_protos.proto @@ -131,7 +131,7 @@ message ApplicationReportProto { optional string name = 4; optional string host = 5; optional int32 rpc_port = 6; - optional hadoop.common.TokenProto client_token = 7; + optional hadoop.common.TokenProto client_to_am_token = 7; optional YarnApplicationStateProto yarn_application_state = 8; optional string trackingUrl = 9; optional string diagnostics = 10 [default = "N/A"]; diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto index 81a7d95..dc2b100 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto @@ -36,7 +36,8 @@ message RegisterApplicationMasterRequestProto { message RegisterApplicationMasterResponseProto { optional ResourceProto maximumCapability = 1; - repeated ApplicationACLMapProto application_ACLs = 2; + optional bytes client_to_am_token_master_key = 2; + repeated ApplicationACLMapProto application_ACLs = 3; } message FinishApplicationMasterRequestProto { diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/Client.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/Client.java index 392b07c..6046612 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/Client.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/Client.java @@ -601,7 +601,7 @@ private boolean monitorApplication(ApplicationId appId) LOG.info("Got application report from ASM for" + ", appId=" + appId.getId() - + ", clientToken=" + report.getClientToken() + + ", clientToAMToken=" + report.getClientToAMToken() + ", appDiagnostics=" + report.getDiagnostics() + ", appMasterHost=" + report.getHost() + ", appQueue=" + report.getQueue() diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-unmanaged-am-launcher/src/main/java/org/apache/hadoop/yarn/applications/unmanagedamlauncher/UnmanagedAMLauncher.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-unmanaged-am-launcher/src/main/java/org/apache/hadoop/yarn/applications/unmanagedamlauncher/UnmanagedAMLauncher.java index 5a7892d..275df8d 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-unmanaged-am-launcher/src/main/java/org/apache/hadoop/yarn/applications/unmanagedamlauncher/UnmanagedAMLauncher.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-unmanaged-am-launcher/src/main/java/org/apache/hadoop/yarn/applications/unmanagedamlauncher/UnmanagedAMLauncher.java @@ -388,8 +388,8 @@ private ApplicationReport monitorApplication(ApplicationId appId, LOG.info("Got application report from ASM for" + ", appId=" + appId.getId() + ", appAttemptId=" - + report.getCurrentApplicationAttemptId() + ", clientToken=" - + report.getClientToken() + ", appDiagnostics=" + + report.getCurrentApplicationAttemptId() + ", clientToAMToken=" + + report.getClientToAMToken() + ", appDiagnostics=" + report.getDiagnostics() + ", appMasterHost=" + report.getHost() + ", appQueue=" + report.getQueue() + ", appMasterRpcPort=" + report.getRpcPort() + ", appStartTime=" + report.getStartTime() diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/BaseClientToAMTokenSecretManager.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/BaseClientToAMTokenSecretManager.java index 41a8401..c455aac 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/BaseClientToAMTokenSecretManager.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/BaseClientToAMTokenSecretManager.java @@ -36,7 +36,7 @@ @Public @Evolving public abstract class BaseClientToAMTokenSecretManager extends - SecretManager { + SecretManager { @Private public abstract SecretKey getMasterKey( @@ -45,14 +45,14 @@ public abstract SecretKey getMasterKey( @Private @Override public synchronized byte[] createPassword( - ClientTokenIdentifier identifier) { + ClientToAMTokenIdentifier identifier) { return createPassword(identifier.getBytes(), getMasterKey(identifier.getApplicationAttemptID())); } @Private @Override - public byte[] retrievePassword(ClientTokenIdentifier identifier) + public byte[] retrievePassword(ClientToAMTokenIdentifier identifier) throws SecretManager.InvalidToken { SecretKey masterKey = getMasterKey(identifier.getApplicationAttemptID()); if (masterKey == null) { @@ -63,8 +63,8 @@ public abstract SecretKey getMasterKey( @Private @Override - public ClientTokenIdentifier createIdentifier() { - return new ClientTokenIdentifier(); + public ClientToAMTokenIdentifier createIdentifier() { + return new ClientToAMTokenIdentifier(); } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenIdentifier.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenIdentifier.java new file mode 100644 index 0000000..d9c576e --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenIdentifier.java @@ -0,0 +1,93 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.security.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceAudience.Public; +import org.apache.hadoop.classification.InterfaceStability.Evolving; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.token.Token; +import org.apache.hadoop.security.token.TokenIdentifier; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.api.records.ApplicationId; + +@Public +@Evolving +public class ClientToAMTokenIdentifier extends TokenIdentifier { + + public static final Text KIND_NAME = new Text("YARN_CLIENT_TOKEN"); + + private ApplicationAttemptId applicationAttemptId; + + // TODO: Add more information in the tokenID such that it is not + // transferrable, more secure etc. + + public ClientToAMTokenIdentifier() { + } + + public ClientToAMTokenIdentifier(ApplicationAttemptId id) { + this(); + this.applicationAttemptId = id; + } + + public ApplicationAttemptId getApplicationAttemptID() { + return this.applicationAttemptId; + } + + @Override + public void write(DataOutput out) throws IOException { + out.writeLong(this.applicationAttemptId.getApplicationId() + .getClusterTimestamp()); + out.writeInt(this.applicationAttemptId.getApplicationId().getId()); + out.writeInt(this.applicationAttemptId.getAttemptId()); + } + + @Override + public void readFields(DataInput in) throws IOException { + this.applicationAttemptId = + ApplicationAttemptId.newInstance( + ApplicationId.newInstance(in.readLong(), in.readInt()), in.readInt()); + } + + @Override + public Text getKind() { + return KIND_NAME; + } + + @Override + public UserGroupInformation getUser() { + if (this.applicationAttemptId == null) { + return null; + } + return UserGroupInformation.createRemoteUser(this.applicationAttemptId.toString()); + } + + @InterfaceAudience.Private + public static class Renewer extends Token.TrivialRenewer { + @Override + protected Text getKind() { + return KIND_NAME; + } + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenSecretManager.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenSecretManager.java index 7da2951..65d854d 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenSecretManager.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenSecretManager.java @@ -38,12 +38,17 @@ BaseClientToAMTokenSecretManager { // Only one client-token and one master-key for AM - private final SecretKey masterKey; + private SecretKey masterKey; public ClientToAMTokenSecretManager( - ApplicationAttemptId applicationAttemptID, byte[] secretKeyBytes) { + ApplicationAttemptId applicationAttemptID, byte[] key) { super(); - this.masterKey = SecretManager.createSecretKey(secretKeyBytes); + if (key != null) { + this.masterKey = SecretManager.createSecretKey(key); + } else { + this.masterKey = null; + } + } @Override @@ -52,4 +57,7 @@ public SecretKey getMasterKey(ApplicationAttemptId applicationAttemptID) { return this.masterKey; } + public void setMasterKey(byte[] key) { + this.masterKey = SecretManager.createSecretKey(key); + } } \ No newline at end of file diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenSelector.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenSelector.java new file mode 100644 index 0000000..e102fb2 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientToAMTokenSelector.java @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.security.client; + +import java.util.Collection; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.security.token.Token; +import org.apache.hadoop.security.token.TokenIdentifier; +import org.apache.hadoop.security.token.TokenSelector; + +public class ClientToAMTokenSelector implements + TokenSelector { + + private static final Log LOG = LogFactory + .getLog(ClientToAMTokenSelector.class); + + @SuppressWarnings("unchecked") + public Token selectToken(Text service, + Collection> tokens) { + if (service == null) { + return null; + } + LOG.debug("Looking for a token with service " + service.toString()); + for (Token token : tokens) { + LOG.debug("Token kind is " + token.getKind().toString() + + " and the token's service name is " + token.getService()); + if (ClientToAMTokenIdentifier.KIND_NAME.equals(token.getKind()) + && service.equals(token.getService())) { + return (Token) token; + } + } + return null; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientTokenIdentifier.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientTokenIdentifier.java deleted file mode 100644 index d7b0719..0000000 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientTokenIdentifier.java +++ /dev/null @@ -1,93 +0,0 @@ -/** -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.apache.hadoop.yarn.security.client; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import org.apache.hadoop.classification.InterfaceAudience; -import org.apache.hadoop.classification.InterfaceAudience.Public; -import org.apache.hadoop.classification.InterfaceStability.Evolving; -import org.apache.hadoop.io.Text; -import org.apache.hadoop.security.UserGroupInformation; -import org.apache.hadoop.security.token.Token; -import org.apache.hadoop.security.token.TokenIdentifier; -import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; -import org.apache.hadoop.yarn.api.records.ApplicationId; - -@Public -@Evolving -public class ClientTokenIdentifier extends TokenIdentifier { - - public static final Text KIND_NAME = new Text("YARN_CLIENT_TOKEN"); - - private ApplicationAttemptId applicationAttemptId; - - // TODO: Add more information in the tokenID such that it is not - // transferrable, more secure etc. - - public ClientTokenIdentifier() { - } - - public ClientTokenIdentifier(ApplicationAttemptId id) { - this(); - this.applicationAttemptId = id; - } - - public ApplicationAttemptId getApplicationAttemptID() { - return this.applicationAttemptId; - } - - @Override - public void write(DataOutput out) throws IOException { - out.writeLong(this.applicationAttemptId.getApplicationId() - .getClusterTimestamp()); - out.writeInt(this.applicationAttemptId.getApplicationId().getId()); - out.writeInt(this.applicationAttemptId.getAttemptId()); - } - - @Override - public void readFields(DataInput in) throws IOException { - this.applicationAttemptId = - ApplicationAttemptId.newInstance( - ApplicationId.newInstance(in.readLong(), in.readInt()), in.readInt()); - } - - @Override - public Text getKind() { - return KIND_NAME; - } - - @Override - public UserGroupInformation getUser() { - if (this.applicationAttemptId == null) { - return null; - } - return UserGroupInformation.createRemoteUser(this.applicationAttemptId.toString()); - } - - @InterfaceAudience.Private - public static class Renewer extends Token.TrivialRenewer { - @Override - protected Text getKind() { - return KIND_NAME; - } - } -} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientTokenSelector.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientTokenSelector.java deleted file mode 100644 index f3d2e02..0000000 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientTokenSelector.java +++ /dev/null @@ -1,58 +0,0 @@ -/** -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.apache.hadoop.yarn.security.client; - -import java.util.Collection; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.classification.InterfaceAudience.Public; -import org.apache.hadoop.classification.InterfaceStability.Stable; -import org.apache.hadoop.io.Text; -import org.apache.hadoop.security.token.Token; -import org.apache.hadoop.security.token.TokenIdentifier; -import org.apache.hadoop.security.token.TokenSelector; - -@Public -@Stable -public class ClientTokenSelector implements - TokenSelector { - - private static final Log LOG = LogFactory - .getLog(ClientTokenSelector.class); - - @SuppressWarnings("unchecked") - public Token selectToken(Text service, - Collection> tokens) { - if (service == null) { - return null; - } - LOG.debug("Looking for a token with service " + service.toString()); - for (Token token : tokens) { - LOG.debug("Token kind is " + token.getKind().toString() - + " and the token's service name is " + token.getService()); - if (ClientTokenIdentifier.KIND_NAME.equals(token.getKind()) - && service.equals(token.getService())) { - return (Token) token; - } - } - return null; - } - -} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/META-INF/services/org.apache.hadoop.security.token.TokenIdentifier hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/META-INF/services/org.apache.hadoop.security.token.TokenIdentifier index 2334040..d01a32d 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/META-INF/services/org.apache.hadoop.security.token.TokenIdentifier +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/META-INF/services/org.apache.hadoop.security.token.TokenIdentifier @@ -13,5 +13,5 @@ # org.apache.hadoop.yarn.security.ContainerTokenIdentifier org.apache.hadoop.yarn.security.ApplicationTokenIdentifier -org.apache.hadoop.yarn.security.client.ClientTokenIdentifier +org.apache.hadoop.yarn.security.client.ClientToAMTokenIdentifier org.apache.hadoop.yarn.security.client.RMDelegationTokenIdentifier diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/utils/BuilderUtils.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/utils/BuilderUtils.java index c346426..0bfeaaf 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/utils/BuilderUtils.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/utils/BuilderUtils.java @@ -313,7 +313,7 @@ public static ApplicationReport newApplicationReport( report.setName(name); report.setHost(host); report.setRpcPort(rpcPort); - report.setClientToken(clientToken); + report.setClientToAMToken(clientToken); report.setYarnApplicationState(state); report.setDiagnostics(diagnostics); report.setTrackingUrl(url); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java index d9d7e20..efbd81f 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java @@ -214,6 +214,12 @@ public RegisterApplicationMasterResponse registerApplicationMaster( .getMaximumResourceCapability()); response.setApplicationACLs(app.getRMAppAttempt(applicationAttemptId) .getSubmissionContext().getAMContainerSpec().getApplicationACLs()); + if (UserGroupInformation.isSecurityEnabled()) { + LOG.info("Setting client token master key"); + response.setClientToAMTokenMasterKey(java.nio.ByteBuffer.wrap(rmContext + .getClientToAMTokenSecretManager() + .getMasterKey(applicationAttemptId).getEncoded())); + } return response; } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/amlauncher/AMLauncher.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/amlauncher/AMLauncher.java index 60258b1..5afa9cb 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/amlauncher/AMLauncher.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/amlauncher/AMLauncher.java @@ -165,12 +165,12 @@ private ContainerLaunchContext createAMContainerLaunchContext( new String[0]))); // Finalize the container - setupTokensAndEnv(container, containerID); + setupTokens(container, containerID); return container; } - private void setupTokensAndEnv( + private void setupTokens( ContainerLaunchContext container, ContainerId containerID) throws IOException { Map environment = container.getEnvironment(); @@ -210,15 +210,6 @@ private void setupTokensAndEnv( credentials.writeTokenStorageToStream(dob); container.setTokens(ByteBuffer.wrap(dob.getData(), 0, dob.getLength())); - - SecretKey clientSecretKey = - this.rmContext.getClientToAMTokenSecretManager().getMasterKey( - application.getAppAttemptId()); - String encoded = - Base64.encodeBase64URLSafeString(clientSecretKey.getEncoded()); - environment.put( - ApplicationConstants.APPLICATION_CLIENT_SECRET_ENV_NAME, - encoded); } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/RMStateStore.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/RMStateStore.java index 0665022..9525911 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/RMStateStore.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/RMStateStore.java @@ -42,7 +42,7 @@ import org.apache.hadoop.yarn.event.Dispatcher; import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.security.ApplicationTokenIdentifier; -import org.apache.hadoop.yarn.security.client.ClientTokenIdentifier; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenIdentifier; import org.apache.hadoop.yarn.server.resourcemanager.recovery.records.impl.pb.ApplicationAttemptStateDataPBImpl; import org.apache.hadoop.yarn.server.resourcemanager.recovery.records.impl.pb.ApplicationStateDataPBImpl; import org.apache.hadoop.yarn.security.client.RMDelegationTokenIdentifier; @@ -382,7 +382,7 @@ private Credentials getTokensFromAppAttempt(RMAppAttempt appAttempt) { if(appToken != null){ credentials.addToken(appToken.getService(), appToken); } - Token clientToken = appAttempt.getClientToken(); + Token clientToken = appAttempt.getClientToken(); if(clientToken != null){ credentials.addToken(clientToken.getService(), clientToken); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppImpl.java index 539ab33..aad280a 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppImpl.java @@ -47,7 +47,7 @@ import org.apache.hadoop.yarn.event.Dispatcher; import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; -import org.apache.hadoop.yarn.security.client.ClientTokenIdentifier; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenIdentifier; import org.apache.hadoop.yarn.server.resourcemanager.ApplicationMasterService; import org.apache.hadoop.yarn.server.resourcemanager.RMAppManagerEvent; import org.apache.hadoop.yarn.server.resourcemanager.RMAppManagerEventType; @@ -445,7 +445,7 @@ public ApplicationReport createAndGetApplicationReport(boolean allowAccess) { currentApplicationAttemptId = this.currentAttempt.getAppAttemptId(); trackingUrl = this.currentAttempt.getTrackingUrl(); origTrackingUrl = this.currentAttempt.getOriginalTrackingUrl(); - Token attemptClientToken = + Token attemptClientToken = this.currentAttempt.getClientToken(); if (attemptClientToken != null) { clientToken = diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttempt.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttempt.java index b9c7eb2..1453182 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttempt.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttempt.java @@ -32,7 +32,7 @@ import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.security.ApplicationTokenIdentifier; -import org.apache.hadoop.yarn.security.client.ClientTokenIdentifier; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenIdentifier; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; /** @@ -94,7 +94,7 @@ * The token required by the clients to talk to the application attempt * @return the token required by the clients to talk to the application attempt */ - Token getClientToken(); + Token getClientToken(); /** * Diagnostics information for the application attempt. diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java index bb2e252..5ed3f9c 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java @@ -63,8 +63,8 @@ import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; import org.apache.hadoop.yarn.security.ApplicationTokenIdentifier; import org.apache.hadoop.yarn.security.ApplicationTokenSelector; -import org.apache.hadoop.yarn.security.client.ClientTokenIdentifier; -import org.apache.hadoop.yarn.security.client.ClientTokenSelector; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenIdentifier; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenSelector; import org.apache.hadoop.yarn.server.resourcemanager.ApplicationMasterService; import org.apache.hadoop.yarn.server.resourcemanager.RMContext; import org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncherEvent; @@ -129,7 +129,7 @@ private final WriteLock writeLock; private final ApplicationAttemptId applicationAttemptId; - private Token clientToken; + private Token clientToken; private final ApplicationSubmissionContext submissionContext; private Token applicationToken = null; @@ -498,7 +498,7 @@ private void setTrackingUrlToRMAppPage() { } @Override - public Token getClientToken() { + public Token getClientToken() { return this.clientToken; } @@ -673,7 +673,7 @@ private void recoverAppAttemptTokens(Credentials appAttemptTokens) { } if (UserGroupInformation.isSecurityEnabled()) { - ClientTokenSelector clientTokenSelector = new ClientTokenSelector(); + ClientToAMTokenSelector clientTokenSelector = new ClientToAMTokenSelector(); this.clientToken = clientTokenSelector.selectToken(new Text(), appAttemptTokens.getAllTokens()); @@ -722,7 +722,7 @@ public void transition(RMAppAttemptImpl appAttempt, // create clientToken appAttempt.clientToken = - new Token(new ClientTokenIdentifier( + new Token(new ClientToAMTokenIdentifier( appAttempt.applicationAttemptId), appAttempt.rmContext.getClientToAMTokenSecretManager()); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockAM.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockAM.java index 52102ff..c4565d3 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockAM.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockAM.java @@ -28,6 +28,7 @@ import org.apache.hadoop.yarn.api.protocolrecords.AllocateResponse; import org.apache.hadoop.yarn.api.protocolrecords.FinishApplicationMasterRequest; import org.apache.hadoop.yarn.api.protocolrecords.RegisterApplicationMasterRequest; +import org.apache.hadoop.yarn.api.protocolrecords.RegisterApplicationMasterResponse; import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.api.records.FinalApplicationStatus; @@ -49,7 +50,7 @@ private final List requests = new ArrayList(); private final List releases = new ArrayList(); - MockAM(RMContext context, ApplicationMasterProtocol amRMProtocol, + public MockAM(RMContext context, ApplicationMasterProtocol amRMProtocol, ApplicationAttemptId attemptId) { this.context = context; this.amRMProtocol = amRMProtocol; @@ -77,7 +78,7 @@ public void waitForState(RMAppAttemptState finalState) throws Exception { finalState, attempt.getAppAttemptState()); } - public void registerAppAttempt() throws Exception { + public RegisterApplicationMasterResponse registerAppAttempt() throws Exception { waitForState(RMAppAttemptState.LAUNCHED); responseId = 0; RegisterApplicationMasterRequest req = Records.newRecord(RegisterApplicationMasterRequest.class); @@ -85,7 +86,7 @@ public void registerAppAttempt() throws Exception { req.setHost(""); req.setRpcPort(1); req.setTrackingUrl(""); - amRMProtocol.registerApplicationMaster(req); + return amRMProtocol.registerApplicationMaster(req); } public void addRequests(String[] hosts, int memory, int priority, diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockRM.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockRM.java index b062eb9..c1d3f92 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockRM.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockRM.java @@ -96,7 +96,7 @@ public void waitForState(ApplicationId appId, RMAppState finalState) while (!finalState.equals(app.getState()) && timeoutSecs++ < 40) { System.out.println("App : " + appId + " State is : " + app.getState() + " Waiting for state : " + finalState); - Thread.sleep(1000); + Thread.sleep(2000); } System.out.println("App State is : " + app.getState()); Assert.assertEquals("App state is not correct (timedout)", finalState, diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestApplicationACLs.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestApplicationACLs.java index 031de04..1cf8045 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestApplicationACLs.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestApplicationACLs.java @@ -338,7 +338,7 @@ private void verifyEnemyAppReport(ApplicationReport appReport) { Assert.assertEquals("Enemy should not see app rpc port!", -1, appReport.getRpcPort()); Assert.assertEquals("Enemy should not see app client token!", - null, appReport.getClientToken()); + null, appReport.getClientToAMToken()); Assert.assertEquals("Enemy should not see app diagnostics!", UNAVAILABLE, appReport.getDiagnostics()); Assert.assertEquals("Enemy should not see app tracking url!", diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/TestRMStateStore.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/TestRMStateStore.java index 75b5d9f..7b58728 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/TestRMStateStore.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/TestRMStateStore.java @@ -55,7 +55,7 @@ import org.apache.hadoop.yarn.event.Dispatcher; import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.security.ApplicationTokenIdentifier; -import org.apache.hadoop.yarn.security.client.ClientTokenIdentifier; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenIdentifier; import org.apache.hadoop.yarn.security.client.RMDelegationTokenIdentifier; import org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore.ApplicationAttemptState; import org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore.ApplicationState; @@ -206,7 +206,7 @@ void storeApp(RMStateStore store, ApplicationId appId, long time) ContainerId storeAttempt(RMStateStore store, ApplicationAttemptId attemptId, String containerIdStr, Token appToken, - Token clientToken, TestDispatcher dispatcher) + Token clientToken, TestDispatcher dispatcher) throws Exception { Container container = new ContainerPBImpl(); @@ -250,7 +250,7 @@ void testRMAppStateStore(RMStateStoreHelper stateStoreHelper) throws Exception { ContainerId containerId1 = storeAttempt(store, attemptId1, "container_1352994193343_0001_01_000001", (Token) (appAttemptToken1.get(0)), - (Token)(appAttemptToken1.get(1)), + (Token)(appAttemptToken1.get(1)), dispatcher); String appAttemptIdStr2 = "appattempt_1352994193343_0001_000002"; @@ -266,7 +266,7 @@ void testRMAppStateStore(RMStateStoreHelper stateStoreHelper) throws Exception { ContainerId containerId2 = storeAttempt(store, attemptId2, "container_1352994193343_0001_02_000001", (Token) (appAttemptToken2.get(0)), - (Token)(appAttemptToken2.get(1)), + (Token)(appAttemptToken2.get(1)), dispatcher); ApplicationAttemptId attemptIdRemoved = ConverterUtils @@ -380,10 +380,10 @@ public void testRMDTSecretManagerStateStore( new Token(appTokenId, appTokenMgr); appToken.setService(new Text("appToken service")); - ClientTokenIdentifier clientTokenId = new ClientTokenIdentifier(attemptId); + ClientToAMTokenIdentifier clientTokenId = new ClientToAMTokenIdentifier(attemptId); clientTokenMgr.registerApplication(attemptId); - Token clientToken = - new Token(clientTokenId, clientTokenMgr); + Token clientToken = + new Token(clientTokenId, clientTokenMgr); clientToken.setService(new Text("clientToken service")); List> tokenPair = new ArrayList>(); tokenPair.add(0, appToken); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientToAMTokens.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientToAMTokens.java new file mode 100644 index 0000000..5148095 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientToAMTokens.java @@ -0,0 +1,323 @@ +/** +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.apache.hadoop.yarn.server.resourcemanager.security; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.net.InetSocketAddress; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; + +import javax.security.sasl.SaslException; + +import junit.framework.Assert; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.CommonConfigurationKeysPublic; +import org.apache.hadoop.ipc.RPC; +import org.apache.hadoop.ipc.RemoteException; +import org.apache.hadoop.ipc.Server; +import org.apache.hadoop.net.NetUtils; +import org.apache.hadoop.security.KerberosInfo; +import org.apache.hadoop.security.SecurityInfo; +import org.apache.hadoop.security.SecurityUtil; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.token.Token; +import org.apache.hadoop.security.token.TokenIdentifier; +import org.apache.hadoop.security.token.TokenInfo; +import org.apache.hadoop.security.token.TokenSelector; +import org.apache.hadoop.service.AbstractService; +import org.apache.hadoop.yarn.api.ContainerManagementProtocol; +import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationReportRequest; +import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationReportResponse; +import org.apache.hadoop.yarn.api.protocolrecords.RegisterApplicationMasterResponse; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.api.records.ApplicationReport; +import org.apache.hadoop.yarn.event.Dispatcher; +import org.apache.hadoop.yarn.event.DrainDispatcher; +import org.apache.hadoop.yarn.exceptions.YarnException; +import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenIdentifier; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenSecretManager; +import org.apache.hadoop.yarn.security.client.ClientToAMTokenSelector; +import org.apache.hadoop.yarn.server.resourcemanager.ClientRMService; +import org.apache.hadoop.yarn.server.resourcemanager.MockAM; +import org.apache.hadoop.yarn.server.resourcemanager.MockNM; +import org.apache.hadoop.yarn.server.resourcemanager.MockRM; +import org.apache.hadoop.yarn.server.resourcemanager.MockRMWithCustomAMLauncher; +import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; +import org.apache.hadoop.yarn.server.utils.BuilderUtils; +import org.apache.hadoop.yarn.util.ProtoUtils; +import org.apache.hadoop.yarn.util.Records; +import org.junit.Test; + +public class TestClientToAMTokens { + + private interface CustomProtocol { + @SuppressWarnings("unused") + public static final long versionID = 1L; + + public void ping() throws YarnException, IOException; + } + + private static class CustomSecurityInfo extends SecurityInfo { + + @Override + public TokenInfo getTokenInfo(Class protocol, Configuration conf) { + return new TokenInfo() { + + @Override + public Class annotationType() { + return null; + } + + @Override + public Class> + value() { + return ClientToAMTokenSelector.class; + } + }; + } + + @Override + public KerberosInfo getKerberosInfo(Class protocol, Configuration conf) { + return null; + } + }; + + private static class CustomAM extends AbstractService implements + CustomProtocol { + + private final ApplicationAttemptId appAttemptId; + private final byte[] secretKey; + private InetSocketAddress address; + private boolean pinged = false; + private ClientToAMTokenSecretManager secretManager; + + public CustomAM(ApplicationAttemptId appId, byte[] secretKey) { + super("CustomAM"); + this.appAttemptId = appId; + this.secretKey = secretKey; + } + + @Override + public void ping() throws YarnException, IOException { + this.pinged = true; + } + + @Override + protected void serviceStart() throws Exception { + Configuration conf = getConfig(); + + secretManager = new ClientToAMTokenSecretManager(this.appAttemptId, secretKey); + Server server; + try { + server = + new RPC.Builder(conf).setProtocol(CustomProtocol.class) + .setNumHandlers(1).setSecretManager(secretManager) + .setInstance(this).build(); + } catch (Exception e) { + throw new YarnRuntimeException(e); + } + server.start(); + this.address = NetUtils.getConnectAddress(server); + super.serviceStart(); + } + + public ClientToAMTokenSecretManager getClientToAMTokenSecretManager() { + return this.secretManager; + } + } + + @Test + public void testClientToAMs() throws Exception { + + final Configuration conf = new Configuration(); + conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, + "kerberos"); + UserGroupInformation.setConfiguration(conf); + + ContainerManagementProtocol containerManager = + mock(ContainerManagementProtocol.class); + final DrainDispatcher dispatcher = new DrainDispatcher(); + + MockRM rm = new MockRMWithCustomAMLauncher(conf, containerManager) { + protected ClientRMService createClientRMService() { + return new ClientRMService(this.rmContext, scheduler, + this.rmAppManager, this.applicationACLsManager, + this.rmDTSecretManager); + }; + + @Override + protected Dispatcher createDispatcher() { + return dispatcher; + } + + @Override + protected void doSecureLogin() throws IOException { + } + }; + rm.start(); + + // Submit an app + RMApp app = rm.submitApp(1024); + + // Set up a node. + MockNM nm1 = rm.registerNode("localhost:1234", 3072); + nm1.nodeHeartbeat(true); + dispatcher.await(); + + + nm1.nodeHeartbeat(true); + dispatcher.await(); + + // Get the app-report. + GetApplicationReportRequest request = + Records.newRecord(GetApplicationReportRequest.class); + request.setApplicationId(app.getApplicationId()); + GetApplicationReportResponse reportResponse = + rm.getClientRMService().getApplicationReport(request); + ApplicationReport appReport = reportResponse.getApplicationReport(); + org.apache.hadoop.yarn.api.records.Token clientToAMToken = + appReport.getClientToAMToken(); + + ApplicationAttemptId appAttempt = app.getCurrentAppAttempt().getAppAttemptId(); + final MockAM mockAM = + new MockAM(rm.getRMContext(), rm.getApplicationMasterService(), + app.getCurrentAppAttempt().getAppAttemptId()); + UserGroupInformation appUgi = + UserGroupInformation.createRemoteUser(appAttempt.toString()); + RegisterApplicationMasterResponse response = + appUgi.doAs(new PrivilegedAction() { + + @Override + public RegisterApplicationMasterResponse run() { + RegisterApplicationMasterResponse response = null; + try { + response = mockAM.registerAppAttempt(); + } catch (Exception e) { + Assert.fail("Exception was not expected"); + } + return response; + } + }); + + // ClientToAMToken master key should have been received on register + // application master response. + Assert.assertNotNull(response.getClientToAMTokenMasterKey()); + Assert + .assertTrue(response.getClientToAMTokenMasterKey().array().length > 0); + + // Start the AM with the correct shared-secret. + ApplicationAttemptId appAttemptId = + app.getAppAttempts().keySet().iterator().next(); + Assert.assertNotNull(appAttemptId); + final CustomAM am = + new CustomAM(appAttemptId, response.getClientToAMTokenMasterKey() + .array()); + am.init(conf); + am.start(); + + // Now the real test! + // Set up clients to be able to pick up correct tokens. + SecurityUtil.setSecurityInfoProviders(new CustomSecurityInfo()); + + // Verify denial for unauthenticated user + try { + CustomProtocol client = + (CustomProtocol) RPC.getProxy(CustomProtocol.class, 1L, am.address, + conf); + client.ping(); + fail("Access by unauthenticated user should fail!!"); + } catch (Exception e) { + Assert.assertFalse(am.pinged); + } + + // Verify denial for a malicious user + UserGroupInformation ugi = UserGroupInformation.createRemoteUser("me"); + Token token = + ProtoUtils.convertFromProtoFormat(clientToAMToken, am.address); + + // Malicious user, messes with appId + ClientToAMTokenIdentifier maliciousID = + new ClientToAMTokenIdentifier(BuilderUtils.newApplicationAttemptId( + BuilderUtils.newApplicationId(app.getApplicationId() + .getClusterTimestamp(), 42), 43)); + + Token maliciousToken = + new Token(maliciousID.getBytes(), + token.getPassword(), token.getKind(), + token.getService()); + ugi.addToken(maliciousToken); + + try { + ugi.doAs(new PrivilegedExceptionAction() { + @Override + public Void run() throws Exception { + try { + CustomProtocol client = + (CustomProtocol) RPC.getProxy(CustomProtocol.class, 1L, + am.address, conf); + client.ping(); + fail("Connection initiation with illegally modified " + + "tokens is expected to fail."); + return null; + } catch (YarnException ex) { + fail("Cannot get a YARN remote exception as " + + "it will indicate RPC success"); + throw ex; + } + } + }); + } catch (Exception e) { + Assert.assertEquals(RemoteException.class.getName(), e.getClass() + .getName()); + e = ((RemoteException)e).unwrapRemoteException(); + Assert + .assertEquals(SaslException.class + .getCanonicalName(), e.getClass().getCanonicalName()); + Assert.assertTrue(e + .getMessage() + .contains( + "DIGEST-MD5: digest response format violation. " + + "Mismatched response.")); + Assert.assertFalse(am.pinged); + } + + // Now for an authenticated user + ugi = UserGroupInformation.createRemoteUser("me"); + ugi.addToken(token); + + ugi.doAs(new PrivilegedExceptionAction() { + @Override + public Void run() throws Exception { + CustomProtocol client = + (CustomProtocol) RPC.getProxy(CustomProtocol.class, 1L, am.address, + conf); + client.ping(); + Assert.assertTrue(am.pinged); + return null; + } + }); + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientTokens.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientTokens.java deleted file mode 100644 index f5c6de0..0000000 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientTokens.java +++ /dev/null @@ -1,325 +0,0 @@ -/** -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.apache.hadoop.yarn.server.resourcemanager.security; - -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.net.InetSocketAddress; -import java.security.PrivilegedExceptionAction; - -import javax.security.sasl.SaslException; - -import junit.framework.Assert; - -import org.apache.commons.codec.binary.Base64; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.CommonConfigurationKeysPublic; -import org.apache.hadoop.ipc.RPC; -import org.apache.hadoop.ipc.RemoteException; -import org.apache.hadoop.ipc.Server; -import org.apache.hadoop.net.NetUtils; -import org.apache.hadoop.security.KerberosInfo; -import org.apache.hadoop.security.SecurityInfo; -import org.apache.hadoop.security.SecurityUtil; -import org.apache.hadoop.security.UserGroupInformation; -import org.apache.hadoop.security.token.Token; -import org.apache.hadoop.security.token.TokenIdentifier; -import org.apache.hadoop.security.token.TokenInfo; -import org.apache.hadoop.security.token.TokenSelector; -import org.apache.hadoop.service.AbstractService; -import org.apache.hadoop.yarn.api.ApplicationConstants; -import org.apache.hadoop.yarn.api.ContainerManagementProtocol; -import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationReportRequest; -import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationReportResponse; -import org.apache.hadoop.yarn.api.protocolrecords.GetContainerStatusRequest; -import org.apache.hadoop.yarn.api.protocolrecords.GetContainerStatusResponse; -import org.apache.hadoop.yarn.api.protocolrecords.StartContainerRequest; -import org.apache.hadoop.yarn.api.protocolrecords.StartContainerResponse; -import org.apache.hadoop.yarn.api.protocolrecords.StopContainerRequest; -import org.apache.hadoop.yarn.api.protocolrecords.StopContainerResponse; -import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; -import org.apache.hadoop.yarn.api.records.ApplicationReport; -import org.apache.hadoop.yarn.event.Dispatcher; -import org.apache.hadoop.yarn.event.DrainDispatcher; -import org.apache.hadoop.yarn.exceptions.YarnException; -import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; -import org.apache.hadoop.yarn.security.client.ClientToAMTokenSecretManager; -import org.apache.hadoop.yarn.security.client.ClientTokenIdentifier; -import org.apache.hadoop.yarn.security.client.ClientTokenSelector; -import org.apache.hadoop.yarn.server.resourcemanager.ClientRMService; -import org.apache.hadoop.yarn.server.resourcemanager.MockNM; -import org.apache.hadoop.yarn.server.resourcemanager.MockRM; -import org.apache.hadoop.yarn.server.resourcemanager.MockRMWithCustomAMLauncher; -import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; -import org.apache.hadoop.yarn.server.utils.BuilderUtils; -import org.apache.hadoop.yarn.util.ProtoUtils; -import org.apache.hadoop.yarn.util.Records; -import org.junit.Test; - -public class TestClientTokens { - - private interface CustomProtocol { - @SuppressWarnings("unused") - public static final long versionID = 1L; - - public void ping() throws YarnException, IOException; - } - - private static class CustomSecurityInfo extends SecurityInfo { - - @Override - public TokenInfo getTokenInfo(Class protocol, Configuration conf) { - return new TokenInfo() { - - @Override - public Class annotationType() { - return null; - } - - @Override - public Class> - value() { - return ClientTokenSelector.class; - } - }; - } - - @Override - public KerberosInfo getKerberosInfo(Class protocol, Configuration conf) { - return null; - } - }; - - private static class CustomAM extends AbstractService implements - CustomProtocol { - - private final ApplicationAttemptId appAttemptId; - private final String secretKey; - private InetSocketAddress address; - private boolean pinged = false; - - public CustomAM(ApplicationAttemptId appId, String secretKeyStr) { - super("CustomAM"); - this.appAttemptId = appId; - this.secretKey = secretKeyStr; - } - - @Override - public void ping() throws YarnException, IOException { - this.pinged = true; - } - - @Override - protected void serviceStart() throws Exception { - Configuration conf = getConfig(); - - ClientToAMTokenSecretManager secretManager = null; - byte[] bytes = Base64.decodeBase64(this.secretKey); - secretManager = new ClientToAMTokenSecretManager(this.appAttemptId, bytes); - Server server; - try { - server = - new RPC.Builder(conf).setProtocol(CustomProtocol.class) - .setNumHandlers(1).setSecretManager(secretManager) - .setInstance(this).build(); - } catch (Exception e) { - throw new YarnRuntimeException(e); - } - server.start(); - this.address = NetUtils.getConnectAddress(server); - super.serviceStart(); - } - } - - private static class CustomNM implements ContainerManagementProtocol { - - public String clientTokensSecret; - - @Override - public StartContainerResponse startContainer(StartContainerRequest request) - throws YarnException { - this.clientTokensSecret = - request.getContainerLaunchContext().getEnvironment() - .get(ApplicationConstants.APPLICATION_CLIENT_SECRET_ENV_NAME); - return null; - } - - @Override - public StopContainerResponse stopContainer(StopContainerRequest request) - throws YarnException { - return null; - } - - @Override - public GetContainerStatusResponse getContainerStatus( - GetContainerStatusRequest request) throws YarnException { - return null; - } - - } - - @Test - public void testClientTokens() throws Exception { - - final Configuration conf = new Configuration(); - conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, - "kerberos"); - UserGroupInformation.setConfiguration(conf); - - CustomNM containerManager = new CustomNM(); - final DrainDispatcher dispatcher = new DrainDispatcher(); - - MockRM rm = new MockRMWithCustomAMLauncher(conf, containerManager) { - protected ClientRMService createClientRMService() { - return new ClientRMService(this.rmContext, scheduler, - this.rmAppManager, this.applicationACLsManager, - this.rmDTSecretManager); - }; - - @Override - protected Dispatcher createDispatcher() { - return dispatcher; - } - - @Override - protected void doSecureLogin() throws IOException { - } - }; - rm.start(); - - // Submit an app - RMApp app = rm.submitApp(1024); - dispatcher.await(); - - // Set up a node. - MockNM nm1 = rm.registerNode("localhost:1234", 3072); - nm1.nodeHeartbeat(true); - dispatcher.await(); - - // Get the app-report. - GetApplicationReportRequest request = - Records.newRecord(GetApplicationReportRequest.class); - request.setApplicationId(app.getApplicationId()); - GetApplicationReportResponse reportResponse = - rm.getClientRMService().getApplicationReport(request); - ApplicationReport appReport = reportResponse.getApplicationReport(); - org.apache.hadoop.yarn.api.records.Token clientToken = appReport.getClientToken(); - - // Wait till AM is 'launched' - int waitTime = 0; - while (containerManager.clientTokensSecret == null && waitTime++ < 20) { - Thread.sleep(1000); - } - Assert.assertNotNull(containerManager.clientTokensSecret); - - // Start the AM with the correct shared-secret. - ApplicationAttemptId appAttemptId = - app.getAppAttempts().keySet().iterator().next(); - Assert.assertNotNull(appAttemptId); - final CustomAM am = - new CustomAM(appAttemptId, containerManager.clientTokensSecret); - am.init(conf); - am.start(); - - // Now the real test! - // Set up clients to be able to pick up correct tokens. - SecurityUtil.setSecurityInfoProviders(new CustomSecurityInfo()); - - // Verify denial for unauthenticated user - try { - CustomProtocol client = - (CustomProtocol) RPC.getProxy(CustomProtocol.class, 1L, am.address, - conf); - client.ping(); - fail("Access by unauthenticated user should fail!!"); - } catch (Exception e) { - Assert.assertFalse(am.pinged); - } - - // Verify denial for a malicious user - UserGroupInformation ugi = UserGroupInformation.createRemoteUser("me"); - Token token = - ProtoUtils.convertFromProtoFormat(clientToken, am.address); - - // Malicious user, messes with appId - ClientTokenIdentifier maliciousID = - new ClientTokenIdentifier(BuilderUtils.newApplicationAttemptId( - BuilderUtils.newApplicationId(app.getApplicationId() - .getClusterTimestamp(), 42), 43)); - - Token maliciousToken = - new Token(maliciousID.getBytes(), - token.getPassword(), token.getKind(), - token.getService()); - ugi.addToken(maliciousToken); - - try { - ugi.doAs(new PrivilegedExceptionAction() { - @Override - public Void run() throws Exception { - try { - CustomProtocol client = - (CustomProtocol) RPC.getProxy(CustomProtocol.class, 1L, - am.address, conf); - client.ping(); - fail("Connection initiation with illegally modified " - + "tokens is expected to fail."); - return null; - } catch (YarnException ex) { - fail("Cannot get a YARN remote exception as " - + "it will indicate RPC success"); - throw ex; - } - } - }); - } catch (Exception e) { - Assert.assertEquals(RemoteException.class.getName(), e.getClass() - .getName()); - e = ((RemoteException)e).unwrapRemoteException(); - Assert - .assertEquals(SaslException.class - .getCanonicalName(), e.getClass().getCanonicalName()); - Assert.assertTrue(e - .getMessage() - .contains( - "DIGEST-MD5: digest response format violation. " - + "Mismatched response.")); - Assert.assertFalse(am.pinged); - } - - // Now for an authenticated user - ugi = UserGroupInformation.createRemoteUser("me"); - ugi.addToken(token); - - ugi.doAs(new PrivilegedExceptionAction() { - @Override - public Void run() throws Exception { - CustomProtocol client = - (CustomProtocol) RPC.getProxy(CustomProtocol.class, 1L, am.address, - conf); - client.ping(); - Assert.assertTrue(am.pinged); - return null; - } - }); - } - -}