Docker Container Security: Non-Root Execution

๐Ÿ’ก Docker Container Security: Non-Root Execution โ€” Executive Summary

Technical architectural analysis, practical configuration manifests, and deployment instructions for Docker Container Security: Non-Root Execution.

Dockerfile Hardening
Example
References and Guidelines (NOTE)

There is a Dockerfile at /root/image/Dockerfile .

Itโ€™s a simple container which tries to make a curl call to an imaginary api with a secret token, the call will 404 , but thatโ€™s okay.

  1. Use specific version 20.04 for the base image
  2. Remove layer caching issues with apt-get
  3. Remove the hardcoded secret value 2e064aad-3a90โ€“4cde-ad86โ€“16fad1f8943e . The secret value should be passed into the container during runtime as env variable TOKEN
  4. Make it impossible to podman exec , docker exec or kubectl exec into the container using bash

You can build the image using

bash
cd /root/image
podman build .
Solution
bash
cd /root/image
vi Dockerfile
```vim
### before
FROM ubuntu
RUN apt-get update
RUN apt-get -y install curl
ENV URL https://google.com/this-will-fail?secret-token=
CMD ["sh", "-c", "curl --head $URL2e064aad-3a90โ€“4cde-ad86โ€“16fad1f8943e"]

### after
FROM ubuntu:20.04
RUN apt-get update && apt-get -y install curl
ENV URL https://google.com/this-will-fail?secret-token=
RUN rm /usr/bin/bash
CMD ["sh", "-c", "curl --head $URL$TOKEN"]
`

podman build -t app .
podman run -d -e TOKEN=2e064aad-3a90โ€“4cde-ad86โ€“16fad1f8943e app sleep 1d
podman ps | grep app #get container_id
podman exec -it $container_id bash #fails
podman exec -it $container_id sh #works
Container Image Footprint User
Example 1
References and Guidelines (NOTE)

There is a given Dockerfile under /opt/ks/Dockerfile .

Using Docker:

  • Build an image named base-image from the Dockerfile.
  • Run a container named c1 from that image.
  • Check under which user the sleep process is running inside the container
Solution
bash
cd /opt/ks
docker build -t base-image .
docker run -d --name c1 base-image
docker ps
```prompt
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS     NAMES
d61223f20e24   base-image   "/bin/sh -c 'sh -c 'โ€ฆ"   16 seconds ago   Up 15 seconds             c1
`
docker exec -it c1 ps
```prompt
PID   USER     TIME  COMMAND
    1 root      0:00 sleep 1d
   21 root      0:00 ps
`

Example 2

References and Guidelines (NOTE)

โ€“ Modify the Dockerfile /opt/ks/Dockerfile to run processes as user appuser
โ€“ Update the image base-image with your change
โ€“ Build a new container c2 from that image

Solution
bash
vi Dockerfile 
```vim
### before
FROM alpine:3.12.3

RUN adduser -D -g '' appuser

CMD sh -c 'sleep 1d'

### after
FROM alpine:3.12.3

RUN adduser -D -g '' appuser
USER appuser

CMD sh -c 'sleep 1d'
`

docker build -t base-image .
docker run -d --name c2 base-image
docker exec -it c2 ps
```prompt
PID   USER     TIME  COMMAND
    1 appuser   0:00 sleep 1d
    7 appuser   0:00 ps
`
Container Namespaces
Example 1

Run two Docker containers app1 and app2 with the following attributes:

  • they should run image nginx:alpine
  • they should share the same PID kernel namespace
  • they should run command sleep infinity
  • they should run in the background (detached)

Then check which container sees which processes and make sense of why.

  • Special note

    โ€“ docker, podman Same.

  • Understanding how it works

    โ€“ Basically, Docker containers use Linux’s Namespace technology to thoroughly isolate processes (PIDs), networks, file systems, etc.
    โ€“ Typical situation: app1 and app2 each have independent rooms (PID namespaces). So app1 has no idea what app2 is doing.
    โ€“ Situation using -pid=container:app1: When running app2, you specified โ€œI want to use the same PID room as app1!โ€ As a result, both containers seamlessly share the process view.

  • When do I use this feature? (Example of practical use)

    โ€“ In practice, this function is mainly used when Sidecar pattern or debugging.
    โ€“ Container debugging/monitoring: When a problem occurs in a running container (app1), you can trace and diagnose the process status inside app1 by attaching another container (app2) containing only debugging tools, without touching the source code or operating environment.
    โ€“ Log and metric collection: When the main application container is running, the collector (Agent) container that monitors the resource usage (CPU, memory, etc.) of the process in real time is grouped and executed in the same PID namespace. The pod structure of Kubernetes is internally designed to share processes and network environments similarly.

Solution
bash
docker run --name app1 -d nginx:alpine sleep infinity
docker exec -it app1 ps aux
```prompt
PID   USER     TIME  COMMAND
    1 root      0:00 sleep infinity
   12 root      0:00 ps aux
`

docker run --name app2 --pid=container:app1 -d nginx:alpine sleep infinity
docker exec -it app2 ps aux
```prompt
PID   USER     TIME  COMMAND
    1 root      0:00 sleep infinity
   18 root      0:00 sleep infinity
   24 root      0:00 ps aux
`
docker exec -it app1 ps aux
```prompt
PID   USER     TIME  COMMAND
    1 root      0:00 sleep infinity
   18 root      0:00 sleep infinity
   30 root      0:00 ps aux
`

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *