486

Normally, docker containers are run using the user root. I'd like to use a different user, which is no problem using docker's USER directive. But this user should be able to use sudo inside the container. This command is missing.

Here's a simple Dockerfile for this purpose:

FROM ubuntu:12.04

RUN useradd docker && echo "docker:docker" | chpasswd
RUN mkdir -p /home/docker && chown -R docker:docker /home/docker

USER docker
CMD /bin/bash

Running this container, I get logged in with user 'docker'. When I try to use sudo, the command isn't found. So I tried to install the sudo package inside my Dockerfile using

RUN apt-get install sudo

This results in Unable to locate package sudo

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
drubb
  • 14,533
  • 7
  • 15
  • 11
  • 1
    Just give sudo group to user. http://askubuntu.com/questions/7477/how-can-i-add-a-new-user-as-sudoer-using-the-command-line – Regan Sep 15 '14 at 12:58

14 Answers14

376

Just got it. As regan pointed out, I had to add the user to the sudoers group. But the main reason was I'd forgotten to update the repositories cache, so apt-get couldn't find the sudo package. It's working now. Here's the completed code:

FROM ubuntu:12.04

RUN apt-get update && \
      apt-get -y install sudo

RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

USER docker
CMD /bin/bash
Ohmen
  • 6,194
  • 3
  • 25
  • 35
drubb
  • 14,533
  • 7
  • 15
  • 11
  • 17
    doesn't work in centos. the `adduser` command spits out the usage help for `useradd` – Emad Oct 30 '15 at 10:07
  • 2
    For CentOS, you could add a user and group, then create a shard file under `/etc/sudoers.d/` and set the permissions to `440` on that file. Then the user would have sudo access under CentOS, 6 and up. 5 you'll have to add the `#includedir /etc/sudoers.d` directive in `/etc/sudoers` – FilBot3 Mar 03 '16 at 03:11
  • Doesn't work for me. I have those errors: E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied) E: Unable to lock directory /var/lib/apt/lists/ – Marosinho Sep 25 '19 at 05:41
  • 3
    This doesnt seem to be working for Ubuntu 18.04 docker image – viggy Apr 04 '20 at 11:28
  • My user is called `bot`. Is the right adaptation of your commands: ` RUN useradd -m bot RUN echo "bot:bot" | chpasswd RUN && adduser docker sudo` maybe explaining `echo "docker:docker" | chpasswd && adduser docker sudo` would have helped. – Charlie Parker Sep 15 '22 at 17:56
  • Does not work. `sudo: a terminal is required to read the password` – Cerin Oct 06 '22 at 01:54
  • `adduser` creates a new user. To add the `docker` user to the `sudo` group, use `usermod -a -G sudo docker`. – Aurélien Gâteau Mar 07 '23 at 13:10
371

When neither sudo nor apt-get is available in container, you can also jump into running container as root user using command

docker exec -u root -t -i container_id /bin/bash
Tomáš Záluský
  • 10,735
  • 2
  • 36
  • 64
  • 18
    This is a much better solution to what the OP probably wants to achieve, even though the accepted answer gives the requested solution. At the very least, it's the answer I was looking for! – spikyjt Jun 02 '20 at 12:44
  • 2
    This is the best answer, instead of doing it the hard way with the dockerfile. – Marton Tatai Mar 30 '21 at 08:40
  • +1 I had an issue in changing permission inside docker.. Came to know that only root user can perform this action and this is the only way to accomplish it. In this way, no sudo is required for me! – Praveen Jul 13 '21 at 11:54
  • 2
    Somebody give this man a medal – Timo Huovinen Oct 11 '21 at 20:56
  • 1
    In case you can not use /bin/bash then use /bin/sh instead. 'docker exec -u root -t -i container_id /bin/sh' – azwar_akbar Sep 14 '22 at 13:06
  • this looks nice but when I get into my container nothing seems to have ebeen installed? `docker pull brandojazz/iit-term-synthesis:test` then `docker run -u root -ti brandojazz/iit-term-synthesis:test_arm bash`. Why? https://stackoverflow.com/questions/73735508/why-is-my-container-when-starting-as-root-seem-to-be-empty – Charlie Parker Sep 15 '22 at 17:50
  • This didn't work for me. This did: `docker exec -u 0 -it container_id bash` – Skillz Nov 30 '22 at 02:17
146

The other answers didn't work for me. I kept searching and found a blog post that covered how a team was running non-root inside of a docker container.

Here's the TL;DR version:

RUN apt-get update \
 && apt-get install -y sudo

RUN adduser --disabled-password --gecos '' docker
RUN adduser docker sudo
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

USER docker

# this is where I was running into problems with the other approaches
RUN sudo apt-get update 

I was using FROM node:9.3 for this, but I suspect that other similar container bases would work as well.

Seth Bergman
  • 386
  • 3
  • 12
M. Scott Ford
  • 2,859
  • 1
  • 23
  • 24
  • I am using `ubuntu:bionic-20180724.1`. I used this approach but, after the above, it does not allow me to install another package. I appended one line to the above `Dockerfile` in order to install a package with: `RUN apt-get install -y tree`. However, it gave me this error message: `Step xxxx/xxxx : RUN apt-get install -y tree ---> Running in j5e6gsvwfafa Reading package lists... E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied) E: Unable to lock directory /var/lib/apt/lists/` – edesz Aug 19 '18 at 19:17
  • 4
    @WR I think you need to change that line to read `RUN sudo apt-get install -y tree`. After setting the `USER` to something other than `root`, you'll need to use `sudo` for any commands that require `root` privileges. – M. Scott Ford Aug 22 '18 at 17:29
86

For anyone who has this issue with an already running container, and they don't necessarily want to rebuild, the following command connects to a running container with root privileges:

docker exec -ti -u root container_name bash

You can also connect using its ID, rather than its name, by finding it with:

docker ps -l

To save your changes so that they are still there when you next launch the container (or docker-compose cluster) - note that these changes would not be repeated if you rebuild from scratch:

docker commit container_id image_name

To roll back to a previous image version (warning: this deletes history rather than appends to the end, so to keep a reference to the current image, tag it first using the optional step):

docker history image_name
docker tag latest_image_id my_descriptive_tag_name  # optional
docker tag desired_history_image_id image_name

To start a container that isn't running and connect as root:

docker run -ti -u root --entrypoint=/bin/bash image_id_or_name -s

To copy from a running container:

docker cp <containerId>:/file/path/within/container /host/path/target

To export a copy of the image:

docker save container | gzip > /dir/file.tar.gz

Which you can restore to another Docker install using:

gzcat /dir/file.tar.gz | docker load

It is much quicker but takes more space to not compress, using:

docker save container | dir/file.tar

And:

cat dir/file.tar | docker load
Chris
  • 5,664
  • 6
  • 44
  • 55
  • 1
    Using `docker exec` and `docker commit` to create a new image is not an especially maintainable path; if you need to recreate the image for any reason (say there's a security issue in the original base image) these manual steps won't be tracked anywhere. – David Maze Sep 12 '21 at 17:49
  • Are you saying it would be better to put the commands in the `Dockerfile` or `entrypoint` and rebuild? I might be misunderstanding your point, I do start with 'For anyone who has this issue with an already running container, and they don't necessarily want to rebuild', and I specifically warn the moment we can't backtrack. I have added your warning 'these changes would not be repeated if you rebuild from scratch'. Is there anything else you would add? – Chris Sep 15 '21 at 14:30
23

if you want to connect to container and install something
using apt-get
first as above answer from our brother "Tomáš Záluský"

docker exec -u root -t -i container_id /bin/bash

then try to

RUN apt-get update or apt-get 'anything you want'

it worked with me hope it's useful for all

alexander.polomodov
  • 5,396
  • 14
  • 39
  • 46
Ismail
  • 1,668
  • 1
  • 15
  • 10
13

Unlike accepted answer, I use usermod instead.

Assume already logged-in as root in docker, and "fruit" is the new non-root username I want to add, simply run this commands:

apt update && apt install sudo
adduser fruit
usermod -aG sudo fruit

Remember to save image after update. Use docker ps to get current running docker's <CONTAINER ID> and <IMAGE>, then run docker commit -m "added sudo user" <CONTAINER ID> <IMAGE> to save docker image.

Then test with:

su fruit
sudo whoami

Or test by direct login(ensure save image first) as that non-root user when launch docker:

docker run -it --user fruit <IMAGE>
sudo whoami

You can use sudo -k to reset password prompt timestamp:

sudo whoami # No password prompt
sudo -k # Invalidates the user's cached credentials
sudo whoami # This will prompt for password
林果皞
  • 7,539
  • 3
  • 55
  • 70
11

Here's how I setup a non-root user with the base image of ubuntu:18.04:

RUN \
    groupadd -g 999 foo && useradd -u 999 -g foo -G sudo -m -s /bin/bash foo && \
    sed -i /etc/sudoers -re 's/^%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
    sed -i /etc/sudoers -re 's/^root.*/root ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
    sed -i /etc/sudoers -re 's/^#includedir.*/## **Removed the include directive** ##"/g' && \
    echo "foo ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
    echo "Customized the sudoers file for passwordless access to the foo user!" && \
    echo "foo user:";  su - foo -c id

What happens with the above code:

  • The user and group foo is created.
  • The user foo is added to the both the foo and sudo group.
  • The uid and gid is set to the value of 999.
  • The home directory is set to /home/foo.
  • The shell is set to /bin/bash.
  • The sed command does inline updates to the /etc/sudoers file to allow foo and root users passwordless access to the sudo group.
  • The sed command disables the #includedir directive that would allow any files in subdirectories to override these inline updates.
Seth Bergman
  • 386
  • 3
  • 12
11

If SUDO or apt-get is not accessible inside the Container, You can use, below option in running container.

docker exec -u root -it f83b5c5bf413 ash

"f83b5c5bf413" is my container ID & here is working example from my terminal:

enter image description here

Yogi Ghorecha
  • 1,584
  • 1
  • 19
  • 26
7

This may not work for all images, but some images contain a root user already, such as in the jupyterhub/singleuser image. With that image it's simply:

USER root
RUN sudo apt-get update
Alex Kaszynski
  • 1,817
  • 2
  • 17
  • 17
  • 2
    for the image "fabric8/java-centos-openjdk8-jdk" just adding USER root before the RUN command solved my problem, didn't even need to add the sudo – Marco Martins Jul 22 '20 at 17:22
5

The main idea is that you need to create user that is a root user according to the container.

Main commands:

RUN echo "bot:bot" | chpasswd
RUN adduser bot sudo

the first sends the literal string bot:bot to chpasswd which creates the user bot with the password bot, chpasswd does:

The chpasswd command reads a list of user name and password pairs from standard input and uses this information to update a group of existing users. Each line is of the format:

user_name:password

By default the supplied password must be in clear-text, and is encrypted by chpasswd. Also the password age will be updated, if present.

The second command I assume adds the user bot as sudo.

Full docker container to play with:

FROM continuumio/miniconda3
# FROM --platform=linux/amd64 continuumio/miniconda3

MAINTAINER Brando Miranda "me@gmail.com"

RUN apt-get update \
  && apt-get install -y --no-install-recommends \
    ssh \
    git \
    m4 \
    libgmp-dev \
    opam \
    wget \
    ca-certificates \
    rsync \
    strace \
    gcc \
    rlwrap \
    sudo

# https://github.com/giampaolo/psutil/pull/2103

RUN useradd -m bot
# format for chpasswd user_name:password
RUN echo "bot:bot" | chpasswd
RUN adduser bot sudo

WORKDIR /home/bot
USER bot
#CMD /bin/bash
Charlie Parker
  • 5,884
  • 57
  • 198
  • 323
  • i get the follwoing error when running the dockerfile : /bin/sh: useradd: not found . No idea why – Berni Dec 23 '22 at 15:17
2

If you have a container running as root that runs a script (which you can't change) that needs access to the sudo command, you can simply create a new sudo script in your $PATH that calls the passed command.

e.g. In your Dockerfile:

RUN if type sudo 2>/dev/null; then \ 
     echo "The sudo command already exists... Skipping."; \
    else \
     echo -e "#!/bin/sh\n\${@}" > /usr/sbin/sudo; \
     chmod +x /usr/sbin/sudo; \
    fi
XtraSimplicity
  • 5,704
  • 1
  • 28
  • 28
  • 1
    Depending on the docker images you are using (in my case Ubuntu:18.04), you might need to remove the `-e` from the `echo`. Otherwise it will be present in the file itself, rendering it infunctional. – stiller_leser Nov 23 '18 at 09:58
  • Neat idea, but this will not work if the original command is using sudo options, such as `sudo -E ls`. It will try to execute `-E ls`. – wisbucky Aug 22 '19 at 17:58
2

An example Dockerfile for Centos7. In this example we add prod_user with privilege of sudo.

FROM centos:7

RUN yum -y update && yum clean all

RUN yum -y install openssh-server  python3 sudo

RUN adduser -m prod_user && \
    echo "MyPass*49?" | passwd prod_user --stdin && \
    usermod -aG wheel prod_user && \
    mkdir /home/prod_user/.ssh && \
    chown prod_user:prod_user -R  /home/prod_user/ && \
    chmod 700 /home/prod_user/.ssh

RUN echo "prod_user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
    echo "%wheel ALL=(ALL) ALL" >> /etc/sudoers

RUN echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config

RUN systemctl enable sshd.service

VOLUME [ "/sys/fs/cgroup" ]

ENTRYPOINT ["/usr/sbin/init"]
Erkan Şirin
  • 1,935
  • 18
  • 28
0

There is no answer on how to do this on CentOS. On Centos, you can add following to Dockerfile

RUN echo "user ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/user && \
    chmod 0440 /etc/sudoers.d/user
Animesh
  • 74
  • 2
  • But this command still failed: ```bash Step 6/8 : RUN echo "user ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/user && chmod 0440 /etc/sudoers.d/user ---> Running in daea0aae031c /bin/sh: 1: cannot create /etc/sudoers.d/user: Permission denied ``` – xnervwang May 01 '21 at 20:59
  • This essentially makes your "non-root" user equivalent to root, so long as an attacker knows to preface their commands with `sudo`. It's very marginally better than running as root, but not something I'd generally recommend in a Docker setup. – David Maze Sep 12 '21 at 17:48
0

I'm using an Ubuntu image, while using the docker desktop had faced this issue.

The following resolved the issue:

  1. apt-get update
  2. apt-get install sudo