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
.dockerignoreexcluding.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
USERin 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
--privilegedfor 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
| Stage | Control |
|---|---|
| Base image | Minimal, pinned, maintained |
| Build | Multi-stage, no secrets, .dockerignore |
| CI | Vulnerability scanning, signing |
| Runtime | Non-root, read-only, dropped capabilities |
| Host | No exposed Docker API or mounted socket |
| Registry | Private, 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.