|
@@ -30,6 +30,7 @@ import org.apache.hadoop.fs.Path;
|
|
import org.apache.hadoop.registry.client.binding.RegistryPathUtils;
|
|
import org.apache.hadoop.registry.client.binding.RegistryPathUtils;
|
|
import org.apache.hadoop.security.UserGroupInformation;
|
|
import org.apache.hadoop.security.UserGroupInformation;
|
|
import org.apache.hadoop.security.authorize.AccessControlList;
|
|
import org.apache.hadoop.security.authorize.AccessControlList;
|
|
|
|
+import org.apache.hadoop.util.Shell;
|
|
import org.apache.hadoop.util.StringUtils;
|
|
import org.apache.hadoop.util.StringUtils;
|
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
|
import org.apache.hadoop.yarn.server.nodemanager.ContainerExecutor;
|
|
import org.apache.hadoop.yarn.server.nodemanager.ContainerExecutor;
|
|
@@ -164,6 +165,9 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
public static final String ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER =
|
|
public static final String ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER =
|
|
"YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER";
|
|
"YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER";
|
|
@InterfaceAudience.Private
|
|
@InterfaceAudience.Private
|
|
|
|
+ public static final String ENV_DOCKER_CONTAINER_RUN_ENABLE_USER_REMAPPING =
|
|
|
|
+ "YARN_CONTAINER_RUNTIME_DOCKER_RUN_ENABLE_USER_REMAPPING";
|
|
|
|
+ @InterfaceAudience.Private
|
|
public static final String ENV_DOCKER_CONTAINER_LOCAL_RESOURCE_MOUNTS =
|
|
public static final String ENV_DOCKER_CONTAINER_LOCAL_RESOURCE_MOUNTS =
|
|
"YARN_CONTAINER_RUNTIME_DOCKER_LOCAL_RESOURCE_MOUNTS";
|
|
"YARN_CONTAINER_RUNTIME_DOCKER_LOCAL_RESOURCE_MOUNTS";
|
|
|
|
|
|
@@ -175,6 +179,9 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
private String cgroupsRootDirectory;
|
|
private String cgroupsRootDirectory;
|
|
private CGroupsHandler cGroupsHandler;
|
|
private CGroupsHandler cGroupsHandler;
|
|
private AccessControlList privilegedContainersAcl;
|
|
private AccessControlList privilegedContainersAcl;
|
|
|
|
+ private boolean enableUserReMapping;
|
|
|
|
+ private int userRemappingUidThreshold;
|
|
|
|
+ private int userRemappingGidThreshold;
|
|
|
|
|
|
/**
|
|
/**
|
|
* Return whether the given environment variables indicate that the operation
|
|
* Return whether the given environment variables indicate that the operation
|
|
@@ -260,6 +267,18 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
privilegedContainersAcl = new AccessControlList(conf.getTrimmed(
|
|
privilegedContainersAcl = new AccessControlList(conf.getTrimmed(
|
|
YarnConfiguration.NM_DOCKER_PRIVILEGED_CONTAINERS_ACL,
|
|
YarnConfiguration.NM_DOCKER_PRIVILEGED_CONTAINERS_ACL,
|
|
YarnConfiguration.DEFAULT_NM_DOCKER_PRIVILEGED_CONTAINERS_ACL));
|
|
YarnConfiguration.DEFAULT_NM_DOCKER_PRIVILEGED_CONTAINERS_ACL));
|
|
|
|
+
|
|
|
|
+ enableUserReMapping = conf.getBoolean(
|
|
|
|
+ YarnConfiguration.NM_DOCKER_ENABLE_USER_REMAPPING,
|
|
|
|
+ YarnConfiguration.DEFAULT_NM_DOCKER_ENABLE_USER_REMAPPING);
|
|
|
|
+
|
|
|
|
+ userRemappingUidThreshold = conf.getInt(
|
|
|
|
+ YarnConfiguration.NM_DOCKER_USER_REMAPPING_UID_THRESHOLD,
|
|
|
|
+ YarnConfiguration.DEFAULT_NM_DOCKER_USER_REMAPPING_UID_THRESHOLD);
|
|
|
|
+
|
|
|
|
+ userRemappingGidThreshold = conf.getInt(
|
|
|
|
+ YarnConfiguration.NM_DOCKER_USER_REMAPPING_GID_THRESHOLD,
|
|
|
|
+ YarnConfiguration.DEFAULT_NM_DOCKER_USER_REMAPPING_GID_THRESHOLD);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -436,6 +455,34 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
"resource: " + mount);
|
|
"resource: " + mount);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private String getUserIdInfo(String userName)
|
|
|
|
+ throws ContainerExecutionException {
|
|
|
|
+ String id = "";
|
|
|
|
+ Shell.ShellCommandExecutor shexec = new Shell.ShellCommandExecutor(
|
|
|
|
+ new String[]{"id", "-u", userName});
|
|
|
|
+ try {
|
|
|
|
+ shexec.execute();
|
|
|
|
+ id = shexec.getOutput().replaceAll("[^0-9]", "");
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ throw new ContainerExecutionException(e);
|
|
|
|
+ }
|
|
|
|
+ return id;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String[] getGroupIdInfo(String userName)
|
|
|
|
+ throws ContainerExecutionException {
|
|
|
|
+ String[] id = null;
|
|
|
|
+ Shell.ShellCommandExecutor shexec = new Shell.ShellCommandExecutor(
|
|
|
|
+ new String[]{"id", "-G", userName});
|
|
|
|
+ try {
|
|
|
|
+ shexec.execute();
|
|
|
|
+ id = shexec.getOutput().replace("\n", "").split(" ");
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ throw new ContainerExecutionException(e);
|
|
|
|
+ }
|
|
|
|
+ return id;
|
|
|
|
+ }
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
public void launchContainer(ContainerRuntimeContext ctx)
|
|
public void launchContainer(ContainerRuntimeContext ctx)
|
|
throws ContainerExecutionException {
|
|
throws ContainerExecutionException {
|
|
@@ -458,7 +505,30 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
|
|
|
|
String containerIdStr = container.getContainerId().toString();
|
|
String containerIdStr = container.getContainerId().toString();
|
|
String runAsUser = ctx.getExecutionAttribute(RUN_AS_USER);
|
|
String runAsUser = ctx.getExecutionAttribute(RUN_AS_USER);
|
|
|
|
+ String dockerRunAsUser = runAsUser;
|
|
Path containerWorkDir = ctx.getExecutionAttribute(CONTAINER_WORK_DIR);
|
|
Path containerWorkDir = ctx.getExecutionAttribute(CONTAINER_WORK_DIR);
|
|
|
|
+ String[] groups = null;
|
|
|
|
+
|
|
|
|
+ if (enableUserReMapping) {
|
|
|
|
+ String uid = getUserIdInfo(runAsUser);
|
|
|
|
+ groups = getGroupIdInfo(runAsUser);
|
|
|
|
+ String gid = groups[0];
|
|
|
|
+ if(Integer.parseInt(uid) < userRemappingUidThreshold) {
|
|
|
|
+ String message = "uid: " + uid + " below threshold: "
|
|
|
|
+ + userRemappingUidThreshold;
|
|
|
|
+ throw new ContainerExecutionException(message);
|
|
|
|
+ }
|
|
|
|
+ for(int i = 0; i < groups.length; i++) {
|
|
|
|
+ String group = groups[i];
|
|
|
|
+ if (Integer.parseInt(group) < userRemappingGidThreshold) {
|
|
|
|
+ String message = "gid: " + group
|
|
|
|
+ + " below threshold: " + userRemappingGidThreshold;
|
|
|
|
+ throw new ContainerExecutionException(message);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ dockerRunAsUser = uid + ":" + gid;
|
|
|
|
+ }
|
|
|
|
+
|
|
//List<String> -> stored as List -> fetched/converted to List<String>
|
|
//List<String> -> stored as List -> fetched/converted to List<String>
|
|
//we can't do better here thanks to type-erasure
|
|
//we can't do better here thanks to type-erasure
|
|
@SuppressWarnings("unchecked")
|
|
@SuppressWarnings("unchecked")
|
|
@@ -485,7 +555,7 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
@SuppressWarnings("unchecked")
|
|
DockerRunCommand runCommand = new DockerRunCommand(containerIdStr,
|
|
DockerRunCommand runCommand = new DockerRunCommand(containerIdStr,
|
|
- runAsUser, imageName)
|
|
|
|
|
|
+ dockerRunAsUser, imageName)
|
|
.detachOnRun()
|
|
.detachOnRun()
|
|
.setContainerWorkDir(containerWorkDir.toString())
|
|
.setContainerWorkDir(containerWorkDir.toString())
|
|
.setNetworkType(network);
|
|
.setNetworkType(network);
|
|
@@ -549,6 +619,10 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
runCommand.setOverrideCommandWithArgs(overrideCommands);
|
|
runCommand.setOverrideCommandWithArgs(overrideCommands);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if(enableUserReMapping) {
|
|
|
|
+ runCommand.groupAdd(groups);
|
|
|
|
+ }
|
|
|
|
+
|
|
String commandFile = dockerClient.writeCommandToTempFile(runCommand,
|
|
String commandFile = dockerClient.writeCommandToTempFile(runCommand,
|
|
containerIdStr);
|
|
containerIdStr);
|
|
PrivilegedOperation launchOp = new PrivilegedOperation(
|
|
PrivilegedOperation launchOp = new PrivilegedOperation(
|