How to run docker container from non-root user? - docker

How do I make a docker container run as non-root user and have working directory (and its files) owned by a non-root user. Variants I could find in various online tutorials didn't work for some reason, files in /var/www would still be owned by root root.
Below is my Dockerfile, I use docker-compose to build and run containers. Host system is Windows 10.
FROM php:7.4-fpm
ARG user
ARG uid
RUN apt-get update && apt-get install -y \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www
USER $user

You can try this docker file
FROM php:7.4-fpm
ARG user
ARG uid
RUN apt-get update && apt-get install -y \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
RUN addgroup -g $uid $user && \
adduser -S -G $user -u $uid -h $user
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN chown $user:$user -R /var/www
WORKDIR /var/www
USER $user
This change is needed to make sure that the user is created in the docker image
RUN addgroup -g $uid $user && \
adduser -S -G $user -u $uid -h $user
This is needed to change the ownership of the files to the new user
RUN chown $user:$user -R /var/www

Simply add
RUN chown $user:$user -R /var/www
before your WORKDIR instruction. Similarly you can change ownership for other locations as needed.

Related

Why am I getting permission issues while writing a file even after using --user with chmod777?

I have built an image and run that container as --user gauravs. I used --user gauravs to build my image, provided all sudo functionalities to the user and modify the permissions to 777, but still, I am getting a permission error whenever I try to write any file (give commands in my script). I need to manually do touch \<file\> then chmod 777 \<file\>. May I request you to tell me what I am doing wrong?
What I have found when I run any experiment, ps aux|grep <pid> shows some random name associated with it, and that random name is later associated with mine.
awoodard 2805117 8778 0.6 27876664 5175500 ? Rsl 10:31 8783:54 python3 main.py --gpu_num 1
gauravs 2808325 0.0 0.0 9032 2708 pts/1 S+ 12:11 0:00 grep --color=auto 2805117
The Dockerfile I used:
FROM nvidia/cuda:11.1-devel-ubuntu20.04
RUN apt-get update
RUN apt-get -y --no-install-recommends install apt-utils
RUN apt-get -y --no-install-recommends install curl ca-certificates
RUN apt-get -y --no-install-recommends install sudo \
git \
bzip2 \
libx11-6 \
wget \
build-essential \
pkg-config \
vim
RUN mkdir /app
WORKDIR /app
VOLUME /app
CMD bash
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
#RUN apt-get -y --no-install-recommends install python3-dev python3-pip
#ENV user gauravs
#RUN adduser --disabled-password --gecos '' --shell /bin/bash ${user} \
# && chown -R ${user}:${user} /app \
# && adduser ${user} sudo
#RUN echo "%sudo ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers
#USER ${user}
RUN adduser --disabled-password --gecos '' --shell /bin/bash user \
&& chown -R user:user /app \
&& adduser user sudo
RUN echo "%sudo ALL=(ALL) NOPASSWD:ALL">/etc/sudoers
USER user
#ENV PATH=/home/${user}/.local/bin:$PATH
ENV PATH=/home/user/.local/bin:$PATH
RUN sudo chmod 777 -R /app
#RUN sudo chmod 777 /home/${user}
RUN sudo chmod 777 /home/user
RUN sudo apt-get -y --no-install-recommends install python3-dev
RUN sudo apt-get -y --no-install-recommends install python3-pip
# Install Dependencies
RUN pip3 install --user --upgrade setuptools
RUN pip3 install --user wheel
RUN sudo apt-get -y --no-install-recommends install nvidia-cuda-toolkit
COPY requirements.txt .
RUN pip3 install --user -r requirements.txt
RUN pip3 uninstall -y torch
#RUN pip3 install torch==1.8.0+cu111 torchvision==0.9.0+cu111 torchaudio==0.8.0 -f https://download.pytorch.org/whl/torch_stable.html
RUN pip3 install torch==1.11.0+cu113 torchvision==0.12.0+cu113 torchaudio==0.11.0+cu113 -f https://download.pytorch.org/whl/cu113/torch_stable.html
RUN pip3 install --user torchtext==0.9.0

How to give non-root user permission to make and give access to a folder in a Dockerfile

I am trying to create/permission to folders using a non-root user using an image from ubi8/ubi-minimal redhat.
Here are two questions:
Make a folder: Another way to give non-user permission to create folders and give permission to folders. I have searched a bit. Could be possible under the RUN command after it installs all package with microdnf?
Give access: Will RUN chmod -R 777 /app is not best practice and best to do RUN chown -R $USER:$USER /app?
Here is my Dockerfile which I repeat chown a bit for permission.
FROM registry.access.redhat.com/ubi8/ubi-minimal
ENV USER=appuser
RUN microdnf update -y \
&& rm -rf /var/cache/yum \
&& microdnf install gcc wget tar gzip make zlib-devel findutils bzip2-devel openssl-devel ncurses-devel \
sqlite-devel libffi-devel xz-devel which shadow-utils \
&& microdnf clean all ;\
useradd -m $USER
RUN chown -R $USER:$USER /opt
RUN mkdir -p /app
RUN chown $USER /app
USER $USER
WORKDIR /app
COPY . /app/
RUN chown -R $USER:$USER /app

How to Add user when creating docker image from alpine base image

I want to add user www-data as my default user when I run my container in bash mode.
Currently, when I type WHOAMI then it's showing root as user, but I need www-data as user, how to do this in docker.
This is my docker file:
FROM php:7.2-fpm-alpine
LABEL maintainer="y.ghorecha#abc.de" \
muz.customer="xxx" \
muz.product="WIDC" \
container.mode="production"
#https://pkgs.alpinelinux.org/packages
RUN apk add --no-cache --virtual .deps autoconf tzdata build-base libzip-dev mysql-dev gmp-dev \
libxml2-dev libpng-dev zlib-dev freetype-dev jpeg-dev icu-dev openldap-dev libxslt-dev &&\
docker-php-ext-install zip xml mbstring json intl gd pdo pdo_mysql iconv soap \
dom gmp fileinfo sockets bcmath mysqli ldap xsl &&\
echo 'date.timezone="Europe/Berlin"' >> "${PHP_INI_DIR}"/php.ini &&\
cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime &&\
echo 'Europe/Berlin' > /etc/timezone &&\
apk del .deps &&\
apk add --no-cache libzip mysql libxml2 libpng zlib freetype jpeg icu gmp git subversion libxslt openldap \
apache2 apache2-ldap apache2-proxy libreoffice openjdk11-jre ghostscript msttcorefonts-installer \
terminus-font ghostscript-fonts &&\
ln -s /usr/lib/apache2 /usr/lib/apache2/modules &&\
ln -s /usr/sbin/httpd /etc/init.d/httpd &&\
update-ms-fonts
# imap setup
RUN apk --update --virtual build-deps add imap-dev
RUN apk add imap
RUN docker-php-ext-install imap
# copy all codebase
COPY ./ /var/www
# SSH setup
RUN apk update && \
apk add --no-cache \
openssh-keygen \
openssh
# copy Azure specific files
COPY backend/build/azure/backend/ /var/www/backend/
# User owner setup
RUN chown -R www-data:www-data /var/www/
# Work directory setup
WORKDIR /var/www
# copy apache httpd.conf file
COPY httpd.conf /etc/apache2/httpd.conf
# copy crontabs for root user
COPY backend/data/CRONTAB/production/crontab.txt /etc/crontabs/www-data
# SSH Key setup
RUN mkdir -p /home/www-data/.ssh
RUN chown -R www-data:www-data /home/www-data/
#https://github.com/docker-library/httpd/blob/3ebff8dadf1e38dbe694ea0b8f379f6b8bcd993e/2.4/alpine/httpd-foreground
#https://github.com/docker-library/php/blob/master/7.2/alpine3.10/fpm/Dockerfile
CMD ["/bin/sh", "-c", "rm -f /usr/local/apache2/logs/httpd.pid && /usr/sbin/crond start && httpd -DBACKGROUND && php-fpm"]
Please advice on above.
I'd start with first checking if the www-data user even exits in the image. Execute in the running container something like:
sudo cat /etc/passwd | grep www-data
If the user does exist then add the USER www-data directive to the Dockerfile after all commands that do installs, create directories, change permissions, etc. It would be required to also add USER 0 at the beginning to switch to the root user for those commands if the base image doesn't run as root. Looking at the Dockerfile I'd suggest to add USER www-data before the CMD directive.
If the www-data user doesn't exist then it has to be added first. The commands for Alpine Linux are addgroup and adduser. Something like these if the user id for www-data is to be 33 and the group it belongs to is also named www-data and has id of 33:
RUN addgroup -S -g 33 www-data \
&& adduser -S -D -u 33 -s /sbin/nologin -h /var/www -G www-data www-data
Add the above just before RUN chown -R www-data:www-data /var/www/, or make it a single RUN directive:
RUN addgroup -S -g 33 www-data \
&& adduser -S -D -u 33 -s /sbin/nologin -h /var/www -G www-data www-data \
&& chown -R www-data:www-data /var/www/
You can add this line to you dockerfile in order to become the www-data user
USER www-data
This can be either added
in the end of your file (if you want at to become that user before the script exits), or
in the beginning if you want to perform your actions within the docker file as this user.

Permission in docker Container just partly working with chown

I have a problem with access rights in a Docker Container. I am copiyng a folder from the host to the docker image into the folder /var/www/html. This folder has a deeper folder structure. Then, I want www-data which is executing apache to have access to the complete /var/www/html folder. I create the container with the following dockerfile.
#start with base Image from php
FROM php:7.3-apache
#install system dependencies and enable PHP modules
RUN apt-get update && apt-get install -y \
libicu-dev \
libpq-dev \
libmcrypt-dev \
mysql-client \
git \
zip \
unzip \
&& rm -r /var/lib/apt/lists/* \
&& docker-php-ext-configure pdo_mysql --with-pdo-mysql=mysqlnd \
&& docker-php-ext-install \
intl \
mbstring \
pcntl \
pdo_mysql \
pdo_pgsql \
pgsql \
opcache
# zip \
# mcrypt \
#configure imap for mails
RUN apt-get update && \
apt-get install -y \
libc-client-dev libkrb5-dev && \
rm -r /var/lib/apt/lists/*
RUN docker-php-ext-configure imap --with-kerberos --with-imap-ssl && \
docker-php-ext-install -j$(nproc) imap
#install mcrypt
RUN apt-get update \
&& apt-get install -y libmcrypt-dev \
&& rm -rf /var/lib/apt/lists/* \
&& pecl install mcrypt-1.0.2 \
&& docker-php-ext-enable mcrypt
#install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
#set our application folder as an environment variable
ENV APP_HOME /var/www/html
#change uid and gid of apache to docker user uid/gid
RUN usermod -u 1000 www-data && groupmod -g 1000 www-data
# enable apache module rewrite
RUN a2enmod rewrite
#COPY Data to html
COPY --chown=www-data:www-data AppBare/ /var/www/html
#change ownership of our applications
RUN chown -R www-data:www-data /var/www/html
#Copy file to start schema update on startup
ENTRYPOINT [ "sh", "-c", "/var/www/html/app/Console/cake schema update -y && /var/www/html/app/Console/cake migration && /usr/sbin/apachectl -D FOREGROUND"]
EXPOSE 80
After I create and start the container, I get the following error message accessing a website of the serving webserver. However it is also loading the website with images that were copied, so basically, the user has access to e.g. images, css and so on.
SplFileInfo::openFile(/var/www/html/app/tmp/cache/models/demo_backend_cake_model_default_backend_dockertest_list):
failed to open stream: Permission denied
When I go into the console of the container and reset the permissions with the chown command, the problem disappears. So the command itself must be right. Also when I create a volume and mount the folder from the host to /var/www/html, everything is working fine.
How can I give the user the full access to the folder? I also tried out to switch give the access before I copy the data, but that's not working also.
About your last comment
The two files are created by the Entrypoint of the code /var/www/html/app/Console/cake schema update -y. So this is executed by the root user. Is it possible to say to execute this as www-data not as root?
The answer is yes. You have to add the following line before your entrypoint :
USER www-data
This way, everything run after this line will be with this user.

Dockerfile entrypoint unable to switch user

I am unable to switch user to a non-root user from the entry point script. The User directive to change the user in Dockerfile works, but I am not able to change permissions using chmod. To overcome this issue I created entrypoint.sh script to change the folder permissions but when I try to switch user using su command, it apparently doesn't work, the container is still running as root.
The Dockerfile
FROM php:7.2-fpm
# Installing dependencies
RUN apt-get update && apt-get install -y \
build-essential \
mysql-client \
libpng-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
locales \
zip \
jpegoptim optipng pngquant gifsicle \
vim \
unzip \
git \
curl
# Installing composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
ENV USER_ID=1000
ENV GROUP_ID=1000
ENV USER_NAME=www
ENV GROUP_NAME=www
RUN groupadd -g $GROUP_ID $GROUP_NAME
RUN useradd -u $USER_ID -ms /bin/bash -g $GROUP_NAME $USER_NAME
RUN mkdir /app
WORKDIR /app
EXPOSE 9000
COPY ./entrypoint.sh /
RUN ["chmod", "+x", "/entrypoint.sh"]
ENTRYPOINT ["/entrypoint.sh"]
Entrypoint.sh file
#!/bin/bash
if [ -n "$USER_ID" -a -n "$GROUP_ID" ]; then
chown -R $USER_NAME:$GROUP_NAME .
su $USER_NAME
fi
php-fpm
exec "$#"
whatever I do I am not able to switch user from the entrypoint.sh script.
My case is to run the container as non-root user.
I think that your su command should be something like
su $USERNAME --command "/doit.sh"
b/c your entrpoiny script is switching user, doing nothing, and then switching back to root.
To solve this you need to change your dockerfile and add:
RUN echo "root ALL = NOPASSWD: /bin/su ALL" >> /etc/sudoers
Or use gosu what is better:
# install gosu
# seealso:
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
# https://github.com/tianon/gosu/blob/master/INSTALL.md
# https://github.com/tianon/gosu
RUN set -eux; \
apt-get update; \
apt-get install -y gosu; \
rm -rf /var/lib/apt/lists/*; \
# verify that the binary works
gosu nobody true
Then inside entrypoint.sh:
gosu root yourservice &
#ie: gosu root /usr/sbin/sshd -D &
exec gosu no-root-user yourservice2
# ie: exec gosu no-root-user tail -f /dev/null

Resources