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

Support USER in Dockerfile - when container starts up non-root #19

Closed
dreamcat4 opened this issue Mar 13, 2015 · 22 comments
Closed

Support USER in Dockerfile - when container starts up non-root #19

dreamcat4 opened this issue Mar 13, 2015 · 22 comments

Comments

@dreamcat4
Copy link

So to recap. The Docker USER directive in Dockerfile. It is a part of the official Docker feature set. The directive provides a simple way to allow people to run their apps with better security by not being the root user. There are other ways people can write containers to achieve the same thing. By starting as root then dropping privileges to the target user before running their program. Or have the program do that itself when it starts up.

However it would provide best and most complete support for Docker community - if we can support USER directive. Not sure how much messing about is required to do that.

The problem presented isn't just about modifying our scripts to avoid doing the [env]setuidgid on processes. But rather it may be difficult to some of these helper processes (logging and such) to be permitted to write to certain directories, when beforehand the overlay tarball does not know which the process UID will be.

Another possible solution might be to assign a single fixed PID number (we choose in the 32000 range again). And tell users they must configure their docker USER to be only that particular fixed uid:gid. Which means we can know it beforehand, and (again) hard-code directories to be owned by that single pre-determined UID number.

@pikeas
Copy link

pikeas commented Mar 25, 2015

Or document the directories which require write access. Then child Dockerfiles can just chown or chmod +w those folders.

@dreamcat4
Copy link
Author

@pikeas That is a good idea too :)

Just to re-clarify what you said -

  • So users who put USER $user in their Dockerfile must first RUN chown -R $user $user after unpacking the overlay tarball. But actually before dropping privileges with the USER directive. This may be fairly simple. E.g.
FROM ubuntu-debootstrap:14.04
ENV _clean="rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*"

# Install s6-overlay
ADD https://github.com/just-containers/s6-overlay-builder/releases/download/v1.8.3/s6-overlay-linux-amd64.tar.gz /tmp/
RUN tar zxf /tmp/s6-overlay-linux-amd64.tar.gz -C / && $_clean

# Create user (if not exist already)
RUN useradd mike

# Chown folders
RUN chown -R mike:mike /whichever-s6-folders

# Drop privilege
USER mike

# Run s6 overlay as user 'mike', and PID=1
ENTRTYPOINT ['/init']
  • We would also still need changes in the s6-overlay scripts. To not try to change users chown the folder and so on etc. unless the process is root. However that isn't too difficult to do. There are only a couple of places where it happens.

@pikeas
Copy link

pikeas commented Mar 25, 2015

Pretty much exactly what you've described. So long as the overlay permissions are initially correct, there's no need to double-check them on container start, so that can be removed.

@glerchundi
Copy link
Member

Hi @dreamcat4, @pikeas,

Can someone give me some use cases in order to identify why should I implement USER support in the overlay? I've been using it these months and I feel comfortable having root privileges in the boot process, and dropping them when I need to execute my custom services.

@dreamcat4
Copy link
Author

Just for general case, for best compatibility when auser wants to use the USER directive. If we do not support this - then that is OK also. Then would be best to document that s6-overlay does not work with USER directive in the README / FAQ / similar.

@glerchundi
Copy link
Member

Of course, this requirement should be part of the documentation. I'll try to complete the readme this month, at least the most important parts of the overlay.

@glerchundi
Copy link
Member

Closing this due to: #79.

@pikeas
Copy link

pikeas commented Aug 25, 2015

This issue is about implementing USER support, and/or adding a workaround (list of directories/files which need to be writeable). Linked PR only says USER is unsupported.

Re-open until docs are updated or USER support is added?

@glerchundi
Copy link
Member

I'm not going to re-open this mainly because (sorted by importance):

@dreamcat4
Copy link
Author

Here is the workaround that I am using ATM. If you do apt-get install sudo in your Dockerfile, then can do this to drop privs:

sudo -E su "$user" << EOF
  # start your daemon here
EOF

@glerchundi
Copy link
Member

Why not this instead of depending in another utility?

s6-setuidgid user
# start your daemon here

@dreamcat4
Copy link
Author

Sure if it works from a regular bash / shell script. Sorry I am not aware of these things.

@glerchundi
Copy link
Member

@dreamcat4
Copy link
Author

Ah I see. The sudo method lets you run multiple commands from the regular shell script (not execline).

@glerchundi
Copy link
Member

Wrapped by sh

  • Entirely execline based:
$> forstdin i import -u i s6-setuidgid daemon sh -c "\${i}" <<EOF
 whoami
 ls
 whoami
EOF
  • A little bit more readable but requires xargs which is in all distros:
$> xargs -0 s6-setuidgid daemon sh -c <<EOF
 whoami
 ls
 whoami
EOF

Without any dependency, this would execute one s6-setuidgid per line:

  • execline:
$> forstdin -C i import -u i s6-setuidgid daemon \${i} <<EOF
  whoami
  ls
  whoami
EOF
  • xargs:
$> xargs -n 1 s6-setuidgid daemon <<EOF
  whoami
  ls
  whoami
EOF

Hope it helps ;)

@CumpsD
Copy link

CumpsD commented Mar 7, 2016

How do you guys deal with redirecting output when dropping priviliges with s6?

For example, I now run with exec s6-setuidgid www-data nginx but that results in:

nginx: [emerg] open() "/proc/self/fd/2" failed (13: Permission denied)

Because I have this in a config to get docker logs to work:
error_log /proc/self/fd/2 warn;

I tracked it down a bit to docker-library/nginx#4 which points to moby/moby#6880 and apparently says it is fixed in Docker 1.9 or higher when using USER. Since we can't use USER I'm guessing Docker doesnt do anything nice with the stdout things, causing the above error.

I'm ok with not being able to do USER, but I was wondering how you deal with logging to stdout/err with s6 when dropping privileges?

@CumpsD
Copy link

CumpsD commented Mar 7, 2016

It seems in this PR they fixed it by really looking at USER to update the permissions: opencontainers/runc#280

@bryanlatten
Copy link

@CumpsD unfortunately, still not fixed when not using the USER directive: moby/moby#31243

@felipecrs
Copy link

Why this is closed? If not yet implemented, it's not supposed to be closed.

To implement such a thing, though, we need to use shc (with -S) to compile a binary which will have suid bit set, which means it will run as root despite the user who called.

@felipecrs
Copy link

felipecrs commented Aug 26, 2020

I made one example here: https://github.com/felipecrs/fixdockergid
Currently, there is no how to use fixuid alongside s6-overlay. We would need such a feature.

@jprjr
Copy link
Member

jprjr commented Sep 12, 2020

As of version 2.1.0.0 you can use the USER directive but there's a good number of features that won't work.

  • logutil-newfifo by default creates fifos with root as the owner.
    • I think a user can work around this by using -o (their user)
  • logutil-service tries to switch to the nobody user, this will fail.
  • fix-attrs.d files will likely not work.
  • the socklog-overlay add-on won't work.
  • the catch-all logger won't work.

Right now, the solution I have is to install a new, small binary with the SETUID bit set. It runs very early in the init script, and all it does is create the /var/run and /var/run/s6 folders, and chowns /var/run/s6 to the current USER. That's enough to get things running.

For other parts, it comes down to 1) how important is it to work with the USER directive, and 2) how to go about making it work with the USER directive. Some things (like logutil-service) may not be a big deal, since it's pretty easy to replace in your own images, so we could probably just say "yeah, logutil-service won't work in that mode."

Having to create a lot of these small utilities may not be super maintainable, but I don't want to take any approach that runs large chunks of s6-overlay as root via SETUID either. And I definitely do not want any SETUID binaries that interpret things like scripts, or allow you to launch other programs as root, etc - it would make things easier but it also seems incredibly dangerous. Using SETUID should be very, very targeted and specific.

@jprjr
Copy link
Member

jprjr commented Jan 22, 2021

Closing since as of version 2.1.0.0 you can use USER.

@jprjr jprjr closed this as completed Jan 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants