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]
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.
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.
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.
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?
-p "$(openssl passwd -6 YOUR_PASS_HERE)"
. The -1
option uses MD5-based hash that is insecure (in case of db leak).
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
adduser
high-level solution is generally preferred to using low-level functions like useradd
.
adduser: unrecognized option: gecos
This doesn't seem to work on Alpine.
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.
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.
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 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
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
Add this line to your Dockerfile (You can run any linux command this way)
RUN useradd -ms /bin/bash yourNewUserName
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 044 /etc/sudoers.d/ubuntu
USER ubuntu:ubuntu
WORKDIR /home/ubuntu
Success story sharing
useradd --create-home --shell /bin/bash
is more understandable/readable for coworkers.RUN echo 'newuser:newpassword' | chpasswd
--no-log-init
option touseradd
.USER newuser
. If you also need the user to have root privileges, you can also includeadduser <username> sudo
./bin/sh: useradd: not found
alpine linux