Skip to content
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

Pass user ID and group ID to docker native image build in Linux #1810

Merged
merged 2 commits into from
Apr 8, 2019

Conversation

johnaohara
Copy link
Member

…efault docker container will run as root

@johnaohara johnaohara added the kind/bug Something isn't working label Apr 2, 2019
@johnaohara johnaohara added this to the 0.13.0 milestone Apr 2, 2019
@Sanne
Copy link
Member

Sanne commented Apr 2, 2019

it works locally, but I'm not sure about us using com.sun.security.auth.module.UnixSystem(). David just cleaned up some com.sun.security usage in another module.

@dmlloyd ?

@Sanne Sanne requested a review from dmlloyd April 2, 2019 12:42
@johnaohara
Copy link
Member Author

johnaohara commented Apr 2, 2019

@Sanne It doesn't work well with JDK11 (well anything after JDK9) due to modules, am looking for a different solution. I need to determine the numerical user ID, passing in the current user name does not work, due to this docker issue: https://success.docker.com/article/KB000447

@johnaohara
Copy link
Member Author

johnaohara commented Apr 2, 2019

And I don't think command substitution works in process builder either e.g.

Collections.addAll(nativeImage, "--user", "$(id -u):$(id -g)");

will not work

@dmlloyd
Copy link
Member

dmlloyd commented Apr 2, 2019

How about id -ur/id -gr?

@johnaohara
Copy link
Member Author

The only other way I have thought about so far is to have a DOCKER_USER environment variable in the docker file for the build and modify the dockerfile to pass the DOCKER_USER environment variable as one of the build parameters
(https://docs.docker.com/engine/reference/builder/#user)

@dmlloyd
Copy link
Member

dmlloyd commented Apr 2, 2019

Alternatively we could develop a "stubs" module for the JDK security things. This would allow the com.sun.security classes to be used.

@dmlloyd
Copy link
Member

dmlloyd commented Apr 2, 2019

You could try using JAAS to create a login context that authenticates using the UNIX login module. That would yield a principal with the real UID/GID. I'm not 100% sure it's possible to do that without actually referencing a com.sun class directly though.

@johnaohara
Copy link
Member Author

johnaohara commented Apr 2, 2019

How about id -ur/id -gr?

@dmlloyd when I tried passing those command into ProcessBuilder, they were not resolved, and docker tried to execute with the literals "$(id -ur):$(id -gr)"

@dmlloyd
Copy link
Member

dmlloyd commented Apr 2, 2019

How about id -ur/id -gr?
@dmlloyd when I tried passing those command into ProcessBuilder, they were not resolved, and docker tried to execute with the literals "$(id -ur):$(id -gr)"

No I meant create new ProcessBuilders to get each value.

At any rate - you could simply call com.sun.security.auth.module.UnixSystem#getUid reflectively. Ugly but OK :)

@johnaohara
Copy link
Member Author

No I meant create new ProcessBuilders to get each value.

@dmlloyd ah, that would work

you could simply call com.sun.security.auth.module.UnixSystem#getUid reflectively. Ugly but OK :)

ok, I'll take a look at those suggestions

@johnaohara
Copy link
Member Author

@dmlloyd please could you review? thanks

Copy link
Member

@dmlloyd dmlloyd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't notice this at first but @gsmet pointed out that the process streams are never closed. These should use try-with-resources.

@johnaohara
Copy link
Member Author

johnaohara commented Apr 4, 2019

@dmlloyd rather than tying th CI up again. I have read through your comments, I think this addresses all the issues you raised

        try {
            StringBuilder responseBuilder = new StringBuilder();
            String line;

            ProcessBuilder idPB = new ProcessBuilder().command("id", option);
            idPB.redirectError(new File("/dev/null"));
            idPB.redirectOutput(new File("/dev/null"));

            process = idPB.start();
            try(InputStream inputStream = process.getInputStream()) {
                try( BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))){
                    while ((line = reader.readLine()) != null) {
                        responseBuilder.append(line);
                    }
                    return responseBuilder.toString();
                }
            }
        } catch (IOException e) { //from process.start()
            //swallow and return null id
            return null;
        }

@dmlloyd
Copy link
Member

dmlloyd commented Apr 4, 2019

Yeah I think that should do the job, except it's missing a process.waitFor() which should be done even in the exceptional case. You might want to add a catch to the try-with-resources:

        try {
            StringBuilder responseBuilder = new StringBuilder();
            String line;

            ProcessBuilder idPB = new ProcessBuilder().command("id", option);
            idPB.redirectError(new File("/dev/null"));
            idPB.redirectOutput(new File("/dev/null"));

            process = idPB.start();
            try(InputStream inputStream = process.getInputStream()) {
                try( BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))){
                    while ((line = reader.readLine()) != null) {
                        responseBuilder.append(line);
                    }
                    return responseBuilder.toString();
                }
            } catch (Throwable t) {
                safeWaitFor(process);
                throw t;
            }
            safeWaitFor(process);
        } catch (IOException e) { //from process.start()
            //swallow and return null id
            return null;
        }

where safeWaitFor is simply:

static void safeWaitFor(Process process) {
    boolean intr = false;
    try {
        for (;;) try {
            process.waitFor();
            return;
        } catch (InterruptedException ex) {
            intr = true;
        }
    } finally {
        if (intr) Thread.currentThread.interrupt();
    }
}

@gsmet gsmet removed this from the 0.13.0 milestone Apr 5, 2019
@johnaohara johnaohara dismissed Sanne’s stale review April 8, 2019 19:56

Concerns were addressed in refactor

@johnaohara johnaohara merged commit 7ce692a into quarkusio:master Apr 8, 2019
@johnaohara johnaohara added this to the 0.14.0 milestone Apr 8, 2019
@johnaohara johnaohara deleted the issue1636 branch April 8, 2019 19:57
@gsmet gsmet changed the title Pass user ID and group ID to docker native image build in linux, by d… Pass user ID and group ID to docker native image build in Linux Apr 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants