Skip to main content

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​

CheckPass CriteriaVerify Command
Non-root userConfig.User is set and not rootdocker inspect CONTAINER --format '{{.Config.User}}'
Capabilities droppedCapDrop includes ALLdocker inspect CONTAINER --format '{{json .HostConfig.CapDrop}}'
No --privilegedPrivileged is falsedocker inspect CONTAINER --format '{{.HostConfig.Privileged}}'
Read-only FS (if feasible)ReadonlyRootfs is truedocker inspect CONTAINER --format '{{.HostConfig.ReadonlyRootfs}}'
No new privilegesSecurity option setdocker inspect CONTAINER --format '{{json .HostConfig.SecurityOpt}}'
No host namespace sharingNo --pid host, --network hostdocker inspect CONTAINER --format '{{.HostConfig.PidMode}} {{.HostConfig.NetworkMode}}'

2. Image Security​

CheckPass CriteriaVerify Command
Base image is minimalAlpine or Distroless-basedReview Dockerfile FROM line
No critical CVEsScan passes severity policytrivy image IMAGE:TAG or docker scout quickview IMAGE
Image pinned by digestDigest used in prod ComposeCheck compose.yaml for @sha256: references
No secrets in layersNo passwords or keys in imagedocker history IMAGE --no-trunc

3. Network Exposure​

CheckPass CriteriaVerify Command
Only required ports publishedNo unnecessary exposed portsdocker ps --format 'table {{.Names}}\t{{.Ports}}'
Internal services unpublishedBackend/DB not accessible externallydocker port CONTAINER
Bound to specific interfaceNot 0.0.0.0 unless intendedCheck Compose ports: directives
Services on user-defined networksNot using default bridgedocker inspect CONTAINER --format '{{json .NetworkSettings.Networks}}'

4. Secrets and Configuration​

CheckPass CriteriaVerify Command
No secrets in Compose YAMLNo plain-text passwords in fileReview compose.yaml
No secrets in DockerfileNo ENV PASSWORD= or ARG with secretsReview Dockerfile
.env files gitignored.env not trackedgit status .env should show untracked
Secrets use file mounts_FILE pattern or Compose secrets:Review service configuration

5. Docker Daemon​

CheckPass CriteriaVerify Command
Log rotation configuredmax-size and max-file setcat /etc/docker/daemon.json
Daemon socket not exposed/var/run/docker.sock not publishedReview Compose volumes
Docker up to dateRunning recent stable versiondocker 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​