Make Docker Container secure as possible - docker

I am looking for a way to make docker images secure as possible. Maybe there is a way to prevent the execution of any process other than specified in CMD?
For example I run the following image, but once a hacker would be able to get into the container he/she could create a python file and do mostly anything with the data in the container.
I also see that wget is available, so the attacker could also easily download his/her files and start sending data to his home. Any tips are welcome.
FROM python:alpine3.16 as builder
RUN pip install --upgrade pip
WORKDIR /opt/working-files
COPY requirements.txt .
RUN python -m venv ./venv
ENV PATH="/opt/working-files/venv/bin:$PATH"
RUN pip install -r requirements.txt
RUN rm -rf requirements.txt && rm -rf ~/.cache/pip
COPY app/ ./app
FROM python:alpine3.16
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PATH="/opt/working-files/venv/bin:$PATH"
RUN addgroup -S 10033 && adduser -S 10033 -G 10033
USER 10033:10033
COPY --from=builder /opt /opt
WORKDIR /opt/working-files/app
CMD ["gunicorn", "-b", "0.0.0.0:8000", "-w", "1", "app:app"]

Related

Setting up Dockerfile to use non-root user

I'm currently having an issue when I tried to run pip as a non-root user in my Dockerfile. When It starts to build the wheel it gives these warnings WARNING: The script foo is installed in '/home/myuser/.local/bin' which is not on PATH. for pep8, sqlformat, isort, gunicorn, django-admin, epylint, pylint, pyreverse, and symilar.
In the current code I have, the build fails with the error COPY failed: stat usr/src/app/wheels: file does not exist when it tries to run COPY --from=builder /usr/src/app/wheels /wheels although it was failing earlier before I took out --wheel-dir /usr/src/app/wheels from line 35.
###########
# BUILDER #
###########
# pull official base image
FROM python:3.9.4-alpine as builder
# set work directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install psycopg2 dependencies
RUN apk update \
&& apk add postgresql-dev gcc python3-dev musl-dev
# lint
RUN pip install --upgrade pip
RUN pip install flake8==3.9.2
COPY . .
RUN flake8 --ignore=E501,F401 .
# install dependencies
RUN adduser -D myuser
USER myuser
WORKDIR /home/myuser
COPY --chown=myuser:myuser requirements.txt requirements.txt
RUN pip install --user -r requirements.txt
ENV PATH="/home/myuser/.local/bin:${PATH}"
COPY --chown=myuser:myuser . .
WORKDIR /usr/src/app
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
#########
# FINAL #
#########
# pull official base image
FROM python:3.9.4-alpine
# create directory for the app user
RUN mkdir -p /home/app
# create the app user
RUN addgroup -S app && adduser -S app -G app
# create the appropriate directories
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME
RUN mkdir $APP_HOME/staticfiles
RUN mkdir $APP_HOME/mediafiles
WORKDIR $APP_HOME
# install dependencies
RUN apk update && apk add libpq
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt .
RUN pip install --upgrade pip
RUN pip install --no-cache /wheels/*
# copy entrypoint.prod.sh
COPY ./entrypoint.prod.sh .
RUN sed -i 's/\r$//g' $APP_HOME/entrypoint.prod.sh
RUN chmod +x $APP_HOME/entrypoint.prod.sh
# copy project
COPY . $APP_HOME
# copy media files
COPY ./media/ $APP_HOME/mediafiles
# chown all the files to the app user
RUN chown -R app:app $APP_HOME
# change to the app user
USER app
# run entrypoint.prod.sh
ENTRYPOINT ["/home/app/web/entrypoint.prod.sh"]
I've tried tinkering with the WORKDIR, ENV PATH, and RUN pip wheel.

Permissions problem in Docker container built in Ubuntu VM composed of files created on Windows host

I work on a project that has a large number of Java SpringBoot services (and other types) running in k8s clusters. Each service has a small start script that executes a more complex script that is provided in a configmap. This all works fine in builds and at runtime.
I need to make some changes to that complex script. I've already made the changes and tested the concept in an isolated script. I still need to do more testing of it. I am attempting to take some of the command lines that run in our Linux build system and run them on my VirtualBox Ubuntu VM that runs on my Windows 10 laptop. Although I am running this on the VM, most of the files were created and written on the host Windows 10 laptop that I get to using a VirtualBox Shared Folder.
When I look at the "ls -l" output of "startService.sh", I just get this:
-rwxrwx--- 1 root vboxsf 634 Aug 24 15:07 startService.sh*
Note that I am running docker with my own uid, and I have that uid in the "vboxsf" group.
It seems like when the file gets copied into the image, either the owner or the perms get changed in a way that make it inaccessible from within the container.
I tried adding a "RUN chmod 777 startService.sh" in the Dockerfile, just before the ENTRYPOINT, but that fails at build time with this:
Step 23/26 : RUN chmod 777 startService.sh
---> Running in 6dbb89c930c1
chmod: startService.sh: Operation not permitted
The command '/bin/sh -c chmod 777 startService.sh' returned a non-zero code: 1
I don't know why this is happening, or whether this is something that might mitigate this.
My "docker build" command looks like it went fine. I saw it execute all the steps that the normal build shows. The "docker run" step seemed to go fine, but it finished very quickly. When I looked at the "docker log" for the container, it just said entirely:
/bin/sh: ./startService.sh: Permission denied
Note that everything here is done the same way it is on the build server. There seems to be something funny with the fact that I'm running an Ubuntu
You have to write chmod +x startService.sh before docker run or docker-compose up -d --build
And example Dockerfile for django. Look at actions with wait-for, you must make same
###########
# BUILDER #
###########
# pull official base image
FROM python:3.8.3-slim as builder
# set work directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install psycopg2 dependencies
RUN apt-get update \
&& apt-get -y install libpq-dev gcc \
python3-dev musl-dev libffi-dev\
&& pip install psycopg2
# lint
RUN pip install --upgrade pip
COPY . .
# install dependencies
COPY ./requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
# copy project
COPY . .
#########
# FINAL #
#########
# pull official base image
FROM python:3.8.3-slim
# create directory for the app user
RUN mkdir -p /home/app
# create the app user
RUN addgroup --system app && adduser --system --group app
# create the appropriate directories
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME
RUN mkdir $APP_HOME/static
RUN mkdir $APP_HOME/media
RUN mkdir $APP_HOME/currencies
WORKDIR $APP_HOME
# install dependencies
RUN apt-get update && apt-get install -y libpq-dev bash netcat rabbitmq-server
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt .
COPY wait-for /bin/wait-for
COPY /log /var/log
COPY /run /var/run
RUN pip install --no-cache /wheels/*
# copy project
COPY . $APP_HOME
# chown all the files to the app user
RUN chown -R app:app $APP_HOME
RUN chown -R app:app /var/log/
RUN chown -R app:app /var/run/
EXPOSE 3000
# change to the app user
USER app
# only for dgango
CMD ["gunicorn", "Config.asgi:application", "--bind", "0.0.0.0:8000", "--workers", "3", "-k","uvicorn.workers.UvicornWorker","--log-file","-"]

RUN addgroup / adduser. Get: Option s is ambiguous (shell, system) error

I am Dockerising my first flask app and following an online guide but stuck with the following line in Dockerfile.prod.
RUN addgroup -S app && adduser -S app -G app
I get the error Option s is ambiguous (shell, system)
I came across this SO post and tried the accepted answer (pretty much the same):
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
With the same outcome. I have tried specifying --shell and --system, and --group instead get the error addgroup: Only one or two names allowed.
No matter what I try, I get these errors:
Option s is ambiguous (shell, system)
Option g is ambiguous (gecos, gid, group)
I am on Windows (using Docker, not Docker Windows). Not sure if that's the issue. But I cannot find a solution.
Dockerfile.prod
FROM python:3.8.1-slim-buster as builder
# set work directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install system dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc
# lint
RUN pip install --upgrade pip
RUN pip install flake8
COPY . /usr/src/app/
RUN flake8 --ignore=E501,F401,E722 .
# install python dependencies
COPY ./requirements.txt .
# COPY requirements .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
# RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements/prod.txt
# pull official base image
FROM python:3.8.1-slim-buster
# create directory for the app user
RUN mkdir -p /home/app
# create the app user
RUN addgroup -S app && adduser -S app -G app
# create the appropriate directories
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME
WORKDIR $APP_HOME
# install dependencies
RUN apt-get update && apt-get install -y --no-install-recommends netcat
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt .
# COPY --from=builder /usr/src/app/requirements/common.txt .
# COPY --from=builder /usr/src/app/requirements/prod.txt .
RUN pip install --upgrade pip
RUN pip install --no-cache /wheels/*
# copy entrypoint-prod.sh
COPY ./entrypoint.prod.sh $APP_HOME
# copy project
COPY . $APP_HOME
# chown all the files to the app user
RUN chown -R app:app $APP_HOME
# change to the app user
USER app
# run entrypoint.prod.sh
ENTRYPOINT ["/home/app/web/entrypoint.prod.sh"]
I do understand you would like to create a user and group both called "app" and the user shall be in that group, both being a system account/group.
That's possible by online using adduser
RUN adduser --system --group app
Maybe this helps:
https://github.com/mozilla-services/Dockerflow/issues/36
Depending on the underlying distribution of the container, these
options can be ambiguous. The options should use the full name format
for readability.

Docker multistage build Issues

My Current Docker file looks like below . I'm trying to use h2o as a base for my ML model service .Now h2o requires JRE and i'm forced to install the required packages for my flask script . It was as heavy as 1.8 Gig so attempted multi-stage build (script below )
#Original Docker File
FROM h2oai/h2o-open-source-k8s
MAINTAINER rajesh.r6r#gmail.com
USER root
WORKDIR /app
ADD . /app
RUN set -xe \
&& apt-get update -y \
&& apt-get install python-pip -y \
&& rm -rf /var/lib/apt/lists/* # remove the cached files
RUN pip install --upgrade pip
RUN pip install --trusted-host pypi.python.org -r requirements.txt
EXPOSE 5005
EXPOSE 54321
ENV NAME World
CMD ["python", "app.py"]
I attempted doing multi-stage builds as follows , but this only results in a python image skipping the h2o part . What am I Missing ?
#Multi-Stage Docker File
FROM h2oai/h2o-open-source-k8s AS baseimage
FROM python:3.7-slim
USER root
WORKDIR /app
ADD . /app
RUN pip install --trusted-host pypi.python.org -r requirements.txt
EXPOSE 5005
EXPOSE 54321
ENV NAME World
CMD ["python", "app.py"]

How to change permission of a folder to 777 in Dockerfile?

I have a project directory like this:
|-var/www
|-docker-compose.yml
|-app
|--uploads
|---photos
|-Dockerfile
This is my docker-compose.yml file:
myapp:
build:
context: myfolder
dockerfile: Dockerfile
container_name: flask
image: api/v1:01
restart: unless-stopped
environment:
APP_ENV: "prod"
APP_DEBUG: "False"
APP_PORT: 5000
volumes:
- appdata:/var/www
What I want:
I want to change app/uploads/photos this folder's permission to 777.This is an upload folder,so user can upload to this folder.
My Dockerfile now is look like this:
FROM python:3.6.8-alpine3.9
ENV GROUP_ID=1000 \
USER_ID=1000
WORKDIR /var/www/
ADD . /var/www/
RUN apk add --no-cache build-base libffi-dev openssl-dev ncurses-dev
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
RUN addgroup -g $GROUP_ID www
RUN adduser -D -u $USER_ID -G www www -s /bin/sh
USER www
EXPOSE 5000
After looking in this question,In order to achieve what I want,I tried below:
FROM python:3.6.8-alpine3.9
ENV GROUP_ID=1000 \
USER_ID=1000
WORKDIR /var/www/
ADD . /var/www/
RUN apk add --no-cache build-base libffi-dev openssl-dev ncurses-dev
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
RUN addgroup -g $GROUP_ID www
RUN adduser -D -u $USER_ID -G www www -s /bin/sh
RUN chown -R www:www /var/www
RUN chmod -R 777 /var/www/uploads
RUN chmod -R 777 /var/www/uploads/photos
USER www
EXPOSE 5000
But seems like the chmod command in my dockerfile is not taking effect.Cause whenever I upload some files to app/uploads/photos in my code,my nginx server keep getting this error:
PermissionError: [Errno 13] Permission denied: '/var/www/uploads/photos/myfilename.png'
Somebody please help.Please provide a solution for how to change the permission of a folder in Dockerfile.
UPDATE:
I tried to change the permission of /var/www/uploads after build the container and the container is running by doing below:
docker exec -it myapp /bin/sh
then run
chmod -R 777 /var/www/uploads
What I get is chmod: /var/www/uploads: Operation not permitted
Therefore I suspect the this error will also happened when the docker is building,then according to this answer from serverfault, I tried to modify the dockerfile to this:
FROM python:3.6.8-alpine3.9
ENV GROUP_ID=1000 \
USER_ID=1000
WORKDIR /var/www/
ADD . /var/www/
USER root
RUN chmod -R 777 /var/www/uploads
RUN addgroup -g $GROUP_ID www
RUN adduser -D -u $USER_ID -G www www -s /bin/sh
USER www
RUN apk add --no-cache build-base libffi-dev openssl-dev ncurses-dev
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
EXPOSE 5000
But it still doesnt work.Look like my above approach is also wrong.Cause I already run in root in the dockerfile.But at the same time,when I access the container in host using docker exec,also getting Operation not permitted.
I am very new in Docker.Just cant figure it out how to get this done.
What I hope to know:
1) How to change the folder var/www/uploads to permission 777?
2) What is the problem causing I cant change the permission from my approach?
3) What is the better way to achieve this? (If any)

Resources