You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by vi...@apache.org on 2014/10/01 19:15:02 UTC
git commit: YARN-1972. Added a secure container-executor for Windows.
Contributed by Remus Rusanu.
Repository: hadoop
Updated Branches:
refs/heads/trunk 5ca97f1e6 -> ba7f31c2e
YARN-1972. Added a secure container-executor for Windows. Contributed by Remus Rusanu.
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/ba7f31c2
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/ba7f31c2
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/ba7f31c2
Branch: refs/heads/trunk
Commit: ba7f31c2ee8d23ecb183f88920ef06053c0b9769
Parents: 5ca97f1
Author: Vinod Kumar Vavilapalli <vi...@apache.org>
Authored: Wed Oct 1 10:14:41 2014 -0700
Committer: Vinod Kumar Vavilapalli <vi...@apache.org>
Committed: Wed Oct 1 10:14:41 2014 -0700
----------------------------------------------------------------------
hadoop-yarn-project/CHANGES.txt | 3 +
.../hadoop/yarn/conf/YarnConfiguration.java | 6 +
.../server/nodemanager/ContainerExecutor.java | 19 ++-
.../nodemanager/DefaultContainerExecutor.java | 70 ++++----
.../nodemanager/LinuxContainerExecutor.java | 10 +-
.../WindowsSecureContainerExecutor.java | 171 +++++++++++++++++++
.../launcher/ContainerLaunch.java | 2 +
.../localizer/ContainerLocalizer.java | 25 +++
.../nodemanager/TestContainerExecutor.java | 8 +-
.../TestDefaultContainerExecutor.java | 4 +-
.../src/site/apt/SecureContainer.apt.vm | 118 +++++++++++++
.../hadoop-yarn-site/src/site/apt/index.apt.vm | 2 +
12 files changed, 392 insertions(+), 46 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/CHANGES.txt
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt
index 9badfac..3878ca1 100644
--- a/hadoop-yarn-project/CHANGES.txt
+++ b/hadoop-yarn-project/CHANGES.txt
@@ -118,6 +118,9 @@ Release 2.6.0 - UNRELEASED
YARN-1063. Augmented Hadoop common winutils to have the ability to create
containers as domain users. (Remus Rusanu via vinodkv)
+ YARN-1972. Added a secure container-executor for Windows. (Remus Rusanu via
+ vinodkv)
+
IMPROVEMENTS
YARN-2197. Add a link to YARN CHANGES.txt in the left side of doc
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
index 4ea2188..25df4ef 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
@@ -928,6 +928,12 @@ public class YarnConfiguration extends Configuration {
public static final long DEFAULT_NM_LINUX_CONTAINER_CGROUPS_DELETE_TIMEOUT =
1000;
+
+ /**
+ /* The Windows group that the windows-secure-container-executor should run as.
+ */
+ public static final String NM_WINDOWS_SECURE_CONTAINER_GROUP =
+ NM_PREFIX + "windows-secure-container-executor.group";
/** T-file compression types used to compress aggregated logs.*/
public static final String NM_LOG_AGG_COMPRESSION_TYPE =
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java
index 7391872..7dbceaf 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java
@@ -79,6 +79,20 @@ public abstract class ContainerExecutor implements Configurable {
public abstract void init() throws IOException;
/**
+ * On Windows the ContainerLaunch creates a temporary empty jar to workaround the CLASSPATH length
+ * In a secure cluster this jar must be localized so that the container has access to it
+ * This function localizes on-demand the jar.
+ *
+ * @param classPathJar
+ * @param owner
+ * @throws IOException
+ */
+ public void localizeClasspathJar(Path classPathJar, String owner) throws IOException {
+ // For the default container this is a no-op
+ // The WindowsSecureContainerExecutor overrides this
+ }
+
+ /**
* Prepare the environment for containers in this application to execute.
* For $x in local.dirs
* create $x/$user/$appId
@@ -264,8 +278,8 @@ public abstract class ContainerExecutor implements Configurable {
* and associate the given groupId in a process group. On
* non-Windows, groupId is ignored.
*/
- protected static String[] getRunCommand(String command, String groupId,
- Configuration conf) {
+ protected String[] getRunCommand(String command, String groupId,
+ String userName, Path pidFile, Configuration conf) {
boolean containerSchedPriorityIsSet = false;
int containerSchedPriorityAdjustment =
YarnConfiguration.DEFAULT_NM_CONTAINER_EXECUTOR_SCHED_PRIORITY;
@@ -396,5 +410,4 @@ public abstract class ContainerExecutor implements Configurable {
}
}
}
-
}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
index a7af1c5..23d2e72 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
@@ -61,7 +61,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
private static final int WIN_MAX_PATH = 260;
- private final FileContext lfs;
+ protected final FileContext lfs;
public DefaultContainerExecutor() {
try {
@@ -75,11 +75,19 @@ public class DefaultContainerExecutor extends ContainerExecutor {
this.lfs = lfs;
}
+ protected void copyFile(Path src, Path dst, String owner) throws IOException {
+ lfs.util().copy(src, dst);
+ }
+
+ protected void setScriptExecutable(Path script, String owner) throws IOException {
+ lfs.setPermission(script, ContainerExecutor.TASK_LAUNCH_SCRIPT_PERMISSION);
+ }
+
@Override
public void init() throws IOException {
// nothing to do or verify here
}
-
+
@Override
public synchronized void startLocalizer(Path nmPrivateContainerTokensPath,
InetSocketAddress nmAddr, String user, String appId, String locId,
@@ -93,14 +101,14 @@ public class DefaultContainerExecutor extends ContainerExecutor {
createUserLocalDirs(localDirs, user);
createUserCacheDirs(localDirs, user);
createAppDirs(localDirs, user, appId);
- createAppLogDirs(appId, logDirs);
+ createAppLogDirs(appId, logDirs, user);
// TODO: Why pick first app dir. The same in LCE why not random?
Path appStorageDir = getFirstApplicationDir(localDirs, user, appId);
String tokenFn = String.format(ContainerLocalizer.TOKEN_FILE_NAME_FMT, locId);
Path tokenDst = new Path(appStorageDir, tokenFn);
- lfs.util().copy(nmPrivateContainerTokensPath, tokenDst);
+ copyFile(nmPrivateContainerTokensPath, tokenDst, user);
LOG.info("Copying from " + nmPrivateContainerTokensPath + " to " + tokenDst);
lfs.setWorkingDirectory(appStorageDir);
LOG.info("CWD set to " + appStorageDir + " = " + lfs.getWorkingDirectory());
@@ -129,30 +137,29 @@ public class DefaultContainerExecutor extends ContainerExecutor {
Path appCacheDir = new Path(userdir, ContainerLocalizer.APPCACHE);
Path appDir = new Path(appCacheDir, appIdStr);
Path containerDir = new Path(appDir, containerIdStr);
- createDir(containerDir, dirPerm, true);
+ createDir(containerDir, dirPerm, true, userName);
}
// Create the container log-dirs on all disks
- createContainerLogDirs(appIdStr, containerIdStr, logDirs);
+ createContainerLogDirs(appIdStr, containerIdStr, logDirs, userName);
Path tmpDir = new Path(containerWorkDir,
YarnConfiguration.DEFAULT_CONTAINER_TEMP_DIR);
- createDir(tmpDir, dirPerm, false);
+ createDir(tmpDir, dirPerm, false, userName);
// copy launch script to work dir
Path launchDst =
new Path(containerWorkDir, ContainerLaunch.CONTAINER_SCRIPT);
- lfs.util().copy(nmPrivateContainerScriptPath, launchDst);
+ copyFile(nmPrivateContainerScriptPath, launchDst, userName);
// copy container tokens to work dir
Path tokenDst =
new Path(containerWorkDir, ContainerLaunch.FINAL_CONTAINER_TOKENS_FILE);
- lfs.util().copy(nmPrivateTokensPath, tokenDst);
+ copyFile(nmPrivateTokensPath, tokenDst, userName);
// Create new local launch wrapper script
- LocalWrapperScriptBuilder sb = Shell.WINDOWS ?
- new WindowsLocalWrapperScriptBuilder(containerIdStr, containerWorkDir) :
- new UnixLocalWrapperScriptBuilder(containerWorkDir);
+ LocalWrapperScriptBuilder sb = getLocalWrapperScriptBuilder(
+ containerIdStr, containerWorkDir);
// Fail fast if attempting to launch the wrapper script would fail due to
// Windows path length limitation.
@@ -178,14 +185,12 @@ public class DefaultContainerExecutor extends ContainerExecutor {
// fork script
ShellCommandExecutor shExec = null;
try {
- lfs.setPermission(launchDst,
- ContainerExecutor.TASK_LAUNCH_SCRIPT_PERMISSION);
- lfs.setPermission(sb.getWrapperScriptPath(),
- ContainerExecutor.TASK_LAUNCH_SCRIPT_PERMISSION);
+ setScriptExecutable(launchDst, userName);
+ setScriptExecutable(sb.getWrapperScriptPath(), userName);
// Setup command to run
String[] command = getRunCommand(sb.getWrapperScriptPath().toString(),
- containerIdStr, this.getConf());
+ containerIdStr, userName, pidFile, this.getConf());
LOG.info("launchContainer: " + Arrays.toString(command));
shExec = new ShellCommandExecutor(
@@ -241,7 +246,14 @@ public class DefaultContainerExecutor extends ContainerExecutor {
return 0;
}
- private abstract class LocalWrapperScriptBuilder {
+ protected LocalWrapperScriptBuilder getLocalWrapperScriptBuilder(
+ String containerIdStr, Path containerWorkDir) {
+ return Shell.WINDOWS ?
+ new WindowsLocalWrapperScriptBuilder(containerIdStr, containerWorkDir) :
+ new UnixLocalWrapperScriptBuilder(containerWorkDir);
+ }
+
+ protected abstract class LocalWrapperScriptBuilder {
private final Path wrapperScriptPath;
@@ -449,7 +461,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
* $logdir/$user/$appId */
static final short LOGDIR_PERM = (short)0710;
- private Path getFirstApplicationDir(List<String> localDirs, String user,
+ protected Path getFirstApplicationDir(List<String> localDirs, String user,
String appId) {
return getApplicationDir(new Path(localDirs.get(0)), user, appId);
}
@@ -472,8 +484,8 @@ public class DefaultContainerExecutor extends ContainerExecutor {
ContainerLocalizer.FILECACHE);
}
- private void createDir(Path dirPath, FsPermission perms,
- boolean createParent) throws IOException {
+ protected void createDir(Path dirPath, FsPermission perms,
+ boolean createParent, String user) throws IOException {
lfs.mkdir(dirPath, perms, createParent);
if (!perms.equals(perms.applyUMask(lfs.getUMask()))) {
lfs.setPermission(dirPath, perms);
@@ -493,7 +505,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
for (String localDir : localDirs) {
// create $local.dir/usercache/$user and its immediate parent
try {
- createDir(getUserCacheDir(new Path(localDir), user), userperms, true);
+ createDir(getUserCacheDir(new Path(localDir), user), userperms, true, user);
} catch (IOException e) {
LOG.warn("Unable to create the user directory : " + localDir, e);
continue;
@@ -529,7 +541,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
Path localDirPath = new Path(localDir);
final Path appDir = getAppcacheDir(localDirPath, user);
try {
- createDir(appDir, appCachePerms, true);
+ createDir(appDir, appCachePerms, true, user);
appcacheDirStatus = true;
} catch (IOException e) {
LOG.warn("Unable to create app cache directory : " + appDir, e);
@@ -537,7 +549,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
// create $local.dir/usercache/$user/filecache
final Path distDir = getFileCacheDir(localDirPath, user);
try {
- createDir(distDir, fileperms, true);
+ createDir(distDir, fileperms, true, user);
distributedCacheDirStatus = true;
} catch (IOException e) {
LOG.warn("Unable to create file cache directory : " + distDir, e);
@@ -570,7 +582,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
Path fullAppDir = getApplicationDir(new Path(localDir), user, appId);
// create $local.dir/usercache/$user/appcache/$appId
try {
- createDir(fullAppDir, appperms, true);
+ createDir(fullAppDir, appperms, true, user);
initAppDirStatus = true;
} catch (IOException e) {
LOG.warn("Unable to create app directory " + fullAppDir.toString(), e);
@@ -586,7 +598,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
/**
* Create application log directories on all disks.
*/
- void createAppLogDirs(String appId, List<String> logDirs)
+ void createAppLogDirs(String appId, List<String> logDirs, String user)
throws IOException {
boolean appLogDirStatus = false;
@@ -595,7 +607,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
// create $log.dir/$appid
Path appLogDir = new Path(rootLogDir, appId);
try {
- createDir(appLogDir, appLogDirPerms, true);
+ createDir(appLogDir, appLogDirPerms, true, user);
} catch (IOException e) {
LOG.warn("Unable to create the app-log directory : " + appLogDir, e);
continue;
@@ -612,7 +624,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
* Create application log directories on all disks.
*/
void createContainerLogDirs(String appId, String containerId,
- List<String> logDirs) throws IOException {
+ List<String> logDirs, String user) throws IOException {
boolean containerLogDirStatus = false;
FsPermission containerLogDirPerms = new FsPermission(LOGDIR_PERM);
@@ -621,7 +633,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
Path appLogDir = new Path(rootLogDir, appId);
Path containerLogDir = new Path(appLogDir, containerId);
try {
- createDir(containerLogDir, containerLogDirPerms, true);
+ createDir(containerLogDir, containerLogDirPerms, true, user);
} catch (IOException e) {
LOG.warn("Unable to create the container-log directory : "
+ appLogDir, e);
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
index 6b8dd28..b4ecfba 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
@@ -220,15 +220,7 @@ public class LinuxContainerExecutor extends ContainerExecutor {
if (javaLibPath != null) {
command.add("-Djava.library.path=" + javaLibPath);
}
- command.add(ContainerLocalizer.class.getName());
- command.add(user);
- command.add(appId);
- command.add(locId);
- command.add(nmAddr.getHostName());
- command.add(Integer.toString(nmAddr.getPort()));
- for (String dir : localDirs) {
- command.add(dir);
- }
+ ContainerLocalizer.buildMainArgs(command, user, appId, locId, nmAddr, localDirs);
String[] commandArray = command.toArray(new String[command.size()]);
ShellCommandExecutor shExec = new ShellCommandExecutor(commandArray);
if (LOG.isDebugEnabled()) {
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/WindowsSecureContainerExecutor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/WindowsSecureContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/WindowsSecureContainerExecutor.java
new file mode 100644
index 0000000..30beaf8
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/WindowsSecureContainerExecutor.java
@@ -0,0 +1,171 @@
+/**
+ * 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.nodemanager;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.util.Shell;
+import org.apache.hadoop.util.Shell.ShellCommandExecutor;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor.LocalWrapperScriptBuilder;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.ContainerLocalizer;
+
+/**
+ * Windows secure container executor. Uses winutils task createAsUser.
+ *
+ */
+public class WindowsSecureContainerExecutor extends DefaultContainerExecutor {
+
+ private static final Log LOG = LogFactory
+ .getLog(WindowsSecureContainerExecutor.class);
+
+ private class WindowsSecureWrapperScriptBuilder
+ extends LocalWrapperScriptBuilder {
+
+ public WindowsSecureWrapperScriptBuilder(Path containerWorkDir) {
+ super(containerWorkDir);
+ }
+
+ @Override
+ protected void writeLocalWrapperScript(Path launchDst, Path pidFile, PrintStream pout) {
+ pout.format("@call \"%s\"", launchDst);
+ }
+ }
+
+ private String nodeManagerGroup;
+
+ @Override
+ public void setConf(Configuration conf) {
+ super.setConf(conf);
+ nodeManagerGroup = conf.get(YarnConfiguration.NM_WINDOWS_SECURE_CONTAINER_GROUP);
+ }
+
+ @Override
+ protected String[] getRunCommand(String command, String groupId,
+ String userName, Path pidFile, Configuration conf) {
+ return new String[] { Shell.WINUTILS, "task", "createAsUser", groupId, userName,
+ pidFile.toString(), "cmd /c " + command };
+ }
+
+ @Override
+ protected LocalWrapperScriptBuilder getLocalWrapperScriptBuilder(
+ String containerIdStr, Path containerWorkDir) {
+ return new WindowsSecureWrapperScriptBuilder(containerWorkDir);
+ }
+
+ @Override
+ protected void copyFile(Path src, Path dst, String owner) throws IOException {
+ super.copyFile(src, dst, owner);
+ lfs.setOwner(dst, owner, nodeManagerGroup);
+ }
+
+ @Override
+ protected void createDir(Path dirPath, FsPermission perms,
+ boolean createParent, String owner) throws IOException {
+ super.createDir(dirPath, perms, createParent, owner);
+ lfs.setOwner(dirPath, owner, nodeManagerGroup);
+ }
+
+ @Override
+ protected void setScriptExecutable(Path script, String owner) throws IOException {
+ super.setScriptExecutable(script, null);
+ lfs.setOwner(script, owner, nodeManagerGroup);
+ }
+
+ @Override
+ public void localizeClasspathJar(Path classpathJar, String owner) throws IOException {
+ lfs.setOwner(classpathJar, owner, nodeManagerGroup);
+ }
+
+ @Override
+ public void startLocalizer(Path nmPrivateContainerTokens,
+ InetSocketAddress nmAddr, String user, String appId, String locId,
+ List<String> localDirs, List<String> logDirs) throws IOException,
+ InterruptedException {
+
+ createUserLocalDirs(localDirs, user);
+ createUserCacheDirs(localDirs, user);
+ createAppDirs(localDirs, user, appId);
+ createAppLogDirs(appId, logDirs, user);
+
+ // TODO: Why pick first app dir. The same in LCE why not random?
+ Path appStorageDir = getFirstApplicationDir(localDirs, user, appId);
+
+ String tokenFn = String.format(ContainerLocalizer.TOKEN_FILE_NAME_FMT, locId);
+ Path tokenDst = new Path(appStorageDir, tokenFn);
+ LOG.info("Copying from " + nmPrivateContainerTokens + " to " + tokenDst);
+ copyFile(nmPrivateContainerTokens, tokenDst, user);
+
+ List<String> command ;
+ String[] commandArray;
+ ShellCommandExecutor shExec;
+
+ File cwdApp = new File(appStorageDir.toString());
+ LOG.info(String.format("cwdApp: %s", cwdApp));
+
+ command = new ArrayList<String>();
+
+ command.add(Shell.WINUTILS);
+ command.add("task");
+ command.add("createAsUser");
+ command.add("START_LOCALIZER_" + locId);
+ command.add(user);
+ command.add("nul:"); // PID file
+
+ //use same jvm as parent
+ File jvm = new File(new File(System.getProperty("java.home"), "bin"), "java.exe");
+ command.add(jvm.toString());
+
+
+ // Build a temp classpath jar. See ContainerLaunch.sanitizeEnv().
+ // Passing CLASSPATH explicitly is *way* too long for command line.
+ String classPath = System.getProperty("java.class.path");
+ Map<String, String> env = new HashMap<String, String>(System.getenv());
+ String classPathJar = FileUtil.createJarWithClassPath(classPath, appStorageDir, env);
+ localizeClasspathJar(new Path(classPathJar), user);
+ command.add("-classpath");
+ command.add(classPathJar);
+
+ String javaLibPath = System.getProperty("java.library.path");
+ if (javaLibPath != null) {
+ command.add("-Djava.library.path=" + javaLibPath);
+ }
+
+ ContainerLocalizer.buildMainArgs(command, user, appId, locId, nmAddr, localDirs);
+ commandArray = command.toArray(new String[command.size()]);
+
+ shExec = new ShellCommandExecutor(
+ commandArray, cwdApp);
+
+ shExec.execute();
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/launcher/ContainerLaunch.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/launcher/ContainerLaunch.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/launcher/ContainerLaunch.java
index cee6a40..87a36c4 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/launcher/ContainerLaunch.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/launcher/ContainerLaunch.java
@@ -766,6 +766,8 @@ public class ContainerLaunch implements Callable<Integer> {
String classPathJar = FileUtil.createJarWithClassPath(
newClassPath.toString(), pwd, mergedEnv);
+ // In a secure cluster the classpath jar must be localized to grant access
+ this.exec.localizeClasspathJar(new Path(classPathJar), container.getUser());
environment.put(Environment.CLASSPATH.name(), classPathJar);
}
}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/localizer/ContainerLocalizer.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/localizer/ContainerLocalizer.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/localizer/ContainerLocalizer.java
index f05f49c..3525170 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/localizer/ContainerLocalizer.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/localizer/ContainerLocalizer.java
@@ -312,6 +312,31 @@ public class ContainerLocalizer {
status.addAllResources(currentResources);
return status;
}
+
+ /**
+ * Adds the ContainerLocalizer arguments for a @{link ShellCommandExecutor},
+ * as expected by ContainerLocalizer.main
+ * @param command the current ShellCommandExecutor command line
+ * @param user localization user
+ * @param appId localized app id
+ * @param locId localizer id
+ * @param nmAddr nodemanager address
+ * @param localDirs list of local dirs
+ */
+ public static void buildMainArgs(List<String> command,
+ String user, String appId, String locId,
+ InetSocketAddress nmAddr, List<String> localDirs) {
+
+ command.add(ContainerLocalizer.class.getName());
+ command.add(user);
+ command.add(appId);
+ command.add(locId);
+ command.add(nmAddr.getHostName());
+ command.add(Integer.toString(nmAddr.getPort()));
+ for(String dir : localDirs) {
+ command.add(dir);
+ }
+ }
public static void main(String[] argv) throws Throwable {
Thread.setDefaultUncaughtExceptionHandler(new YarnUncaughtExceptionHandler());
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestContainerExecutor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestContainerExecutor.java
index c04ec29..fd3634b 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestContainerExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestContainerExecutor.java
@@ -27,11 +27,13 @@ import org.junit.Test;
import static org.junit.Assert.*;
public class TestContainerExecutor {
+
+ private ContainerExecutor containerExecutor = new DefaultContainerExecutor();
@Test (timeout = 5000)
public void testRunCommandNoPriority() throws Exception {
Configuration conf = new Configuration();
- String[] command = ContainerExecutor.getRunCommand("echo", "group1", conf);
+ String[] command = containerExecutor.getRunCommand("echo", "group1", "user", null, conf);
assertTrue("first command should be the run command for the platform",
command[0].equals(Shell.WINUTILS) || command[0].equals("bash"));
}
@@ -40,7 +42,7 @@ public class TestContainerExecutor {
public void testRunCommandwithPriority() throws Exception {
Configuration conf = new Configuration();
conf.setInt(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY, 2);
- String[] command = ContainerExecutor.getRunCommand("echo", "group1", conf);
+ String[] command = containerExecutor.getRunCommand("echo", "group1", "user", null, conf);
if (Shell.WINDOWS) {
// windows doesn't currently support
assertEquals("first command should be the run command for the platform",
@@ -54,7 +56,7 @@ public class TestContainerExecutor {
// test with negative number
conf.setInt(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY, -5);
- command = ContainerExecutor.getRunCommand("echo", "group1", conf);
+ command = containerExecutor.getRunCommand("echo", "group1", "user", null, conf);
if (Shell.WINDOWS) {
// windows doesn't currently support
assertEquals("first command should be the run command for the platform",
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestDefaultContainerExecutor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestDefaultContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestDefaultContainerExecutor.java
index 9c86c71..f6f0e9f 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestDefaultContainerExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestDefaultContainerExecutor.java
@@ -199,7 +199,7 @@ public class TestDefaultContainerExecutor {
Assert.assertEquals(appDirPerm, stats.getPermission());
}
- executor.createAppLogDirs(appId, logDirs);
+ executor.createAppLogDirs(appId, logDirs, user);
for (String dir : logDirs) {
FileStatus stats = lfs.getFileStatus(new Path(dir, appId));
@@ -277,7 +277,7 @@ public class TestDefaultContainerExecutor {
mockExec.createUserLocalDirs(localDirs, appSubmitter);
mockExec.createUserCacheDirs(localDirs, appSubmitter);
mockExec.createAppDirs(localDirs, appSubmitter, appId);
- mockExec.createAppLogDirs(appId, logDirs);
+ mockExec.createAppLogDirs(appId, logDirs, appSubmitter);
Path scriptPath = new Path("file:///bin/echo");
Path tokensPath = new Path("file:///dev/null");
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/SecureContainer.apt.vm
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/SecureContainer.apt.vm b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/SecureContainer.apt.vm
new file mode 100644
index 0000000..1f9688a
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/SecureContainer.apt.vm
@@ -0,0 +1,118 @@
+~~ Licensed 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. See accompanying LICENSE file.
+
+ ---
+ YARN Secure Containers
+ ---
+ ---
+ ${maven.build.timestamp}
+
+YARN Secure Containers
+
+%{toc|section=1|fromDepth=0|toDepth=3}
+
+* {Overview}
+
+ YARN containers in a secure cluster use the operating system facilities to offer
+ execution isolation for containers. Secure containers execute under the credentials
+ of the job user. The operating system enforces access restriction for the container.
+ The container must run as the use that submitted the application.
+
+ Secure Containers work only in the context of secured YARN clusters.
+
+ ** Container isolation requirements
+
+ The container executor must access the local files and directories needed by the
+ container such as jars, configuration files, log files, shared objects etc. Although
+ it is launched by the NodeManager, the container should not have access to the
+ NodeManager private files and configuration. Container running applications
+ submitted by different users should be isolated and unable to access each other
+ files and directories. Similar requirements apply to other system non-file securable
+ objects like named pipes, critical sections, LPC queues, shared memory etc.
+
+
+ ** Linux Secure Container Executor
+
+ On Linux environment the secure container executor is the <<<LinuxContainerExecutor>>>.
+ It uses an external program called the <<container-executor>>> to launch the container.
+ This program has the <<<setuid>>> access right flag set which allows it to launch
+ the container with the permissions of the YARN application user.
+
+ *** Configuration
+
+ The configured directories for <<<yarn.nodemanager.local-dirs>>> and
+ <<<yarn.nodemanager.log-dirs>>> must be owned by the configured NodeManager user
+ (<<<yarn>>>) and group (<<<hadoop>>>). The permission set on these directories must
+ be <<<drwxr-xr-x>>>.
+
+ The <<<container-executor>>> program must be owned by <<<root>>> and have the
+ permission set <<<---sr-s--->>>.
+
+ To configure the <<<NodeManager>>> to use the <<<LinuxContainerExecutor>>> set the following
+ in the <<conf/yarn-site.xml>>:
+
++---+
+<property>
+ <name>yarn.nodemanager.container-executor.class</name>
+ <value>org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value>
+</property>
+
+<property>
+ <name>yarn.nodemanager.linux-container-executor.group</name>
+ <value>hadoop</value>
+</property>
++---+
+
+ Additionally the LCE requires the <<<container-executor.cfg>>> file, which is read by the
+ <<<container-executor>>> program.
+
++---+
+yarn.nodemanager.linux-container-executor.group=#configured value of yarn.nodemanager.linux-container-executor.group
+banned.users=#comma separated list of users who can not run applications
+allowed.system.users=#comma separated list of allowed system users
+min.user.id=1000#Prevent other super-users
++---+
+
+
+ ** Windows Secure Container Executor
+
+ The Windows environment secure container executor is the <<<WindowsSecureContainerExecutor>>>.
+ It uses the Windows S4U infrastructure to launch the container as the
+ YARN application user.
+
+ *** Configuration
+
+ To configure the <<<NodeManager>>> to use the <<<WindowsSecureContainerExecutor>>>
+ set the following in the <<conf/yarn-site.xml>>:
+
++---+
+<property>
+ <name>yarn.nodemanager.container-executor.class</name>
+ <value>org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor</value>
+</property>
+
+<property>
+ <name>yarn.nodemanager.windows-secure-container-executor.group</name>
+ <value>hadoop</value>
+</property>
++---+
+
+ The NodeManager must run as a member of the local <<<Administrators>>> group or as
+ <<<LocalSystem>>>. It is not enough for the NodeManager to simply impersonate such an user.
+
+ *** Useful Links
+
+ * {{{http://msdn.microsoft.com/en-us/magazine/cc188757.aspx}Exploring S4U Kerberos Extensions in Windows Server 2003}}
+
+ * {{{https://issues.apache.org/jira/browse/YARN-1063}Winutils needs ability to create task as domain user}}
+
+ * {{{https://issues.apache.org/jira/browse/YARN-1972}Implement secure Windows Container Executor}}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba7f31c2/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/index.apt.vm
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/index.apt.vm b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/index.apt.vm
index 9f07b19..adb2a0a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/index.apt.vm
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/index.apt.vm
@@ -52,6 +52,8 @@ MapReduce NextGen aka YARN aka MRv2
* {{{./WebApplicationProxy.html}Web Application Proxy}}
* {{{./TimelineServer.html}YARN Timeline Server}}
+
+ * {{{./SecureContainer.html}YARN Secure Containers}}
* {{{../../hadoop-project-dist/hadoop-common/CLIMiniCluster.html}CLI MiniCluster}}