← All cybersecurity posts

Docker Container Security Best Practices

Containers package your application and its dependencies together. That makes deployment consistent, and it means every vulnerability, secret and misconfiguration in the image ships with it.

Build: start from a minimal base

  • Use small, maintained base images, such as distroless, Alpine or slim variants. Fewer packages means fewer vulnerabilities.
  • Pin versions and digests, not latest, so builds are reproducible and reviewed.
  • Use multi-stage builds to keep compilers and build tools out of the final image.
FROM node:22-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM gcr.io/distroless/nodejs22-debian12
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
USER nonroot
CMD ["dist/server.js"]

Build: never bake in secrets

Secrets copied into an image, or passed as build arguments, remain in image layers even if deleted later. Anyone who can pull the image can extract them.

  • Use build secret mounts for build-time credentials.
  • Inject runtime secrets from a secrets manager or orchestrator.
  • Add a .dockerignore excluding .env, .git, keys and local config.

Build: scan images

Scan images in CI for known vulnerabilities and fail builds on critical issues that have fixes available. Rebuild regularly to pick up patched base images.

Run: drop privileges

  • Run as a non-root user with USER in the Dockerfile.
  • Drop all capabilities and add back only what is required.
  • Use a read-only root filesystem, with writable volumes only where needed.
  • Disallow privilege escalation, for example --security-opt no-new-privileges.
  • Never run --privileged for application containers.

Run: protect the Docker socket

Mounting /var/run/docker.sock into a container gives it control of the Docker daemon, which is equivalent to root on the host. Avoid it, or use tightly scoped alternatives.

Run: never expose the Docker API

The Docker daemon API on TCP port 2375 without TLS gives anyone full control of the host. Exposed Docker APIs are actively scanned for and abused, commonly for crypto mining.

Run: limit resources and network

  • Set memory and CPU limits.
  • Use separate networks for services that do not need to talk.
  • Restrict outbound traffic where possible.

Registry security

  • Keep private images in private registries with access control.
  • Check that no images in public registries contain secrets or internal code.
  • Sign images and verify signatures at deploy time.

Container security checklist

StageControl
Base imageMinimal, pinned, maintained
BuildMulti-stage, no secrets, .dockerignore
CIVulnerability scanning, signing
RuntimeNon-root, read-only, dropped capabilities
HostNo exposed Docker API or mounted socket
RegistryPrivate, access-controlled

Finding container exposure

SecurityInfinity's network agent detects exposed Docker APIs and container management interfaces, and the secrets agent finds credentials leaked from builds and repositories. Start free.

Frequently asked questions

Are containers a security boundary?

They provide isolation, but share the host kernel. Treat them as a useful layer, not as strong as virtual machine isolation.

Is Alpine always the most secure base?

It is small, but compatibility issues can arise. Distroless and slim images are also good options. Size and maintenance matter more than the specific distribution.

How often should images be rebuilt?

Regularly, such as weekly, and whenever a critical vulnerability is fixed in the base image or dependencies.

Find what attackers can see, before they do.

AI pentesting agents test your web app, API and cloud, and every finding comes with evidence and a fix. First report in about 10 minutes.

Stay ahead of attackers.

New vulnerabilities, breach write-ups and practical fixes. A few emails a month.