512

I have a docker container with some processes (uwsgi and celery) running inside. I want to create a celery user and a uwsgi user for these processes as well as a worker group that they will both belong to, in order to assign permissions.

I tried adding RUN adduser uwsgi and RUN adduser celery to my Dockerfile, but this is causing problems, since these commands prompt for input (I've posted the responses from the build below).

What is the best way to add users to a Docker container so as to set permissions for workers running in the container?

My Docker image is built from the official Ubuntu14.04 base.

Here is the output from the Dockerfile when the adduser commands are run:

Adding user `uwsgi' ...
Adding new group `uwsgi' (1000) ... 
Adding new user `uwsgi' (1000) with group `uwsgi' ... 
Creating home directory `/home/uwsgi' ...
Copying files from `/etc/skel' ... 
[91mEnter new UNIX password: Retype new UNIX password: [0m 
[91mpasswd: Authentication token manipulation error
passwd: password unchanged
[0m 
[91mUse of uninitialized value $answer in chop at /usr/sbin/adduser line 563.
[0m 
[91mUse of uninitialized value $answer in pattern match (m//) at /usr/sbin/adduser line 564.
[0m 
Try again? [y/N] 
Changing the user information for uwsgi
Enter the new value, or press ENTER for the default
    Full Name []: 
Room Number []:     Work Phone []:  Home Phone []:  Other []: 
[91mUse of uninitialized value $answer in chop at /usr/sbin/adduser line 589.
[0m 
[91mUse of uninitialized value $answer in pattern match (m//) at /usr/sbin/adduser line 590.
[0m 
Is the information correct? [Y/n] 
---> 258f2f2f13df 
Removing intermediate container 59948863162a 
Step 5 : RUN adduser celery 
---> Running in be06f1e20f64 
Adding user `celery' ...
Adding new group `celery' (1001) ... 
Adding new user `celery' (1001) with group `celery' ... 
Creating home directory `/home/celery' ...
Copying files from `/etc/skel' ... 
[91mEnter new UNIX password: Retype new UNIX password: [0m 
[91mpasswd: Authentication token manipulation error
passwd: password unchanged
[0m 
[91mUse of uninitialized value $answer in chop at /usr/sbin/adduser line 563.
[0m 
[91mUse of uninitialized value $answer in pattern match (m//) at /usr/sbin/adduser line 564.
[0m 
Try again? [y/N] 
Changing the user information for celery
Enter the new value, or press ENTER for the default
    Full Name []:   Room Number []:     Work Phone []: 
Home Phone []:  Other []: 
[91mUse of uninitialized value $answer in chop at /usr/sbin/adduser line 589.
[0m 
[91mUse of uninitialized value $answer in pattern match (m//) at /usr/sbin/adduser line 590.
[0m 
Is the information correct? [Y/n] 
Manik
  • 573
  • 1
  • 9
  • 28
rfj001
  • 7,948
  • 8
  • 30
  • 48

10 Answers10

809

The trick is to use useradd instead of its interactive wrapper adduser. I usually create users with:

RUN useradd -ms /bin/bash newuser

which creates a home directory for the user and ensures that bash is the default shell.

You can then add:

USER newuser
WORKDIR /home/newuser

to your dockerfile. Every command afterwards as well as interactive sessions will be executed as user newuser:

docker run -t -i image
newuser@131b7ad86360:~$

You might have to give newuser the permissions to execute the programs you intend to run before invoking the user command.

Using non-privileged users inside containers is a good idea for security reasons. It also has a few drawbacks. Most importantly, people deriving images from your image will have to switch back to root before they can execute commands with superuser privileges.

David
  • 330
  • 1
  • 7
Paul Staab
  • 8,430
  • 1
  • 12
  • 6
  • Is 'newuser' the name of the user which you yourself will select? – basickarl Nov 23 '15 at 15:35
  • Yes, exactly. Replace it with a name of your choice. – Paul Staab Nov 23 '15 at 19:10
  • 268
    I'd recommend using the full name options in a Dockerfile, like in a script, instead of the short ones (more to be used when used interactively IMO). `useradd --create-home --shell /bin/bash` is more understandable/readable for coworkers. – Baptiste Mathus Mar 22 '16 at 14:46
  • 43
    In order to set password you could use chpasswd like: `RUN echo 'newuser:newpassword' | chpasswd` – iuridiniz Jul 21 '16 at 17:16
  • 8
    Note that if you're creating a new user with a large user ID, docker may hang/crash as it tries to create *lastlog* - a massive sparse file. Avoid this with the `--no-log-init` option to `useradd`. – davidA Aug 24 '16 at 23:24
  • 16
    Nice tip, @iuridiniz! Don't forget to call it before `USER newuser`. If you also need the user to have root privileges, you can also include `adduser sudo`. – Yamaneko Sep 01 '16 at 19:47
  • @Yamaneko yes or for adding to groups the non-interactive version `useradd` as suggested already in the original answer. – daniel.kahlenberg Jan 24 '17 at 09:54
  • So useradd does the job but how can we handle other commands in docker which requires an interactive prompt.What could be the general solution in that case? – athavan kanapuli Feb 20 '18 at 17:14
  • how can you give this user sudo? – Austin May 23 '18 at 19:10
  • 12
    `/bin/sh: useradd: not found` alpine linux – deathangel908 May 27 '18 at 10:12
  • 4
    @deathangel908 It's available in the `shadow` package: `apk add shadow`. See https://pkgs.alpinelinux.org/package/v3.8/community/x86/shadow – valiano Oct 07 '18 at 08:16
  • Is this only for Linux? Or can we also adduser in Windows? – variable May 29 '20 at 11:43
  • @deathangel908 in alpine try `adduser` command, eg. `RUN adduser -D -g '' newuser` – rezam Oct 24 '21 at 03:42
  • 1
    I get `useradd: Permission denied. useradd: cannot lock /etc/passwd; try again later.` .. and I cannot use `sudo` as then I obviously get `sudo: no tty present and no askpass program specified`. – c0mr4t Jan 16 '22 at 21:49
  • how do you add this user to a specific group? – mike01010 Mar 25 '23 at 17:57
241

Ubuntu

Try the following lines in Dockerfile:

RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u 1001 ubuntu
USER ubuntu
WORKDIR /home/ubuntu

useradd options (see: man useradd):

  • -r, --system Create a system account. see: Implications creating system accounts
  • -m, --create-home Create the user's home directory.
  • -d, --home-dir HOME_DIR Home directory of the new account.
  • -s, --shell SHELL Login shell of the new account.
  • -g, --gid GROUP Name or ID of the primary group.
  • -G, --groups GROUPS List of supplementary groups.
  • -u, --uid UID Specify user ID. see: Understanding how uid and gid work in Docker containers
  • -p, --password PASSWORD Encrypted password of the new account (e.g. ubuntu).

Setting default user's password

To set the user password, add -p "$(openssl passwd -1 ubuntu)" to useradd command.

Alternatively add the following lines to your Dockerfile:

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN echo 'ubuntu:ubuntu' | chpasswd

The first shell instruction is to make sure that -o pipefail option is enabled before RUN with a pipe in it. Read more: Hadolint: Linting your Dockerfile.

kenorb
  • 155,785
  • 88
  • 678
  • 743
  • 10
    Why would the user be in the root group? Isn't the whole point of this is to have a non-root user for security purposes – Novaterata Feb 07 '19 at 15:16
  • 9
    @Novaterata Depending on the use. `root` group doesn't indicate they've root access, it just they've more read access to some files (such as logs), which is useful, but it depends on the project. – kenorb Feb 07 '19 at 15:22
  • 2
    I can see that this works, I automatically am logged in as user, but I'm still generating files owned by root. I even just used 'USER user' since my username on the local user and group is 'user'. Still generates root owned files. Is there something else I should be doing? I'm basically making a docker container that compiles our codebase. So it checks out code from svn, sets up variables using bash source. Could bash commands be doing things as root even if I'm never asked for the root password? – JoeManiaci Jan 03 '20 at 22:30
  • Setting the password interactively with ```SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN echo 'ubuntu:ubuntu' | chpasswd``` didn't work for me, the container was just built, didn't ask me for the password. What did I do wrong? – András Aszódi Jan 28 '21 at 16:50
  • 1
    For security I recommend `-p "$(openssl passwd -6 YOUR_PASS_HERE)"`. The `-1` option uses MD5-based hash that is insecure (in case of db leak). – Real Dec 03 '21 at 22:07
119

To avoid the interactive questions by adduser, you can call it with these parameters:

RUN adduser --disabled-password --gecos '' newuser

The --gecos parameter is used to set the additional information. In this case it is just empty.

On systems with busybox (like Alpine), use

RUN adduser -D -g '' newuser

See busybox adduser

Raffael
  • 2,287
  • 1
  • 15
  • 14
38

Adding user in docker and running your app under that user is very good practice for security point of view. To do that I would recommend below steps:

FROM node:10-alpine

# Copy source to container
RUN mkdir -p /usr/app/src

# Copy source code
COPY src /usr/app/src
COPY package.json /usr/app
COPY package-lock.json /usr/app

WORKDIR /usr/app

# Running npm install for production purpose will not run dev dependencies.
RUN npm install -only=production    

# Create a user group 'xyzgroup'
RUN addgroup -S xyzgroup

# Create a user 'appuser' under 'xyzgroup'
RUN adduser -S -D -h /usr/app/src appuser xyzgroup

# Chown all the files to the app user.
RUN chown -R appuser:xyzgroup /usr/app

# Switch to 'appuser'
USER appuser

# Open the mapped port
EXPOSE 3000

# Start the process
CMD ["npm", "start"]

Above steps is a full example of the copying NodeJS project files, creating a user group and user, assigning permissions to the user for the project folder, switching to the newly created user and running the app under that user.

S.Mishra
  • 3,394
  • 28
  • 20
  • 3
    addgroup failed for me, Step 11/15 : RUN addgroup -S username ---> Running in db9fd22d469d Option s is ambiguous (shell, system) adduser [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID] [--firstuid ID] [--lastuid ID] [--gecos GECOS] [--ingroup GROUP | --gid ID] [--disabled-password] [--disabled-login] [--encrypt-home] USER Add a normal user – teoring Mar 19 '20 at 13:35
  • Thank-you! After many attempts this was the one that worked for me – Paul Fabbroni Jul 27 '21 at 20:07
  • -S is amiguous (shell or system) – Stephan Kristyn Jul 12 '22 at 16:16
26

You can imitate open source Dockerfile, for example:

Node: node12-github

RUN groupadd --gid 1000 node \
    && useradd --uid 1000 --gid node --shell /bin/bash --create-home node

superset: superset-github

RUN useradd --user-group --create-home --no-log-init --shell /bin/bash 
    superset

I think it's a good way to follow open source.

Ryan Miao
  • 471
  • 6
  • 13
16

Everyone has their personal favorite, and this is mine:

RUN useradd --user-group --system --create-home --no-log-init app
USER app

Reference: man useradd (alt)

The RUN line above will add the user and group app:

root@ef3e54b60048:/# id app
uid=999(app) gid=999(app) groups=999(app)

Use a more specific name than app if the image is to be reused as a base image. As an aside, include --shell /bin/bash if you really need.


Partial credit: answer by Ryan M

Asclepius
  • 57,944
  • 17
  • 167
  • 143
  • 1
    This answer was the only one that worked for me. Using FROM python:3.9.6-bullseye – Arkham Angel May 15 '22 at 16:51
  • 1
    @ArkhamAngel because `bullseye` is a release of `debian`, `alpine` will be a bit different. I really like this answer, cause it is not using shorthand args – vanduc1102 Sep 15 '22 at 08:34
6

Alternatively you can do like this.

RUN addgroup demo && adduser -DH -G demo demo

First command creates group called demo. Second command creates demo user and adds him to previously created demo group.

Flags stands for:

-G Group
-D Don't assign password
-H Don't create home directory
Lukasz Dynowski
  • 11,169
  • 9
  • 81
  • 124
2

Kindly add below entries inside dockerfile in order to create a sudo user in container.

RUN useradd -m  -s /bin/bash ubuntu
RUN usermod -aG sudo ubuntu && echo "ubuntu ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/ubuntu
RUN chmod 0440 /etc/sudoers.d/ubuntu // should be 0440
USER ubuntu:ubuntu
WORKDIR /home/ubuntu
jukialeN23
  • 13
  • 2
linux.cnf
  • 519
  • 6
  • 7
2
WORKDIR /api

RUN adduser -D nameuser

COPY --from=builder --chown=nameuser:nameuser /api

USER nameuser
elmerzouki
  • 199
  • 2
  • 7
0

Add this line to your Dockerfile (You can run any linux command this way)

RUN useradd -ms /bin/bash yourNewUserName
user6123723
  • 10,546
  • 18
  • 67
  • 109
basickarl
  • 37,187
  • 64
  • 214
  • 335