You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@slider.apache.org by st...@apache.org on 2014/12/18 22:32:11 UTC

[03/50] incubator-slider git commit: SLIDER-677 enable operation without keytabs for short lived applications

SLIDER-677 enable operation without keytabs for short lived applications


Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/1bdf80cd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/1bdf80cd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/1bdf80cd

Branch: refs/heads/feature/SLIDER-151_REST_API
Commit: 1bdf80cdf0dcc085e9195bfe80b2ebed35f1b2f9
Parents: 3fe140c
Author: Jon Maron <jm...@hortonworks.com>
Authored: Mon Dec 1 15:32:15 2014 -0500
Committer: Jon Maron <jm...@hortonworks.com>
Committed: Mon Dec 1 15:32:15 2014 -0500

----------------------------------------------------------------------
 .../slider/core/launch/AppMasterLauncher.java   | 22 ++++-
 .../providers/agent/AgentProviderService.java   | 29 +++---
 .../slideram/SliderAMClientProvider.java        | 22 +++--
 .../server/appmaster/SliderAppMaster.java       | 97 ++++++++++++--------
 .../security/SecurityConfiguration.java         | 20 ++--
 .../security/SecurityConfigurationTest.groovy   | 15 ---
 6 files changed, 118 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/1bdf80cd/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java b/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java
index 7023c80..c5526ed 100644
--- a/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java
+++ b/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java
@@ -21,6 +21,9 @@ package org.apache.slider.core.launch;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.security.SecurityUtil;
+import org.apache.hadoop.security.token.Token;
+import org.apache.hadoop.security.token.TokenIdentifier;
+import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdentifier;
 import org.apache.hadoop.yarn.api.records.ApplicationId;
 import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
 import org.apache.hadoop.yarn.api.records.Priority;
@@ -37,6 +40,8 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.net.InetAddress;
+import java.text.DateFormat;
+import java.util.Date;
 import java.util.Map;
 import java.util.Set;
 
@@ -218,8 +223,21 @@ public class AppMasterLauncher extends AbstractLauncher {
 
     // For now, only getting tokens for the default file-system.
     FileSystem fs = coreFileSystem.getFileSystem();
-    fs.addDelegationTokens(tokenRenewer, credentials);
-  }
+    Token<? extends TokenIdentifier>[] tokens = fs.addDelegationTokens(tokenRenewer,
+                                                             credentials);
+    // obtain the token expiry from the first token - should be the same for all
+    // HDFS tokens
+    if (tokens != null && tokens.length > 0) {
+      AbstractDelegationTokenIdentifier id =
+        (AbstractDelegationTokenIdentifier)tokens[0].decodeIdentifier();
+      Date d = new Date(id.getIssueDate() + 24*60*60*1000);
+      log.info("HDFS delegation tokens for AM launch context require renewal by {}",
+               DateFormat.getDateTimeInstance().format(d));
+    } else {
+      log.warn("No HDFS delegation tokens obtained for AM launch context");
+    }
+
+   }
 
   /**
    * Submit the application. 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/1bdf80cd/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
index 4f981c7..808b15c 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
@@ -523,27 +523,28 @@ public class AgentProviderService extends AbstractProviderService implements
       // we need to localize the keytab files in the directory
       Path keytabDirPath = fileSystem.buildKeytabPath(keytabDir, null,
                                                       getClusterName());
-      FileStatus[] keytabs = fileSystem.getFileSystem().listStatus(keytabDirPath);
-      LocalResource keytabRes;
       boolean serviceKeytabsDeployed = false;
-      for (FileStatus keytab : keytabs) {
-        if (!amKeytabName.equals(keytab.getPath().getName())
-            && keytab.getPath().getName().endsWith(".keytab")) {
-          serviceKeytabsDeployed = true;
-          log.info("Localizing keytab {}", keytab.getPath().getName());
-          keytabRes = fileSystem.createAmResource(keytab.getPath(),
-            LocalResourceType.FILE);
-          launcher.addLocalResource(SliderKeys.KEYTAB_DIR + "/" +
-                                  keytab.getPath().getName(),
-                                  keytabRes);
+      if (fileSystem.getFileSystem().exists(keytabDirPath)) {
+        FileStatus[] keytabs = fileSystem.getFileSystem().listStatus(keytabDirPath);
+        LocalResource keytabRes;
+        for (FileStatus keytab : keytabs) {
+          if (!amKeytabName.equals(keytab.getPath().getName())
+              && keytab.getPath().getName().endsWith(".keytab")) {
+            serviceKeytabsDeployed = true;
+            log.info("Localizing keytab {}", keytab.getPath().getName());
+            keytabRes = fileSystem.createAmResource(keytab.getPath(),
+              LocalResourceType.FILE);
+            launcher.addLocalResource(SliderKeys.KEYTAB_DIR + "/" +
+                                    keytab.getPath().getName(),
+                                    keytabRes);
+          }
         }
       }
       if (!serviceKeytabsDeployed) {
         log.warn("No service keytabs for the application have been localized.  "
                  + "If the application requires keytabs for secure operation, "
                  + "please ensure that the required keytabs have been uploaded "
-                 + "to the folder designated by the property {}: {}",
-                 SliderXmlConfKeys.KEY_HDFS_KEYTAB_DIR, keytabDirPath);
+                 + "to the folder {}", keytabDirPath);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/1bdf80cd/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMClientProvider.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMClientProvider.java b/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMClientProvider.java
index 5ce0a78..b790713 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMClientProvider.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMClientProvider.java
@@ -175,7 +175,6 @@ public class SliderAMClientProvider extends AbstractClientProvider
     Map<String, LocalResource> providerResources =
         new HashMap<String, LocalResource>();
 
-
     ProviderUtils.addProviderJar(providerResources,
         this,
         SLIDER_JAR,
@@ -193,10 +192,11 @@ public class SliderAMClientProvider extends AbstractClientProvider
                                          libdir,
                                          libDirProp);
     addKeytabResourceIfNecessary(fileSystem,
-                                 launcher,
                                  instanceDescription,
                                  providerResources);
 
+    launcher.addLocalResources(providerResources);
+
     //also pick up all env variables from a map
     launcher.copyEnvVars(
       instanceDescription.getInternalOperations().getOrAddComponent(
@@ -208,13 +208,11 @@ public class SliderAMClientProvider extends AbstractClientProvider
    * authentication, add this keytab as a local resource for the AM launch.
    *
    * @param fileSystem
-   * @param launcher
    * @param instanceDescription
    * @param providerResources
    * @throws IOException
    */
   protected void addKeytabResourceIfNecessary(SliderFileSystem fileSystem,
-                                              AbstractLauncher launcher,
                                               AggregateConf instanceDescription,
                                               Map<String, LocalResource> providerResources)
       throws IOException {
@@ -231,14 +229,20 @@ public class SliderAMClientProvider extends AbstractClientProvider
                 SliderXmlConfKeys.KEY_HDFS_KEYTAB_DIR);
         Path keytabPath = fileSystem.buildKeytabPath(keytabDir, amKeytabName,
                                                      instanceDescription.getName());
-        LocalResource keytabRes = fileSystem.createAmResource(keytabPath,
-                                                LocalResourceType.FILE);
+        if (fileSystem.getFileSystem().exists(keytabPath)) {
+          LocalResource keytabRes = fileSystem.createAmResource(keytabPath,
+                                                  LocalResourceType.FILE);
 
-         providerResources.put(SliderKeys.KEYTAB_DIR + "/" +
-                               amKeytabName, keytabRes);
+          providerResources.put(SliderKeys.KEYTAB_DIR + "/" +
+                                 amKeytabName, keytabRes);
+        } else {
+          log.warn("No keytab file was found at {}.  The AM will be "
+                   + "started without a kerberos authenticated identity. "
+                   + "The application is therefore not guaranteed to remain "
+                   + "operational beyond 24 hours.", keytabPath);
+        }
       }
     }
-    launcher.addLocalResources(providerResources);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/1bdf80cd/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
index 1bafe4b..a84cf52 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
@@ -33,6 +33,7 @@ import org.apache.hadoop.hdfs.HdfsConfiguration;
 import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
 import org.apache.hadoop.http.HttpConfig;
 import org.apache.hadoop.io.DataOutputBuffer;
+import org.apache.hadoop.io.Text;
 import org.apache.hadoop.ipc.ProtocolSignature;
 import org.apache.hadoop.registry.client.binding.RegistryUtils;
 import org.apache.hadoop.security.Credentials;
@@ -150,7 +151,7 @@ import org.apache.slider.server.appmaster.web.WebAppApi;
 import org.apache.slider.server.appmaster.web.WebAppApiImpl;
 import org.apache.slider.server.appmaster.web.rest.RestPaths;
 import org.apache.slider.server.services.security.CertificateManager;
-import org.apache.slider.server.services.security.FsDelegationTokenManager;
+//import org.apache.slider.server.services.security.FsDelegationTokenManager;
 import org.apache.slider.server.services.utility.AbstractSliderLaunchedService;
 import org.apache.slider.server.appmaster.management.MetricsBindingService;
 import org.apache.slider.server.services.utility.WebAppService;
@@ -376,9 +377,10 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
   private String agentOpsUrl;
   private String agentStatusUrl;
   private YarnRegistryViewForProviders yarnRegistryOperations;
-  private FsDelegationTokenManager fsDelegationTokenManager;
+  //private FsDelegationTokenManager fsDelegationTokenManager;
   private RegisterApplicationMasterResponse amRegistrationData;
   private PortScanner portScanner;
+  private SecurityConfiguration securityConfiguration;
 
   /**
    * Service Constructor
@@ -584,7 +586,7 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
 
     Configuration serviceConf = getConfig();
 
-    SecurityConfiguration securityConfiguration = new SecurityConfiguration(
+    securityConfiguration = new SecurityConfiguration(
         serviceConf, instanceDefinition, clustername);
     // obtain security state
     boolean securityEnabled = securityConfiguration.isSecurityEnabled();
@@ -765,25 +767,7 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
       appInformation.put(ResourceKeys.YARN_CORES, Integer.toString(containerMaxCores));
       appInformation.put(ResourceKeys.YARN_MEMORY, Integer.toString(containerMaxMemory));
 
-      // process the initial user to obtain the set of user
-      // supplied credentials (tokens were passed in by client). Remove AMRM
-      // token and HDFS delegation token, the latter because we will provide an
-      // up to date token for container launches (getContainerCredentials()).
-      UserGroupInformation currentUser = UserGroupInformation.getCurrentUser();
-      Credentials credentials = currentUser.getCredentials();
-      Iterator<Token<? extends TokenIdentifier>> iter =
-          credentials.getAllTokens().iterator();
-      while (iter.hasNext()) {
-        Token<? extends TokenIdentifier> token = iter.next();
-        log.info("Token {}", token.getKind());
-        if (token.getKind().equals(AMRMTokenIdentifier.KIND_NAME)  ||
-            token.getKind().equals(DelegationTokenIdentifier.HDFS_DELEGATION_KIND)) {
-          iter.remove();
-        }
-      }
-      // at this point this credentials map is probably clear, but leaving this
-      // code to allow for future tokens...
-      containerCredentials = credentials;
+      processAMCredentials(securityConfiguration);
 
       if (securityEnabled) {
         secretManager.setMasterKey(
@@ -793,17 +777,19 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
         //tell the server what the ACLs are
         rpcService.getServer().refreshServiceAcl(serviceConf,
             new SliderAMPolicyProvider());
-        // perform keytab based login to establish kerberos authenticated
-        // principal.  Can do so now since AM registration with RM above required
-        // tokens associated to principal
-        String principal = securityConfiguration.getPrincipal();
-        File localKeytabFile =
-            securityConfiguration.getKeytabFile(instanceDefinition);
-        // Now log in...
-        login(principal, localKeytabFile);
-        // obtain new FS reference that should be kerberos based and different
-        // than the previously cached reference
-        fs = getClusterFS();
+        if (securityConfiguration.isKeytabProvided()) {
+          // perform keytab based login to establish kerberos authenticated
+          // principal.  Can do so now since AM registration with RM above required
+          // tokens associated to principal
+          String principal = securityConfiguration.getPrincipal();
+          File localKeytabFile =
+              securityConfiguration.getKeytabFile(instanceDefinition);
+          // Now log in...
+          login(principal, localKeytabFile);
+          // obtain new FS reference that should be kerberos based and different
+          // than the previously cached reference
+          fs = getClusterFS();
+        }
       }
 
       // extract container list
@@ -881,7 +867,8 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
     maybeStartMonkey();
 
     // setup token renewal and expiry handling for long lived apps
-//    if (SliderUtils.isHadoopClusterSecure(getConfig())) {
+//    if (!securityConfiguration.isKeytabProvided() &&
+//        SliderUtils.isHadoopClusterSecure(getConfig())) {
 //      fsDelegationTokenManager = new FsDelegationTokenManager(actionQueues);
 //      fsDelegationTokenManager.acquireDelegationToken(getConfig());
 //    }
@@ -929,6 +916,37 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
     return finish();
   }
 
+  private void processAMCredentials(SecurityConfiguration securityConfiguration)
+      throws IOException {
+    // process the initial user to obtain the set of user
+    // supplied credentials (tokens were passed in by client). Remove AMRM
+    // token and HDFS delegation token, the latter because we will provide an
+    // up to date token for container launches (getContainerCredentials()).
+    UserGroupInformation currentUser = UserGroupInformation.getCurrentUser();
+    Credentials credentials = currentUser.getCredentials();
+    List<Text> filteredTokens = new ArrayList<Text>();
+    filteredTokens.add(AMRMTokenIdentifier.KIND_NAME);
+
+    boolean keytabProvided = securityConfiguration.isKeytabProvided();
+    log.info("Slider AM Security Mode: {}", keytabProvided ? "KEYTAB" : "TOKEN");
+    if (keytabProvided) {
+      filteredTokens.add(DelegationTokenIdentifier.HDFS_DELEGATION_KIND);
+    }
+    Iterator<Token<? extends TokenIdentifier>> iter =
+        credentials.getAllTokens().iterator();
+    while (iter.hasNext()) {
+      Token<? extends TokenIdentifier> token = iter.next();
+      log.info("Token {}", token.getKind());
+      if (filteredTokens.contains(token.getKind())) {
+        log.debug("Filtering token {} from AM tokens", token.getKind());
+        iter.remove();
+      }
+    }
+    // at this point this credentials map is probably clear, but leaving this
+    // code to allow for future tokens...
+    containerCredentials = credentials;
+  }
+
   private int getPortToRequest(AggregateConf instanceDefinition)
       throws SliderException {
     int portToRequest = 0;
@@ -2034,10 +2052,13 @@ the registry with/without the new record format
     // the login is via a keytab (see above)
     Credentials credentials = new Credentials(containerCredentials);
     ByteBuffer tokens = null;
-    Token<? extends TokenIdentifier>[] hdfsTokens =
-        getClusterFS().getFileSystem().addDelegationTokens(
-            UserGroupInformation.getLoginUser().getShortUserName(), credentials);
-    if (hdfsTokens.length > 0) {
+    if (securityConfiguration.isKeytabProvided()) {
+      Token<? extends TokenIdentifier>[] hdfsTokens =
+          getClusterFS().getFileSystem().addDelegationTokens(
+              UserGroupInformation.getLoginUser().getShortUserName(),
+              credentials);
+    }
+    if (credentials.getAllTokens().size() > 0) {
       DataOutputBuffer dob = new DataOutputBuffer();
       credentials.writeTokenStorageToStream(dob);
       dob.close();

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/1bdf80cd/slider-core/src/main/java/org/apache/slider/server/appmaster/security/SecurityConfiguration.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/security/SecurityConfiguration.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/security/SecurityConfiguration.java
index 63a7543..4ff6916 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/security/SecurityConfiguration.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/security/SecurityConfiguration.java
@@ -99,15 +99,6 @@ public class SecurityConfiguration {
       String keytabName = instanceDefinition.getAppConfOperations()
           .getComponent(SliderKeys.COMPONENT_AM)
           .get(SliderXmlConfKeys.KEY_AM_LOGIN_KEYTAB_NAME);
-      if (SliderUtils.isUnset(keytabFullPath) && SliderUtils.isUnset(keytabName)) {
-        throw new SliderException(SliderExitCodes.EXIT_BAD_CONFIGURATION,
-                                  "Either a keytab path on the cluster host (%s) or a"
-                                  + " keytab to be retrieved from HDFS (%s) are"
-                                  + " required.  Please configure one of the keytab"
-                                  + " retrieval mechanisms.",
-                                  SliderXmlConfKeys.KEY_AM_KEYTAB_LOCAL_PATH,
-                                  SliderXmlConfKeys.KEY_AM_LOGIN_KEYTAB_NAME);
-      }
       if (SliderUtils.isSet(keytabFullPath) && SliderUtils.isSet(keytabName)) {
         throw new SliderException(SliderExitCodes.EXIT_BAD_CONFIGURATION,
                                   "Both a keytab on the cluster host (%s) and a"
@@ -141,6 +132,17 @@ public class SecurityConfiguration {
     return principal;
   }
 
+  public boolean isKeytabProvided() {
+    boolean keytabProvided = instanceDefinition.getAppConfOperations()
+                    .getComponent(SliderKeys.COMPONENT_AM)
+                    .get(SliderXmlConfKeys.KEY_AM_KEYTAB_LOCAL_PATH) != null ||
+                instanceDefinition.getAppConfOperations()
+                    .getComponent(SliderKeys.COMPONENT_AM).
+                    get(SliderXmlConfKeys.KEY_AM_LOGIN_KEYTAB_NAME) != null;
+    return keytabProvided;
+
+  }
+
   public File getKeytabFile(AggregateConf instanceDefinition)
       throws SliderException, IOException {
     String keytabFullPath = instanceDefinition.getAppConfOperations()

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/1bdf80cd/slider-core/src/test/groovy/org/apache/slider/server/appmaster/security/SecurityConfigurationTest.groovy
----------------------------------------------------------------------
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/security/SecurityConfigurationTest.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/security/SecurityConfigurationTest.groovy
index 4b60ead..e543b7c 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/security/SecurityConfigurationTest.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/security/SecurityConfigurationTest.groovy
@@ -118,21 +118,6 @@ public class SecurityConfigurationTest {
     }
 
     @Test
-    public void testNoKeytabMechanismConfigured() throws Throwable {
-        Configuration config = new Configuration()
-        config.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, "kerberos")
-        AggregateConf aggregateConf = new AggregateConf();
-        MapOperations compOps =
-            aggregateConf.appConfOperations.getOrAddComponent(SliderKeys.COMPONENT_AM)
-        compOps.put(SliderXmlConfKeys.KEY_KEYTAB_PRINCIPAL, "test")
-
-        shouldFail(SliderException) {
-            SecurityConfiguration securityConfiguration =
-                new SecurityConfiguration(config, aggregateConf, "testCluster")
-        }
-    }
-
-    @Test
     public void testMissingPrincipalButLoginWithDistributedConfig() throws Throwable {
         Configuration config = new Configuration()
         config.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, "kerberos")