Securing Docker Containers
What this article covers
- Why container security matters.
- How Rootless Docker reduces risk.
- How Capabilities, Seccomp, and AppArmor help.
- Securing networks and port bindings.
- Image scanning and up-to-date base images.
Introduction: Securing Docker Containers
Docker simplifies application deployment but also introduces new attack surfaces. Containers running as root, with excessive capabilities, or exposed unprotected on the network can become entry points for compromise. When hosting sensitive workloads like AI services (Ollama, Open WebUI) or databases, solid container hardening is non-negotiable.
This article walks through practical steps to secure Docker containers without unnecessarily complicating operations.
Key concepts
- Rootless: Running Docker as a regular user without root privileges.
- Capabilities: Fine-grained permissions for Linux processes.
- Seccomp: Filtering system calls.
- AppArmor / SELinux: Mandatory Access Control for processes.
- Read-only Filesystem: Container filesystem mounted as read-only.
- No-new-privileges: Container cannot gain additional privileges.
- Image Scanning: Checking images for known vulnerabilities.
- Least Privilege: Granting only the minimum necessary permissions.
Don’t run as root
Most images start as root by default. Create a dedicated user instead:
FROM python:3.11-slim
RUN useradd -m appuser
USER appuser
In Compose:
services:
app:
image: mein-image
user: "1000:1000"
Rootless Docker
Rootless Docker runs the Docker daemon in user context. If a container breaks out, the attacker gains only user privileges, not root.
dockerd-rootless-setuptool.sh install
Trade-offs:
- Not all features available.
- Network and storage functionality limited in some cases.
- GPU passthrough requires additional configuration.
Restrict capabilities
Docker grants some capabilities by default, but most workloads don’t need them:
services:
app:
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
Read-only filesystem
Containers that don’t need write access should run read-only:
services:
app:
read_only: true
tmpfs:
- /tmp
For Ollama or databases, read_only doesn’t make sense since they write to volumes.
No-new-privileges
Prevents a process from gaining elevated privileges through setuid:
services:
app:
security_opt:
- no-new-privileges:true
Restrict network access
- Bind ports only to
127.0.0.1. - Place containers in separate networks.
- Avoid
--network hostunless strictly necessary. - Expose external services through a reverse proxy.
Example:
services:
ollama:
ports:
- "127.0.0.1:11434:11434"
Handle secrets properly
Never store secrets in images or Compose files in plain text:
services:
app:
env_file:
- .env
Better options: Docker Secrets, HashiCorp Vault, Infisical, or encrypted .env files with dotenvx or SOPS.
Image scanning
Regularly scan images for vulnerabilities:
docker scout cves mein-image:latest
Or with Trivy:
trivy image mein-image:latest
Use current and minimal base images
- Source official images from trusted registries.
- Use fixed version tags instead of
latest. - Choose leaner variants like
alpine,slim, ordistroless. - Apply updates regularly.
Logging and monitoring
- Collect container logs centrally.
- Enable audit rules.
- Monitor for unusual network activity.
- Use container runtime security tools like Falco.
Example of a hardened Compose service
services:
app:
image: mein-image:1.2.3
user: "1000:1000"
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
networks:
- backend
env_file:
- .env
restart: unless-stopped
networks:
backend:
Common pitfalls
- Container runs as root: Unnecessary risk.
- All capabilities enabled: Verify what’s actually needed.
- Ports bound to 0.0.0.0: Public exposure without protection.
- Secrets in images: Leaked during registry pushes.
- Outdated images: Contain known vulnerabilities.
- No log monitoring: Attacks go undetected.
- Dismissing Rootless as too complex: Worth the effort in sensitive environments.
Further reading and resources
- BotServ.de Docker Networking
- BotServ.de Docker Reverse Proxy
- BotServ.de Docker Volumes
- BotServ.de Ollama Security
- BotServ.de Secret Management
FAQ: Docker Security
Should I use Rootless Docker? For highly sensitive environments, yes, but not every GPU workload runs smoothly out of the box.
Is running as root inside a container dangerous? Yes, because a container breakout could grant the attacker root access on the host.
How do I scan Docker images? Use Docker Scout, Trivy, or Snyk.
Should I avoid latest tags?
Yes, fixed versions improve reproducibility and security.
What’s better: capabilities or rootless? Both complement each other. Rootless mitigates daemon-level compromise, while capability restrictions limit process permissions.
Sources and references
- Docker Security: https://docs.docker.com/engine/security/
- Docker Bench Security: https://github.com/docker/docker-bench-security
- Trivy: https://trivy.dev/
- Rootless Docker: https://docs.docker.com/engine/security/rootless/
Summary: Securing Docker Containers
Docker security starts with simple measures: don’t run containers as root, drop unnecessary capabilities, use read-only filesystems, bind network ports only to 127.0.0.1, and keep secrets external. Regular image scanning and current base images reduce attack surface. Combining Rootless Docker, no-new-privileges, and network isolation creates a significantly more robust container infrastructure for AI services. Security isn’t a one-time project but an ongoing process of hardening, monitoring, and regular updates.


