You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@slider.apache.org by jm...@apache.org on 2014/10/11 03:28:21 UTC

git commit: SLIDER-491 some corrections to delegation retrieval code and ability to specify full keytab location in HDFS

Repository: incubator-slider
Updated Branches:
  refs/heads/develop da67c440b -> 6f0d9cb65


SLIDER-491 some corrections to delegation retrieval code and ability to specify full keytab location in HDFS


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

Branch: refs/heads/develop
Commit: 6f0d9cb6537b7eb3498cab44ff4cfa1404507e7c
Parents: da67c44
Author: Jon Maron <jm...@hortonworks.com>
Authored: Fri Oct 10 18:27:46 2014 -0700
Committer: Jon Maron <jm...@hortonworks.com>
Committed: Fri Oct 10 18:27:46 2014 -0700

----------------------------------------------------------------------
 .../apache/slider/common/SliderXmlConfKeys.java |  1 +
 .../slider/common/tools/CoreFileSystem.java     | 18 ++++---
 .../providers/agent/AgentProviderService.java   | 30 ++++++-----
 .../slideram/SliderAMClientProvider.java        | 49 +++++++++++++++++-
 .../server/appmaster/SliderAppMaster.java       | 37 +++++++-------
 .../security/SecurityConfiguration.java         | 52 ++++----------------
 .../security/SecurityConfigurationTest.groovy   | 17 +++++++
 7 files changed, 122 insertions(+), 82 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/6f0d9cb6/slider-core/src/main/java/org/apache/slider/common/SliderXmlConfKeys.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/common/SliderXmlConfKeys.java b/slider-core/src/main/java/org/apache/slider/common/SliderXmlConfKeys.java
index cc2a03f..6bc007b 100644
--- a/slider-core/src/main/java/org/apache/slider/common/SliderXmlConfKeys.java
+++ b/slider-core/src/main/java/org/apache/slider/common/SliderXmlConfKeys.java
@@ -145,6 +145,7 @@ public interface SliderXmlConfKeys {
       "hadoop.http.filter.initializers";
   String KEY_KEYSTORE_LOCATION = "ssl.server.keystore.location";
   String KEY_AM_LOGIN_KEYTAB_NAME = "slider.am.login.keytab.name";
+  String KEY_HDFS_KEYTAB_DIR = "slider.hdfs.keytab.dir";
   String KEY_AM_KEYTAB_LOCAL_PATH = "slider.am.keytab.local.path";
   String KEY_KEYTAB_PRINCIPAL = "slider.keytab.principal.name";
   String KEY_SECURITY_ENABLED = "site.global.security_enabled";

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/6f0d9cb6/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java b/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java
index 2ea371b..9a96bd1 100644
--- a/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java
+++ b/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java
@@ -139,13 +139,17 @@ public class CoreFileSystem {
    *
    * @return the path for keytab installation location
    */
-  public Path buildKeytabPath(String keytabName, String applicationName) {
-    Preconditions.checkNotNull(applicationName);
-    Path basePath = getBaseApplicationPath();
-    Path baseKeytabDir = new Path(basePath, SliderKeys.KEYTAB_DIR);
-    Path appKeytabDir = new Path(baseKeytabDir, applicationName);
-    return keytabName == null ? appKeytabDir :
-        new Path(appKeytabDir, keytabName);
+  public Path buildKeytabPath(String keytabDir, String keytabName, String clusterName) {
+    Path homePath = getHomeDirectory();
+    Path baseKeytabDir;
+    if (keytabDir != null) {
+      baseKeytabDir = new Path(homePath, keytabDir);
+    } else {
+      baseKeytabDir = new Path(buildClusterDirPath(clusterName),
+                               SliderKeys.KEYTAB_DIR);
+    }
+    return keytabName == null ? baseKeytabDir :
+        new Path(baseKeytabDir, keytabName);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/6f0d9cb6/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 330ffa3..44777c3 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
@@ -357,20 +357,24 @@ public class AgentProviderService extends AbstractProviderService implements
     }
 
     if (SliderUtils.isHadoopClusterSecure(getConfig())) {
-      String keytabFullPath = instanceDefinition.getAppConfOperations()
+      String keytabPathOnHost = instanceDefinition.getAppConfOperations()
           .getComponent(SliderKeys.COMPONENT_AM).get(
               SliderXmlConfKeys.KEY_AM_KEYTAB_LOCAL_PATH);
-      String amKeytabName = instanceDefinition.getAppConfOperations()
-          .getComponent(SliderKeys.COMPONENT_AM).get(
-              SliderXmlConfKeys.KEY_AM_LOGIN_KEYTAB_NAME);
-      if (SliderUtils.isUnset(keytabFullPath)) {
+      if (SliderUtils.isUnset(keytabPathOnHost)) {
+        String amKeytabName = instanceDefinition.getAppConfOperations()
+            .getComponent(SliderKeys.COMPONENT_AM).get(
+                SliderXmlConfKeys.KEY_AM_LOGIN_KEYTAB_NAME);
+        String keytabDir = instanceDefinition.getAppConfOperations()
+            .getComponent(SliderKeys.COMPONENT_AM).get(
+                SliderXmlConfKeys.KEY_HDFS_KEYTAB_DIR);
         // we need to localize the keytab files in the directory
-        Path keytabDir = fileSystem.buildKeytabPath(null,
-          getAmState().getApplicationName());
-        FileStatus[] keytabs = fileSystem.getFileSystem().listStatus(keytabDir);
+        Path keytabDirPath = fileSystem.buildKeytabPath(keytabDir, null,
+                                                        clusterName);
+        FileStatus[] keytabs = fileSystem.getFileSystem().listStatus(keytabDirPath);
         LocalResource keytabRes;
         for (FileStatus keytab : keytabs) {
-          if (!amKeytabName.equals(keytab.getPath().getName())) {
+          if (!amKeytabName.equals(keytab.getPath().getName())
+              && keytab.getPath().getName().endsWith(".keytab")) {
             log.info("Localizing keytab {}", keytab.getPath().getName());
             keytabRes = fileSystem.createAmResource(keytab.getPath(),
               LocalResourceType.FILE);
@@ -678,12 +682,12 @@ public class AgentProviderService extends AbstractProviderService implements
 
       serviceRecord.addInternalEndpoint(
           new Endpoint(CustomRegistryConstants.AGENT_SECURE_REST_API,
-              ProtocolTypes.PROTOCOL_REST,
-              restURL.toURI()));
+                       ProtocolTypes.PROTOCOL_REST,
+                       restURL.toURI()));
       serviceRecord.addInternalEndpoint(
           new Endpoint(CustomRegistryConstants.AGENT_ONEWAY_REST_API,
-              ProtocolTypes.PROTOCOL_REST,
-              agentStatusURL.toURI()));
+                       ProtocolTypes.PROTOCOL_REST,
+                       agentStatusURL.toURI()));
     } catch (URISyntaxException e) {
       throw new IOException(e);
     }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/6f0d9cb6/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 991a6b1..5edf1bf 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
@@ -25,12 +25,15 @@ import org.apache.curator.CuratorZookeeperClient;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.yarn.api.records.LocalResource;
+import org.apache.hadoop.yarn.api.records.LocalResourceType;
 import org.apache.hadoop.yarn.api.records.Resource;
 import org.apache.slider.api.InternalKeys;
 import org.apache.slider.api.ResourceKeys;
 import org.apache.slider.api.RoleKeys;
 import org.apache.slider.common.SliderKeys;
+import org.apache.slider.common.SliderXmlConfKeys;
 import org.apache.slider.common.tools.SliderFileSystem;
 import org.apache.slider.common.tools.SliderUtils;
 import org.apache.slider.core.conf.AggregateConf;
@@ -206,8 +209,12 @@ public class SliderAMClientProvider extends AbstractClientProvider
     ProviderUtils.addDependencyJars(providerResources, fileSystem, tempPath,
                                     libdir, jars,
                                     classes);
-    
-    launcher.addLocalResources(providerResources);
+
+    addKeytabResourceIfNecessary(fileSystem,
+                                 launcher,
+                                 instanceDescription,
+                                 providerResources);
+
     //also pick up all env variables from a map
     launcher.copyEnvVars(
       instanceDescription.getInternalOperations().getOrAddComponent(
@@ -215,6 +222,44 @@ public class SliderAMClientProvider extends AbstractClientProvider
   }
 
   /**
+   * If the cluster is secure, and an HDFS installed keytab is available for AM
+   * 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 {
+    if (UserGroupInformation.isSecurityEnabled()) {
+      String keytabPathOnHost = instanceDescription.getAppConfOperations()
+          .getComponent(SliderKeys.COMPONENT_AM).get(
+              SliderXmlConfKeys.KEY_AM_KEYTAB_LOCAL_PATH);
+      if (SliderUtils.isUnset(keytabPathOnHost)) {
+        String amKeytabName = instanceDescription.getAppConfOperations()
+            .getComponent(SliderKeys.COMPONENT_AM).get(
+                SliderXmlConfKeys.KEY_AM_LOGIN_KEYTAB_NAME);
+        String keytabDir = instanceDescription.getAppConfOperations()
+            .getComponent(SliderKeys.COMPONENT_AM).get(
+                SliderXmlConfKeys.KEY_HDFS_KEYTAB_DIR);
+        Path keytabPath = fileSystem.buildKeytabPath(keytabDir, amKeytabName,
+                                                     instanceDescription.getName());
+        LocalResource keytabRes = fileSystem.createAmResource(keytabPath,
+                                                LocalResourceType.FILE);
+
+         providerResources.put(SliderKeys.KEYTAB_DIR + "/" +
+                               amKeytabName, keytabRes);
+      }
+    }
+    launcher.addLocalResources(providerResources);
+  }
+
+  /**
    * Update the AM resource with any local needs
    * @param capability capability to update
    */

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/6f0d9cb6/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 4baa11c..a887cf8 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
@@ -34,6 +34,7 @@ import org.apache.hadoop.security.Credentials;
 import org.apache.hadoop.security.SaslRpcServer;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.token.Token;
+import org.apache.hadoop.security.token.TokenIdentifier;
 import org.apache.hadoop.service.Service;
 import org.apache.hadoop.service.ServiceStateChangeListener;
 import org.apache.hadoop.yarn.api.ApplicationConstants;
@@ -234,7 +235,7 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
   /**
    * token blob
    */
-  private Credentials containerTokens;
+  private Credentials containerCredentials;
 
   private WorkflowRpcService rpcService;
 
@@ -716,12 +717,13 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
       // 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 (getContainerTokens()).
+      // up to date token for container launches (getContainerCredentials()).
       UserGroupInformation currentUser = UserGroupInformation.getCurrentUser();
       Credentials credentials = currentUser.getCredentials();
-      Iterator<Token<?>> iter = credentials.getAllTokens().iterator();
+      Iterator<Token<? extends TokenIdentifier>> iter =
+          credentials.getAllTokens().iterator();
       while (iter.hasNext()) {
-        Token<?> token = iter.next();
+        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)) {
@@ -730,7 +732,7 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
       }
       // at this point this credentials map is probably clear, but leaving this
       // code to allow for future tokens...
-      containerTokens = credentials;
+      containerCredentials = credentials;
 
       if (securityEnabled) {
         secretManager.setMasterKey(
@@ -744,8 +746,8 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
         // principal.  Can do so now since AM registration with RM above required
         // tokens associated to principal
         String principal = securityConfiguration.getPrincipal();
-        File localKeytabFile = securityConfiguration.getKeytabFile(
-            fs, instanceDefinition, principal);
+        File localKeytabFile =
+            securityConfiguration.getKeytabFile(instanceDefinition);
         // Now log in...
         login(principal, localKeytabFile);
         // obtain new FS reference that should be kerberos based and different
@@ -898,13 +900,14 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
     }
     Credentials credentials =
         user.getCredentials();
-    Iterator<Token<?>> iter = credentials.getAllTokens().iterator();
+    Iterator<Token<? extends TokenIdentifier>> iter =
+        credentials.getAllTokens().iterator();
     while (iter.hasNext()) {
-      Token<?> token = iter.next();
+      Token<? extends TokenIdentifier> token = iter.next();
       log.info("Token {}", token.getKind());
       if (token.getKind().equals(
           DelegationTokenIdentifier.HDFS_DELEGATION_KIND)) {
-        log.info("Unexpected HDFS delegation token.  Removing...");
+        log.info("HDFS delegation token {}.  Removing...", token);
         iter.remove();
       }
     }
@@ -1907,7 +1910,7 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
     // inside the distributed shell.
 
     // add current HDFS delegation token with an up to date token
-    ByteBuffer tokens = getContainerTokens();
+    ByteBuffer tokens = getContainerCredentials();
 
     if (tokens != null) {
       ctx.setTokens(tokens);
@@ -1918,15 +1921,15 @@ public class SliderAppMaster extends AbstractSliderLaunchedService
     nmClientAsync.startContainerAsync(container, ctx);
   }
 
-  private ByteBuffer getContainerTokens() throws IOException {
+  private ByteBuffer getContainerCredentials() throws IOException {
     // a delegation token can be retrieved from filesystem since
     // the login is via a keytab (see above)
+    Credentials credentials = new Credentials(containerCredentials);
     ByteBuffer tokens = null;
-    Token hdfsToken = getClusterFS().getFileSystem().getDelegationToken
-        (UserGroupInformation.getLoginUser().getShortUserName());
-    if (hdfsToken != null) {
-      Credentials credentials = new Credentials(containerTokens);
-      credentials.addToken(hdfsToken.getKind(), hdfsToken);
+    Token<? extends TokenIdentifier> hdfsTokens[] =
+        getClusterFS().getFileSystem().addDelegationTokens(
+            UserGroupInformation.getLoginUser().getShortUserName(), credentials);
+    if (hdfsTokens.length > 0) {
       DataOutputBuffer dob = new DataOutputBuffer();
       credentials.writeTokenStorageToStream(dob);
       dob.close();

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/6f0d9cb6/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 e5cdad2..63a7543 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
@@ -141,8 +141,7 @@ public class SecurityConfiguration {
     return principal;
   }
 
-  public File getKeytabFile(SliderFileSystem fs,
-                             AggregateConf instanceDefinition, String principal)
+  public File getKeytabFile(AggregateConf instanceDefinition)
       throws SliderException, IOException {
     String keytabFullPath = instanceDefinition.getAppConfOperations()
         .getComponent(SliderKeys.COMPONENT_AM)
@@ -151,52 +150,19 @@ public class SecurityConfiguration {
     if (SliderUtils.isUnset(keytabFullPath)) {
       // get the keytab
       String keytabName = instanceDefinition.getAppConfOperations()
-          .getComponent(SliderKeys.COMPONENT_AM).get(SliderXmlConfKeys.KEY_AM_LOGIN_KEYTAB_NAME);
-      log.info("No host keytab file path specified. Downloading keytab {}"
-               + " from HDFS to perform login of using principal {}",
-               keytabName, principal);
+          .getComponent(SliderKeys.COMPONENT_AM).
+              get(SliderXmlConfKeys.KEY_AM_LOGIN_KEYTAB_NAME);
+      log.info("No host keytab file path specified. Will attempt to retrieve"
+               + " keytab file {} as a local resource for the container",
+               keytabName);
       // download keytab to local, protected directory
-      localKeytabFile = getFileFromFileSystem(fs, keytabName);
+      localKeytabFile = new File(SliderKeys.KEYTAB_DIR, keytabName);
     } else {
-      log.info("Leveraging host keytab file {} to login  principal {}",
-               keytabFullPath, principal);
+      log.info("Leveraging host keytab file {} for login",
+               keytabFullPath);
       localKeytabFile = new File(keytabFullPath);
     }
     return localKeytabFile;
   }
 
-  /**
-   * Download the keytab file from FileSystem to local file.
-   * @param fs
-   * @param keytabName
-   * @return
-   * @throws SliderException
-   * @throws IOException
-   */
-  protected File getFileFromFileSystem(SliderFileSystem fs, String keytabName)
-      throws SliderException, IOException {
-    File keytabDestinationDir = new File(
-        FileUtils.getTempDirectory().getAbsolutePath() +
-        "/keytab" + System.currentTimeMillis());
-    if (!keytabDestinationDir.mkdirs()) {
-      throw new SliderException("Unable to create local keytab directory");
-    }
-    RawLocalFileSystem fileSystem = new RawLocalFileSystem();
-    // allow app user to access local keytab dir
-    FsPermission permissions = new FsPermission(FsAction.ALL, FsAction.NONE,
-                                                FsAction.NONE);
-    fileSystem.setPermission(new Path(keytabDestinationDir.getAbsolutePath()),
-                             permissions);
-
-    Path keytabPath = fs.buildKeytabPath(keytabName, clusterName);
-    File localKeytabFile = new File(keytabDestinationDir, keytabName);
-    FileUtil.copy(fs.getFileSystem(), keytabPath,
-                  localKeytabFile,
-                  false, configuration);
-    // set permissions on actual keytab file to be read-only for user
-    permissions = new FsPermission(FsAction.READ, FsAction.NONE, FsAction.NONE);
-    fileSystem.setPermission(new Path(localKeytabFile.getAbsolutePath()),
-                             permissions);
-    return localKeytabFile;
-  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/6f0d9cb6/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 4ef142a..4b60ead 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
@@ -157,4 +157,21 @@ public class SecurityConfigurationTest {
         SecurityConfiguration securityConfiguration =
             new SecurityConfiguration(config, aggregateConf, "testCluster")
     }
+
+    @Test
+    public void testKeypathLocationOnceLocalized() 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_AM_LOGIN_KEYTAB_NAME, "some.keytab")
+
+        SecurityConfiguration securityConfiguration =
+            new SecurityConfiguration(config, aggregateConf, "testCluster")
+
+        assert new File(SliderKeys.KEYTAB_DIR, "some.keytab").getAbsolutePath() ==
+               securityConfiguration.getKeytabFile(aggregateConf).getAbsolutePath()
+    }
+
 }