#!/usr/bin/env bash set -euo pipefail IFS=$'\n' ##### CONFIGURACIÓN ##### OUTPUT_DIR="./output" SKIP_PDF=false SEND_MAIL=false EMAIL_RECIPIENT="example@example.com" HELP=false declare -a IMAGES show_help(){ cat </dev/null; then echo "✅"; else echo "❌"; fi done ##### IMÁGENES A ESCANEAR ##### if [ ${#IMAGES[@]} -eq 0 ]; then # locales while read -r repo tag; do [[ "$repo"=="" ]] && continue IMAGES+=("$repo:$tag") done < <(docker images --format '{{.Repository}} {{.Tag}}') # en ejecución while read -r img; do IMAGES+=("$img") done < <(docker ps --format '{{.Image}}') fi # dedupe IMAGES=($(printf "%s\n" "${IMAGES[@]}" | sort -u)) [ ${#IMAGES[@]} -gt 0 ] || { echo "❌ No hay imágenes para auditar."; exit 1; } echo "🖼️ Imágenes a auditar:" for img in "${IMAGES[@]}"; do echo " - $img"; done ##### FUNCIONES ##### check_security(){ local image=$1 local ok=0 if docker inspect "$image" 2>/dev/null | grep -q '"Privileged": true'; then echo " ⚠️ $image usa --privileged"; ok=1 fi if docker inspect "$image" 2>/dev/null | grep -q '/var/run/docker.sock'; then echo " ⚠️ $image monta docker.sock"; ok=1 fi return $ok } download_image(){ local i=$1 echo -n " • pull $i: " if docker pull "$i" &>/dev/null; then echo "✅"; else echo "❌"; fi } scan_image(){ local image=$1 local safe=${image//[:\/]/_} echo "🔍 $image" # Trivy echo -n " - Trivy: " if docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$PWD/$OUTPUT_DIR":/output \ ghcr.io/aquasecurity/trivy:latest image \ --quiet --format json --output /output/"$safe"-trivy.json "$image"; then echo "✅"; else echo "❌"; fi # Checkov (requiere BC_API_KEY) if [ -n "${BC_API_KEY-}" ]; then echo -n " - Checkov: " if docker run --rm \ -e BC_API_KEY="$BC_API_KEY" \ -v "$PWD/$OUTPUT_DIR":/output \ bridgecrew/checkov:latest \ --docker-image "$image" \ --output-file-path /output/"$safe"-checkov.md; then echo "✅"; else echo "❌"; fi else echo " - Checkov: ⚠️ salto (falta BC_API_KEY)" fi # Syft echo -n " - Syft: " if docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$PWD/$OUTPUT_DIR":/output \ anchore/syft:latest "$image" -o json \ >"$OUTPUT_DIR/$safe"-syft.json; then echo "✅"; else echo "❌"; fi # Dive echo -n " - Dive: " if docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$PWD/$OUTPUT_DIR":/output \ wagoodman/dive:latest "$image"; then echo "✅"; else echo "❌"; fi # Nmap echo -n " - Nmap: " if docker run --rm --net host \ instrumentisto/nmap:latest -p- --open "$image" \ -oN /output/"$safe"-nmap.txt; then echo "✅"; else echo "❌"; fi } generate_pdf(){ local mds=( "$OUTPUT_DIR"/*-checkov.md ) if [ ${#mds[@]} -gt 0 ] && [ "$SKIP_PDF" = false ]; then echo "🖨️ Generando PDF..." if pandoc -s "${mds[@]}" -o "$OUTPUT_DIR"/report.pdf; then echo " ✅ report.pdf"; else echo " ❌"; fi else echo "⚠️ No hay Checkov.md o --skip-pdf activo" fi } send_mail(){ if [ "$SEND_MAIL" = true ]; then if command -v mailx &>/dev/null; then echo "📧 Enviando correo..." mailx -s "Informe Auditoría Docker" -a "$OUTPUT_DIR"/report.pdf \ "$EMAIL_RECIPIENT" < /dev/null \ && echo " ✅ correo enviado" else echo "⚠️ mailx no instalado" fi fi } ##### EJECUCIÓN ##### echo "==== DESCARGA IMÁGENES ====" for img in "${IMAGES[@]}"; do download_image "$img"; done echo "==== ESCANEO ====" for img in "${IMAGES[@]}"; do if check_security "$img"; then scan_image "$img" else echo " ❌ $img omitida" fi done echo "==== INFORMES ====" generate_pdf echo "==== CORREO ====" send_mail echo "✅ Listo. Revisa $OUTPUT_DIR"```