Containers are not a security boundary by default. Proper hardening is essential to prevent container escapes and privilege escalation.
Secure Dockerfile
# Bad: Running as root
FROM ubuntu:latest
RUN apt-get update && apt-get install -y nginx
# Good: Non-root user, minimal image
FROM nginx:alpine
RUN adduser -D -u 1001 appuser
USER appuser
COPY --chown=appuser:appuser ./app /usr/share/nginx/html
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
Image Scanning
# Scan with Trivy
trivy image myapp:latest
# Scan with Docker Scout
docker scout cves myapp:latest
# Scan with Grype
grype myapp:latest
Runtime Security
# Run with security options
docker run \
--read-only \
--security-opt=no-new-privileges:true \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
--user 1001:1001 \
myapp:latest
Never Do This
- Run containers as root
- Use
--privilegedflag - Mount Docker socket inside containers
- Use
latesttag in production
Best Practices
- Use distroless or alpine base images
- Scan images in CI/CD pipeline
- Sign images with Docker Content Trust
- Use read-only filesystem
- Implement resource limits
December 2024