๐ Script for Docker CIS & Image Audit
Salute,
Let's start the week with practice, I decided to share the custom, since you can use it for triage and report conversion.
Scenario
- Determines the Linux/macOS/other platform and selects the image as the main one for auditing
- Creates a directory structure ./audit_reports/{json,text,xlsx,odt} for the results
- Runs Trivy on images, writing JSON vulnerability reports to audit_reports/json/*.json
- Runs the docker-bench-security container with mounts and rights, performing auditing
- If Python with openpyxl and odfpy are additionally side by side, then iterates through all JSON reports
- Scans Docker images for CVEs according to a given list, including docker/docker-bench-security, launches an analysis for each tool with a list of vulnerable libraries, their versions, vulnerability identifiers, severity levels and patch status
- Conducts a configuration audit of the Docker host
Script
set -euo pipefail
echo "Docker CIS & Image Audit"
command -v docker >/dev/null 2>&1 || { echo "no docker"; exit 1; }
docker info >/dev/null 2>&1 || { echo "docker daemon down"; exit 1; }
case "$(uname -s)" in
Linux) PLATFORM="Linux" ;;
Darwin) PLATFORM="macOS" ;;
*) PLATFORM="Other" ;;
esac
BENCH_IMAGE="${DOCKER_BENCH_IMAGE:-docker/docker-bench-security:latest}"
REPORTS_DIR="./audit_reports"
mkdir -p "${REPORTS_DIR}"/{json,text,xlsx,odt}
echo "Platform: ${PLATFORM}"
echo "Image: ${BENCH_IMAGE}"
docker image inspect "${BENCH_IMAGE}" >/dev/null 2>&1 || docker pull "${BENCH_IMAGE}"
if command -v trivy >/dev/null 2>&1; then
trivy image --format json --output "${REPORTS_DIR}/json/docker-bench-security.json" "${BENCH_IMAGE}" || true
for img in nginx:alpine python:3.11-alpine postgres:16-alpine; do
safe=$(echo "${img}" | sed 's/[:\/]/-/g')
trivy image --format json --output "${REPORTS_DIR}/json/${safe}.json" "${img}" || true
done
fi
run_bench() {
out="${REPORTS_DIR}/text/docker-bench-security-cis.txt"
docker run --rm\
--name "docker-bench-$(date +%s)" \
--cap-add audit_control\
--security-opt no-new-privileges \
--network host --pid host --users host \
-e DOCKER_CONTENT_TRUST="${DOCKER_CONTENT_TRUST:-0}" \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /etc:/etc:ro -v /var/lib:/var/lib:ro -v /usr/bin:/usr/bin:ro \
"${BENCH_IMAGE}" 2>&1 | tee "${out}"
}
[ "${PLATFORM}" = "Linux" ] && run_bench || echo "CIS audit in Linux/WSL"
if command -v python3 >/dev/null 2>&1; then
python3 << 'PY'
import json, os, sys
from pathlib import Path
try:
from openpyxl import Workbook
from odf.opendocument import OpenDocumentText
from odf.text import P
except ImportError:
sys.exit(0)
BASE = Path("./audit_reports")
for jf in (BASE / "json").glob("*.json"):
with jf.open() as f:
data = json.load(f)
xlsx = BASE / "xlsx" / (jf.stem + ".xlsx")
wb, ws = Workbook(), Workbook().active
ws = wb.active
ws.append(["Target","Type","VulnID","Severity","Status","Title"])
for r in data.get("Results", []):
t = r.get("Target","N/A")
for v in r.get("Vulnerabilities", []) + r.get("Misconfigurations", []):
ws.append([
t, r.get("Type","unknown"),
v.get("VulnerabilityID","N/A"),
v.get("Severity","UNKNOWN"),
v.get("Status","N/A"),
v.get("Title","N/A")[:80],
])
wb.save(xlsx)
odt = BASE / "odt" / (jf.stem + ".odt")
doc = OpenDocumentText()
doc.text.addElement(P(text=f"Report: {jf.name}"))
for r in data.get("Results", []):
doc.text.addElement(P(text=f"\nTarget: {r.get('Target','N/A')}"))
for i, v in enumerate(r.get("Vulnerabilities", []) + r.get("Misconfigurations", []), 1):
doc.text.addElement(P(text=f"[{i}] {v.get('VulnerabilityID','N/A')} ({v.get('Severity','UNKNOWN')}): {v.get('Title','N/A')}"))
doc.save(str(odt))
PY
fi
echo "Done -> ${REPORTS_DIR}/{json,text,xlsx,odt}"
#appsec #devsecops #specialty #toolchain #containersecurity #vulnmanagement #techsolution
