Technical architectural analysis, practical configuration manifests, and deployment instructions for Docker Container Security: Non-Root Execution.
Dockerfile Hardening
Example
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.
- Use specific version
20.04for the base image - Remove layer caching issues with
apt-get - Remove the hardcoded secret value
2e064aad-3a90โ4cde-ad86โ16fad1f8943e. The secret value should be passed into the container during runtime as env variableTOKEN - Make it impossible to
podman exec,docker execorkubectl execinto the container usingbash
You can build the image using
cd /root/image
podman build .
Solution
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
There is a given Dockerfile under /opt/ks/Dockerfile .
Using Docker:
- Build an image named
base-imagefrom the Dockerfile. - Run a container named
c1from that image. - Check under which user the
sleepprocess is running inside the container
Solution
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
โ 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
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, podmanSame. -
Understanding how it works
โ Basically, Docker containers use Linux’s Namespace technology to thoroughly isolate processes (PIDs), networks, file systems, etc.
โ Typical situation:app1andapp2each have independent rooms (PID namespaces). Soapp1has no idea whatapp2is doing.
โ Situation using-pid=container:app1: When runningapp2, you specified โI want to use the same PID room asapp1!โ 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 insideapp1by 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
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
`




Leave a Reply