Docker Security
Docker security is a layered concern: the Docker daemon itself (which runs as root), the container runtime isolation, the container images, and application configuration inside containers. The most dangerous default is that the Docker socket (/var/run/docker.sock) grants root-equivalent access to anyone who can reach it. Understanding and addressing this and other defaults is essential before running Docker on production servers.
Docker attack surface
Docker security risks:
1. Docker socket (/var/run/docker.sock)
Mounting this gives container full host control
→ Never mount docker.sock in containers unless absolutely necessary
2. Running as root inside container
If container escape occurs, attacker has root on host
→ Use USER directive in Dockerfile, run as non-root
3. Unpatched base images
Old Alpine/Ubuntu base images have known CVEs
→ Rebuild images regularly, scan with trivy/grype
4. Exposed Docker API (port 2375/2376)
Unauthenticated Docker API = full server compromise
→ Never expose port 2375 publiclyRunning containers as non-root
# In Dockerfile — add a non-root user:
FROM ubuntu:22.04
RUN useradd -m -u 1001 appuser
WORKDIR /app
COPY . .
RUN chown -R appuser:appuser /app
USER appuser # Switch to non-root user
CMD ["./myapp"]
# Run existing image as non-root:
docker run --user 1000:1000 nginx:alpine
# Verify user inside container:
docker exec mycontainer id
docker exec id output
uid=1001(appuser) gid=1001(appuser) groups=1001(appuser)
# Good — not running as root (uid=0)
Resource limits
# Without resource limits, one container can starve all others
# Set CPU and memory limits:
docker run -d --memory="512m" --memory-swap="512m" --cpus="0.5" --name myapp myapp:latest
# In docker-compose.yml:
# services:
# app:
# deploy:
# resources:
# limits:
# cpus: '0.5'
# memory: 512M
# reservations:
# cpus: '0.25'
# memory: 256M
# Verify limits are applied:
docker inspect myapp | grep -i "memory\|cpu"
Image security
# Scan images for CVEs with Trivy (excellent free scanner):
sudo apt install -y wget
wget https://github.com/aquasecurity/trivy/releases/latest/download/trivy_*_Linux-64bit.deb
sudo dpkg -i trivy_*_Linux-64bit.deb
# Scan an image:
trivy image nginx:latest
trivy scan output
nginx:latest (debian 12.5)
Total: 78 (UNKNOWN: 0, LOW: 36, MEDIUM: 33, HIGH: 8, CRITICAL: 1)
CRITICAL: CVE-2024-XXXX openssl 3.0.x < 3.0.y...
# Use minimal base images (smaller attack surface):
# Instead of: FROM ubuntu:22.04 (1.4GB)
# Use: FROM alpine:3.19 (5MB)
# Or: FROM scratch (empty, for static binaries)
# Or: FROM distroless/base (Google's minimal runtime images)
Conclusion
Docker security priority list: (1) never expose the Docker socket to containers that don't need it; (2) run application containers as non-root using the USER directive; (3) set memory and CPU limits on every container to prevent resource exhaustion; (4) scan images with Trivy before pushing to production and rebuild regularly to pick up base image security patches. The Docker socket grants root access — treat mounting it with the same caution as giving root credentials.
Need help with Ubuntu administration?
Work directly with Muhammad Irfan Aslam for Ubuntu Server, Linux, cloud, Docker, DevOps, CI/CD, or infrastructure troubleshooting support.
Work with Muhammad Irfan Aslam