Security Audit Checklist
Use this checklist before deploying to production or during periodic security reviews. Each item includes the command to verify it.
1. Container Runtime
| Check | Pass Criteria | Verify Command |
|---|---|---|
| Non-root user | Config.User is set and not root | docker inspect CONTAINER --format '{{.Config.User}}' |
| Capabilities dropped | CapDrop includes ALL | docker inspect CONTAINER --format '{{json .HostConfig.CapDrop}}' |
No --privileged | Privileged is false | docker inspect CONTAINER --format '{{.HostConfig.Privileged}}' |
| Read-only FS (if feasible) | ReadonlyRootfs is true | docker inspect CONTAINER --format '{{.HostConfig.ReadonlyRootfs}}' |
| No new privileges | Security option set | docker inspect CONTAINER --format '{{json .HostConfig.SecurityOpt}}' |
| No host namespace sharing | No --pid host, --network host | docker inspect CONTAINER --format '{{.HostConfig.PidMode}} {{.HostConfig.NetworkMode}}' |
2. Image Security
| Check | Pass Criteria | Verify Command |
|---|---|---|
| Base image is minimal | Alpine or Distroless-based | Review Dockerfile FROM line |
| No critical CVEs | Scan passes severity policy | trivy image IMAGE:TAG or docker scout quickview IMAGE |
| Image pinned by digest | Digest used in prod Compose | Check compose.yaml for @sha256: references |
| No secrets in layers | No passwords or keys in image | docker history IMAGE --no-trunc |
3. Network Exposure
| Check | Pass Criteria | Verify Command |
|---|---|---|
| Only required ports published | No unnecessary exposed ports | docker ps --format 'table {{.Names}}\t{{.Ports}}' |
| Internal services unpublished | Backend/DB not accessible externally | docker port CONTAINER |
| Bound to specific interface | Not 0.0.0.0 unless intended | Check Compose ports: directives |
| Services on user-defined networks | Not using default bridge | docker inspect CONTAINER --format '{{json .NetworkSettings.Networks}}' |
4. Secrets and Configuration
| Check | Pass Criteria | Verify Command |
|---|---|---|
| No secrets in Compose YAML | No plain-text passwords in file | Review compose.yaml |
| No secrets in Dockerfile | No ENV PASSWORD= or ARG with secrets | Review Dockerfile |
.env files gitignored | .env not tracked | git status .env should show untracked |
| Secrets use file mounts | _FILE pattern or Compose secrets: | Review service configuration |
5. Docker Daemon
| Check | Pass Criteria | Verify Command |
|---|---|---|
| Log rotation configured | max-size and max-file set | cat /etc/docker/daemon.json |
| Daemon socket not exposed | /var/run/docker.sock not published | Review Compose volumes |
| Docker up to date | Running recent stable version | docker version |
Docker Socket Warning
Mounting /var/run/docker.sock into a container gives that container full root access to the host. Only do this for trusted management tools (Portainer, Watchtower) and never for application containers.
Quick Audit Script
Run this against any container for a quick security snapshot:
#!/bin/bash
CONTAINER=$1
echo "=== Security Audit: $CONTAINER ==="
echo "User: $(docker inspect $CONTAINER --format '{{.Config.User}}')"
echo "Privileged: $(docker inspect $CONTAINER --format '{{.HostConfig.Privileged}}')"
echo "ReadOnly FS: $(docker inspect $CONTAINER --format '{{.HostConfig.ReadonlyRootfs}}')"
echo "Cap Drop: $(docker inspect $CONTAINER --format '{{json .HostConfig.CapDrop}}')"
echo "Cap Add: $(docker inspect $CONTAINER --format '{{json .HostConfig.CapAdd}}')"
echo "PID Mode: $(docker inspect $CONTAINER --format '{{.HostConfig.PidMode}}')"
echo "Network Mode: $(docker inspect $CONTAINER --format '{{.HostConfig.NetworkMode}}')"
echo "Security Opt: $(docker inspect $CONTAINER --format '{{json .HostConfig.SecurityOpt}}')"
echo "Ports: $(docker port $CONTAINER 2>/dev/null || echo 'none')"
Usage: bash audit.sh my-container
Key Takeaways
- A security audit should be repeatable and evidence-based -- use commands, not opinions.
- The five areas that matter most: runtime privileges, image supply chain, network exposure, secrets handling, and daemon configuration.
- Run a quick audit before every production deployment and a full audit monthly.
- Automate checks where possible -- the audit script above is a starting point.
What's Next
- Return to the Security Hardening module overview.
- Continue to Module 10: Cheatsheet and Reference for quick command lookup.