A main process running as root inside a production container. Hardcoded credentials in a Dockerfile’s ENV. An image based on full Ubuntu with 247 known vulnerabilities. All running in production for 8 months. This isn’t a theoretical exercise, but a real, unfortunately common, scenario I’ve encountered across various environments. Docker and container adoption has revolutionized how we develop and deploy applications, offering unprecedented agility and scalability. However, this flexibility introduces new and complex security challenges. Ignoring these can expose your entire infrastructure to significant risks. Many organizations prioritize deployment speed, often unconsciously sacrificing fundamental security best practices. The consequence is a containerized environment that, while seemingly efficient, is actually a sieve for potential attacks. This guide delves into the 10 most critical, and too often overlooked, Docker security best practices, providing practical guidance to protect your production environments.
Prerequisites / Test Environment
To follow this guide, you will need a Linux environment with Docker installed and running (version 25.x or higher). All commands have been tested on Ubuntu Server 24.04 LTS. Familiarity with basic Docker concepts and the Linux command line is recommended. Ensure you have sudo permissions or are part of the docker group.
1-2. Image Hardening: Minimal Bases and Continuous Scanning
The security of a container begins with its base image. Using minimal images like Alpine Linux or Google’s Distroless images drastically reduces the attack surface by eliminating unnecessary packages and dependencies. Every additional piece of software is a potential vulnerability vector. Avoiding the :latest tag is crucial; prefer specific tags like node:16-alpine to ensure reproducibility and stability. Once you’ve chosen a base image, vulnerability scanning must become a standard practice in your CI/CD pipeline. Tools like Docker Scout (integrated into Docker Desktop and CLI) or Trivy can identify known CVEs.
Example scan with docker scout:
docker scout cves myimage:latest
This analysis provides a detailed report on vulnerabilities present in the image, allowing you to act before a vulnerable image reaches production. According to the Snyk Container Security Report 2024, 75% of Docker images in production contain at least one critical or high-risk vulnerability.
3-4. Runtime Security: Non-Root User and Read-Only Filesystem
A common mistake is running processes inside the container as the root user. This grants the process elevated privileges that, if compromised, can be exploited to attack the host. Configure your Dockerfile to create a non-root user and use it to run the application. If an application needs to access privileged ports (<1024), you can use setcap or a reverse proxy.
Run a container as a non-root user:
docker run --user 1000:1000 myimage
Another fundamental best practice is to make the container’s filesystem read-only. This prevents an attacker from writing malicious files or modifying critical configurations after the container starts. Any persistent data must be managed via external volumes.
Run a container with a read-only filesystem:
docker run --read-only myimage
5-6. Networking: Minimal Exposure and Network Isolation
Every exposed port is a potential entry point. Expose only strictly necessary ports and enable the host firewall to further limit access. Use custom Docker networks (docker network create) to segment your applications. This isolates containers from each other and from the host, limiting the spread of an attack. For example, a database should never be directly accessible from the outside, but only from application containers. Read also: Nginx Reverse Proxy: Secure HTTPS, Headers, and Rate Limiting
7-8. Secrets Management: Never in Environment Variables
Hardcoding credentials or embedding them as environment variables in your Dockerfile or docker run commands is an extremely dangerous practice. This information can be easily extracted via docker inspect or logs. Use dedicated secrets management solutions like Docker Secrets (for Docker Swarm), Kubernetes Secrets, or more robust external solutions such as HashiCorp Vault. These tools offer mechanisms to securely inject secrets into the container at runtime, encrypted and without leaving them in plain text.
Check container configuration (beware of exposed secrets):
docker inspect <container> | jq '.[].HostConfig'
9-10. Logging, Monitoring, and Automated Image Updates
Centralized logging and proactive monitoring are essential for identifying and responding quickly to potential security incidents. Integrate your container logs with solutions like the ELK Stack or Grafana Loki. Monitor resource utilization metrics and security events. Finally, an image update plan is vital. Vulnerabilities are discovered continuously; automate the process of rebuilding and redeploying images when base images are updated or new security patches become available. This can be integrated into your CI/CD pipeline.
Docker Bench Security: Automated Audit in 2 Minutes
For a quick, automated assessment of your Docker host’s security, you can use Docker Bench for Security. This open-source script checks dozens of security best practices based on the CIS Docker Benchmark. It’s an excellent starting point for identifying areas for improvement. You can find more details in the official documentation: https://github.com/docker/docker-bench-security
Run Docker Bench Security:
docker run --rm --net host --pid host --userns host --cap-add audit_control \n -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \n -v /etc:/etc:ro -v /usr/bin/containerd:/usr/bin/containerd:ro \n docker/docker-bench-security
This command will launch a container that runs a series of tests on the Docker host, providing a detailed report with hardening recommendations.
Common Errors and Troubleshooting
One of the most common errors is ignoring warnings from docker scout or other vulnerability scanners. Many believe that a vulnerability in an unused package isn’t relevant, but an attacker might find a way to activate it. Another error is not limiting container capabilities (--cap-drop). For troubleshooting, if a container fails to start with a non-root user, check permissions on files and directories the application attempts to read/write. If a read-only container has issues, ensure persistent data is mounted on writable external volumes.
FAQ — Frequently Asked Questions
What is Docker Bench for Security and how does it help me?
Docker Bench for Security is an open-source script that automates the verification of Docker security best practices, based on the CIS Docker Benchmark. It provides a report with specific recommendations for hardening your Docker host and containers, helping you identify and correct insecure configurations.
What is the difference between Docker Secrets and simple environment variables for secrets?
Environment variables are easily inspectable and can end up in logs. Docker Secrets, on the other hand, are natively managed by Docker Swarm (or Kubernetes Secrets for Kubernetes), encrypted in transit and at rest, and injected into the container as in-memory files, making them much more secure and less susceptible to accidental exposure.
Why is it discouraged to use the :latest tag for Docker images in production?
The :latest tag is volatile and can point to different versions of the image at different times. This makes builds irreproducible and can unexpectedly introduce new vulnerabilities or breaking changes. Using specific tags (e.g., my-app:1.2.3) ensures that the deployed image is always the same.
Should I always use Distroless or Alpine images?
Not necessarily, but they are highly recommended. If your application has complex dependencies that require a more complete base (e.g., Debian or Ubuntu), ensure you remove all non-essential packages from the Dockerfile and regularly scan the image for vulnerabilities. The trade-off between image size, functionality, and security must always be evaluated.
Conclusions with Operational Takeaways
Docker container security is not an option, but a necessity for any production environment. Implementing these 10 best practices will allow you to significantly reduce the attack surface and mitigate risks. Start with image hardening, running processes with minimal privileges, and secure secrets management. Automate scans and integrate security from the earliest stages of the development lifecycle. Don’t wait for an incident to force your hand; proactivity is the only true defense in the containerized ecosystem.
Read also: AD Hardening: 10 Critical Settings to Check Now (2026)