Docker Security for Developers: 15 Practical Rules
Docker Security for Developers: 15 Practical Rules
Every Dockerfile default is a security decision. Here are 15 rules that turn insecure defaults into production-ready containers.
Docker containers run with permissive defaults. Run as non-root, use minimal base images, never embed secrets, scan for vulnerabilities, drop Linux capabilities, and sign your images. These 15 rules cover the build, image, runtime and deployment layers of container security.
Docker makes it easy to package and deploy applications. It also makes it easy to ship containers with root access, hardcoded secrets, unpatched vulnerabilities and excessive permissions. The good news: every one of these issues has a straightforward fix.
This article covers 15 practical security rules every developer should apply, with concrete Dockerfile examples and commands.
Rule 1: Run as Non-Root User
# GOOD: Create and use non-root user
FROM python:3.12-slim
RUN groupadd -r appuser && useradd -r -g appuser appuser
COPY --chown=appuser:appuser . /app
WORKDIR /app
USER appuser
CMD ["python", "main.py"]
# Verify: docker run --rm myapp whoami
# Output should be "appuser", NOT "root"
By default, Docker runs containers as root. If a container escape vulnerability is exploited, root inside the container means root on the host. Creating a dedicated user limits the blast radius.
Rule 2: Use Minimal Base Images
| Image | Security Level | Trade-off |
|---|---|---|
| gcr.io/distroless/* | Highest | No shell, no package manager — debugging harder |
| alpine:3.19 | High | ~5 MB, has shell and apk for debugging |
| python:3.12-slim | Medium | ~50 MB, Debian minimal, easy debugging |
| python:3.12 | Lower | ~900 MB, full Debian — many unused packages |
Every package in the base image is potential attack surface. Smaller images have fewer vulnerabilities and are faster to pull and deploy.
Rule 3: Never Store Secrets in Images
# BAD: Anyone who pulls the image can see these
ENV API_KEY=sk_live_REAL_KEY
ENV DATABASE_PASSWORD=p4ssw0rd
# GOOD: Inject at runtime, never in the image
docker run -e API_KEY=$API_KEY myapp
# BEST: Fetch from secret manager at startup
# Vault / AWS Secrets Manager / GCP Secret Manager
Rule 4: Use .dockerignore
# .dockerignore
.git
.env
.env.*
*.pem
*.key
*.cert
node_modules
__pycache__
.vscode
tests/
README.md
Even deleted files exist in image layers. If you COPY . /app without a .dockerignore, your .env file and private keys enter the image — even if you delete them in a subsequent RUN instruction.
Rule 5: Pin Image Versions
# BAD: Unpredictable
FROM python:latest
# GOOD: Pinned version
FROM python:3.12.7-slim
# BEST: Pinned by digest (maximum reproducibility)
FROM python:3.12.7-slim@sha256:abc123def456...
Rule 6: Use Read-Only Filesystem
docker run --read-only --tmpfs /tmp myapp
# Container filesystem is read-only
# Writes go to /tmp (in-memory only)
# Malware cannot persist files to disk
Rule 7: Scan Images for Vulnerabilities
| Tool | Type | Command |
|---|---|---|
| Docker Scout | Built-in | docker scout cves myapp |
| Trivy | Open source | trivy image myapp:latest |
| Grype | Open source | grype myapp:latest |
| Snyk | Freemium | snyk container test myapp |
Add scanning to your CI/CD pipeline. Fail the build on HIGH or CRITICAL vulnerabilities.
Rules 8-10: Build Hygiene
| Rule | Do This | Not This |
|---|---|---|
| Rule 8: Fewer packages | Install only what app needs | curl, vim, git, wget in prod |
| Rule 9: COPY not ADD | COPY app/ /app/ | ADD http://... /app/ |
| Rule 10: Resource limits | --memory=512m --cpus=1 | Unlimited RAM and CPU |
Rules 11-13: Runtime Security
# Rule 11: Use trusted base images
# Prefer Docker Official Images, Verified Publishers, or distroless
# Rule 12: Drop all capabilities, add only what's needed
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp
# Rule 13: Never use --privileged
# Use --device for specific hardware access instead
docker run --device=/dev/gpu myapp
Rules 14-15: Supply Chain Security
# Rule 14: Multi-stage builds (smaller = safer)
FROM python:3.12 AS builder
COPY . /build
RUN pip install --user -r requirements.txt
FROM python:3.12-slim
RUN groupadd -r app && useradd -r -g app app
COPY --from=builder /root/.local /home/app/.local
COPY --from=builder /build /app
USER app
CMD ["python", "main.py"]
# Rule 15: Sign and verify images
# Sign with cosign
cosign sign --key cosign.key myregistry/myapp:v1
# Verify before deploy
cosign verify --key cosign.pub myregistry/myapp:v1
The Complete Secure Dockerfile
Combining all 15 rules into one template:
# Rule 5: Pin version | Rule 14: Multi-stage
FROM python:3.12.7-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
COPY . .
# Rule 2: Minimal base | Rule 1: Non-root
FROM python:3.12.7-slim
RUN groupadd -r app && useradd -r -g app -d /home/app app
COPY --from=builder --chown=app:app /root/.local /home/app/.local
COPY --from=builder --chown=app:app /build /home/app
WORKDIR /home/app
# Rule 1: Non-root | Rule 6: Read-only ready
USER app
ENV PATH=/home/app/.local/bin:$PATH
# Rule 3: No secrets | Rule 10: Resource limits at runtime
# docker run --read-only --memory=512m --cpus=1 myapp
CMD ["python", "main.py"]
Security Checklist
BUILD: [ ] 1. Non-root user (USER directive) [ ] 2. Minimal base image (alpine/slim/distroless) [ ] 3. No secrets in image or ENV [ ] 4. .dockerignore configured [ ] 5. Pinned image versions (not :latest) IMAGE: [ ] 6. Read-only filesystem where possible [ ] 7. Vulnerability scan passed [ ] 8. No unnecessary packages installed [ ] 9. COPY used instead of ADD [ ] 10. Resource limits set at runtime RUNTIME: [ ] 11. Trusted base image source [ ] 12. Linux capabilities dropped (cap-drop=ALL) [ ] 13. --privileged never used [ ] 14. Multi-stage build (smaller image) [ ] 15. Image signed and verified
Try It Yourself
- JSON Formatter — Structure Docker Compose and security configs
- Password Strength Checker — Verify container credential strength
- Secure Random Token Generator — Generate secrets for runtime injection
- CIDR Subnet Calculator — Plan container network isolation
Related BestWordz Articles
- → Docker Images vs Containers Explained
- → Docker vs Virtual Machines
- → Secrets Management for Developers
- → SQL Injection Explained and Prevented
- → Cross-Site Scripting Explained for Web Developers
Further Reading
- → Docker: Engine Security
- → Docker: Dockerfile Best Practices
- → Aqua Security: Docker Security Best Practices
- → OWASP: Docker Security Cheat Sheet
Conclusion
Docker security is not a single setting — it is a series of decisions at build time, image creation, runtime and deployment. The 15 rules in this article cover the most impactful changes: running non-root, using minimal images, keeping secrets out of images, scanning for vulnerabilities, limiting capabilities and signing your supply chain.
Most of these rules add minutes to your Dockerfile and seconds to your CI/CD pipeline. The security improvement is disproportionate to the effort. Start with rules 1-5 (the highest impact, lowest effort), then progressively add the rest.
The default Docker container is not secure. Non-root user, minimal base, no secrets, vulnerability scanning, dropped capabilities and image signing — these six changes eliminate the most common container security failures.
Try the JSON Formatter
Put what you've learned into practice with this free BestWordz tool.
💬 Discuss this topic
Have questions or insights about Docker Security for Developers: 15 Practical Rules? Join the BestWordz Community.
📚 Related Articles
Secrets Management for Developers: From .env Files to Secret Managers
KEY TAKEAWAY Secrets management is the practice of storing, accessing, rotating and revoking cred…
CybersecurityBuild a Production-Style Python CI Pipeline
Key Takeaway --> A production CI pipeline goes beyond running tests. It combines pytest for correc…
CybersecurityDocker vs Virtual Machines: What Developers Need to Know
KEY TAKEAWAY Docker containers and virtual machines both isolate software, but they work at diffe…
CybersecurityIs AI-Generated Code Secure? A Developer Security Checklist
Key Takeaway AI-generated code is not automatically secure. LLMs produce syntactically …
CybersecurityThe 15 AI Security Domains
AI security is not one problem — it is 15 interconnected domains. From prompt injection to sandboxi…
CybersecurityWhy AI Changes the Security Model
AI coding agents can read files, modify code, execute commands, and access tools — capabilities tha…
🔧 Related Tools
Secure Random Token Generator
Generate cryptographically secure random tokens for API keys, session IDs, and more.
Try it now →Base64 Encoder
Encode and decode Base64 data, entirely in your browser.
Try it now →Password Strength Checker
Analyze password strength, entropy, and common weaknesses - entirely in your browser.
Try it now →HMAC-SHA256 Generator
Generate an HMAC-SHA256 signature from a key and message, entirely in your browser.
Try it now →💬 Discuss on BestWordz Community
Join the conversation about Python, Docker, SQL Injection on the BestWordz Community forum.
Visit Forum →