-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CHE-3359 - Starting a workspace as an user #3376
Conversation
Can one of the admins verify this patch? |
private void prepareContainer(String containerId, LineConsumer machineLogger) throws MachineException { | ||
String prepareCmd = "CHE_USER=`id -un`;" | ||
+ "sudo chown -R ${CHE_USER}:docker /home/user;" | ||
+ "sudo ln -s /home/user `eval echo \"~${CHE_USER}\"`"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need to create this symbolic link?
@@ -340,7 +347,27 @@ public Instance startService(String namespace, | |||
} | |||
} | |||
|
|||
@Override | |||
private void prepareContainer(String containerId, LineConsumer machineLogger) throws MachineException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name prepareContainer
doesn't say much about this method. What about changeWorkingDirOwner
?
throw new MachineException(format("Error occurs while executing command %s in docker container %s: %s", | ||
Arrays.toString(exec.getCommand()), containerId, e.getMessage()), e); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that last curly bracket is not correctly aligned
@snjeza your PR looks ok to me. How have you tested your PR? Can you please tell me the command line you have used to start Che and the simple steps of your tests? @garagatyi and @benoitf I think you should have a look too |
Che supposes a workspace runs as the "user" user that has a specific home directory. The command sets the same environment for any user starting the workspace.
You start che as described in #3265
create a workspace and call
If you start a workspace as usually, you will get the user "user(1000)". When using the above command, you will get the "test" user and its ID. The test user must have the sudo NOPASSWD permission (must be a member of the sudo group). |
@snjeza Can you elaborate on what this PR does and what for. It is not clear in most cases what PRs do, so we are welcoming in PRs body detailed explanation of all information needed for reviewers. |
@@ -41,7 +42,7 @@ | |||
// from docs for 1.15 API https://docs.docker.com/reference/api/docker_remote_api_v1.15/#create-a-container | |||
// An object mapping ports to an empty object in the form of: "ExposedPorts": { "<port>/<tcp|udp>: {}" } | |||
private Map<String, Map<String, String>> exposedPorts = new HashMap<>(); | |||
private String user = ""; | |||
private String user = System.getenv(CHE_USER_ID) == null ? "" : System.getenv(CHE_USER_ID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This object is simple POJO. It should not include any logic for fields evaluation based on environment settings.
@@ -294,6 +297,10 @@ public Instance startService(String namespace, | |||
|
|||
docker.startContainer(StartContainerParams.create(container)); | |||
|
|||
if (System.getenv("CHE_USER_ID") != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PLease use injection to check env variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -294,6 +297,10 @@ public Instance startService(String namespace, | |||
|
|||
docker.startContainer(StartContainerParams.create(container)); | |||
|
|||
if (System.getenv("CHE_USER_ID") != null) { | |||
changeWorkingDirOwner(container, machineLogger); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not clear why we need that. PLease comment code or add javadocs to this method on why we do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When che starts a workspace, it expects that there is the "user" user that has the /home/user directory as the home directory with a specific content.
You can check that by the following:
docker run -it codenvy/ubuntu_jdk8 id
docker run -it codenvy/ubuntu_jdk8 ls -la /home/user
The changeWorkingDirOwner method sets the same environment for a user defined with CHE_USER which enables us to use the existing che images.
CHE-3264 implements the CHE_USER environment variable. However, only the che server is started as a user defined with CHE_USER. By executing the following command, you can see which user started the che server or a workspace:
|
f0ee59a
to
aba9a87
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI @snjeza master branch has been rewritten on docs import to discard images files so you'll have to rebase your branch to be in sync with latest master. I can help around this task if you need help
I don't understand why should we change user inside of workspace containers and change ownership of files. It is quiet risky operation to me that can raise a lot of issues with some specific software in containers. |
The basic expectation is that a workspace is the ownership of the user, not of Che. And so if the end user or admin thinks of a workspace runtime as "their" property, then they want to have root-like behaviors. Their project may require a certain user identity or other override behaviors. So this would give an admin the ability to configure a workspace as a particular user. |
@@ -89,7 +94,26 @@ public void provision(Environment envConfig, CheServicesEnvironmentImpl internal | |||
.add(SystemInfo.isWindows() ? pathEscaper.escapePath(projectFolderVolume) | |||
: projectFolderVolume); | |||
|
|||
if (System.getenv(CHE_USER_ID) != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use dependency injection instead of getenv method. Take a look at my comment to learn more about that.
@@ -541,6 +570,10 @@ private String createContainer(String workspaceId, | |||
.getId(); | |||
} | |||
|
|||
protected String getUser() { | |||
return System.getenv("CHE_USER_ID") == null ? "" : System.getenv("CHE_USER_ID"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use dependency injection instead of getenv method. If named property starts from env. it is retrieved from environment variables by name that follows prefix env.. For example @Named("env.MY_VAR") String str
injects value from env variable MY_VAR. Also it is better to do that in constructor.
@@ -341,7 +348,28 @@ public Instance startService(String namespace, | |||
} | |||
} | |||
|
|||
@Override | |||
// sets the home directory for a user defined with CHE_USER | |||
private void changeWorkingDirOwner(String containerId, LineConsumer machineLogger) throws MachineException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please cover changed code with unit tests. See MachineProviderImplTest
@@ -89,7 +94,26 @@ public void provision(Environment envConfig, CheServicesEnvironmentImpl internal | |||
.add(SystemInfo.isWindows() ? pathEscaper.escapePath(projectFolderVolume) | |||
: projectFolderVolume); | |||
|
|||
if (System.getenv(CHE_USER_ID) != null) { | |||
addVolume(internalEnv, devMachineName, ETC_PASSWD_VOLUME); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add unit tests to cover changed code. Unfortunately there are no tests yet for this class. But you can cover only your code if you will.
@@ -528,6 +556,7 @@ private String createContainer(String workspaceId, | |||
.withEntrypoint(toArrayIfNotNull(service.getEntrypoint())) | |||
.withLabels(service.getLabels()) | |||
.withNetworkingConfig(networkingConfig) | |||
.withUser(getUser()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will container start if there is no such user in container?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably with mounting of /etc/passwd and /etc/group user kinda already exists in container. But there is possibility of permissions problems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@garagatyi user will be the same that is running in che-server container. The same env variable CHE_USER_ID is used by both workspace and che-server.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way I think the purpose of this PR is to solve permissions problems. Let's say that I'm logged in my Linux box using user mario
. When starting a Che workspace I would expect it to run as user mario
too. With permission to open files that I can read and only those. This user does not exist in the original recipe docker image but mounting the /etc/passwd will do the trick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I got it. Thanks for additional explanation.
private void changeWorkingDirOwner(String containerId, LineConsumer machineLogger) throws MachineException { | ||
String prepareCmd = "CHE_USER=`id -un`;" | ||
+ "sudo chown -R ${CHE_USER}:docker /home/user;" | ||
+ "sudo ln -s /home/user `eval echo \"~${CHE_USER}\"`"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mario asked that and I haven't found answer. Why do you need to create this symbolic link?
path = format("%s:%s:ro", volume, volume); | ||
} | ||
internalEnv.getServices() | ||
.get(devMachineName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why mapping of these files are needed for dev machines only and not all the machines?
@@ -294,6 +297,10 @@ public Instance startService(String namespace, | |||
|
|||
docker.startContainer(StartContainerParams.create(container)); | |||
|
|||
if (!Strings.isNullOrEmpty(getUser())) { | |||
changeWorkingDirOwner(container, machineLogger); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it OK that previous user in container is already running main process of container?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I misunderstood it a bit. In that case main process will run under new user but files on container's FS will be under old user. It can raise problem with that container. WDYT?
// sets the home directory for a user defined with CHE_USER | ||
private void changeWorkingDirOwner(String containerId, LineConsumer machineLogger) throws MachineException { | ||
String prepareCmd = "CHE_USER=`id -un`;" | ||
+ "sudo chown -R ${CHE_USER}:docker /home/user;" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why user home dir here and in link uses hardcoded path /home/user? User in container can have another name. And if it is root it can be in /root instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And user may not have home directory at all. And main process of container may have some permissions problems because of some hardcoded permissions on FS in container but not in home folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we get home directory ?
why are we not using $HOME or getent passwd with user
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benoitf do you agree that $HOME does not correspond to /home/user here right? By the way /home/user/
Alex - I generally agree with that basic philosophy. I actually don't know how we haven't been getting user complaints on this limitation in higher volume. |
I have updated the patch. |
@snjeza I'm sorry but I'm getting lost here 😄 Could you remember me what you have you changed since the last commit? Looking at current PR I can't remember the difference of this last update with the previous one. And there is a question about the commands executed in the container ( I think we are really close to merge this PR but we need these details from you. |
return; | ||
} | ||
try { | ||
if (exec != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is not covered by tests, can you cover it?
// sets the home directory for a user defined with CHE_USER | ||
private void changeWorkingDirOwner(String containerId, LineConsumer machineLogger) throws MachineException { | ||
String prepareCmd = "CHE_USER=`id -un`;" | ||
+ "sudo chown -R ${CHE_USER}:docker /home/user;" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if user is root in a container? His home folder will be /root instead of /home/user. Or even if user has different username - not the "user".
Regarding @garagatyi requests, I have added the following:
I have already answered it.
The home directory contains some required files (maven, tomcat, ...). Che won't start a workspace if those files/directories aren't present.
The command won't do anything. We don't know what to do in this case because we don't know what user is a default user. Do you know an image I could test?
I have tried to do it, but the che mockup docker container returns null when calling "docker.createExec". I don't know how to test this method. How to fix the issue with @nAmed("env.MYVAR") when MYVAR isn't set? Che throws an exception in this case. |
I suppose that if current user is root and user "user" exists in s container this command will do unneeded chown.
Here is an example how to use mocks to stub container creation. You can do pretty the same for exec. The difference is that you can do it in you specific test instead of setup method because this stubbing is not needed by other tests.
Yes, we don't have such behavior for now. What can I suggest instead is to create property. Then it will be possible to inject it, to have default value as null and to override it with environment variable. |
| The home directory contains some required files (maven, tomcat, ...). Che won't start a workspace if those files/directories aren't present. This means that the workspaces Docker images have been built assuming that they will be run by user |
@l0rd Sorry I don't understand what do you mean. If you want to run containers by user "myuser" there is no possibility to fix root issue that it was not considered by author of docker image. |
@garagatyi Let's take Java default stack. Tomcat and maven are installed in RUN mkdir /home/user/tomcat8 /home/user/apache-maven-$MAVEN_VERSION This should be changed. Along with everything is related to a specific |
I don't see the reason why stack author have to predict that someone would want to change user in container he designed. Also users can create workspaces from custom recipes instead of stacks. In that case we can't rely on what user exists in container and how software is configured in that container. |
hi @snjeza, could you rebase/fix conflicts with master ? |
@sunix I have rebased the patch. |
Thanks @snjeza will review and test this week |
0057419
to
f698203
Compare
@sunix
You have to use Linux to test this feature. |
@snjeza - you should not have to use |
@TylerJewell che starts as the root user
|
oh my god - there was a refactoring of the CLI and the |
Signed-off-by: Snjezana Peco <[email protected]>
Signed-off-by: Snjezana Peco <[email protected]>
Can one of the admins verify this patch? |
1 similar comment
Can one of the admins verify this patch? |
@garagatyi I think that this PR is useful and we can have someone working on it to rebase it. But it would be better to rebase it on top of the SPI branch, not master. What do you think? |
@l0rd On which infra do you want to support it? |
@garagatyi in OpenShift this is automatically handled by the infra (by default user id is choosen arbitrarly) so I guess that Docker infra is missing that at the moment. |
I'm not sure what for it is needed in case of Docker infrastructure. And the solution is tricky which may lead to unexpected behavior of software in containers |
Can one of the admins verify this patch? |
closing. There is no interest in this pr. |
What does this PR do?
Fixes #3359
What issues does this PR fix or reference?
#3359
Signed-off-by: Snjezana Peco [email protected]