Skip to content
BotServBotServ
DockerSecurityRootlessCapabilitiesSecretsImage Scan

Secure Docker Containers

Run Docker containers and images securely. Rootless mode, capabilities, networking, secrets, and image scanning.

S

schutzgeist

3 min read
Secure Docker Containers

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 host unless 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, or distroless.
  • 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

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

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.

Back to Blog
Share:

Related Posts