Files
Auditor/theauditor/commands/docker_analyze.py

94 lines
3.6 KiB
Python

"""Docker security analysis command."""
import click
import json
from pathlib import Path
from theauditor.utils.error_handler import handle_exceptions
from theauditor.utils.exit_codes import ExitCodes
@click.command("docker-analyze")
@handle_exceptions
@click.option("--db-path", default="./.pf/repo_index.db", help="Path to repo_index.db")
@click.option("--output", help="Output file for findings (JSON format)")
@click.option("--severity", type=click.Choice(["all", "critical", "high", "medium", "low"]),
default="all", help="Minimum severity to report")
@click.option("--check-vulns/--no-check-vulns", default=True,
help="Check base images for vulnerabilities (requires network)")
def docker_analyze(db_path, output, severity, check_vulns):
"""Analyze Docker images for security issues.
Detects:
- Containers running as root
- Exposed secrets in ENV/ARG instructions
- High entropy values (potential secrets)
- Base image vulnerabilities (if --check-vulns enabled)
"""
from theauditor.docker_analyzer import analyze_docker_images
# Check if database exists
if not Path(db_path).exists():
click.echo(f"Error: Database not found at {db_path}", err=True)
click.echo("Run 'aud index' first to create the database", err=True)
return ExitCodes.TASK_INCOMPLETE
# Run analysis
click.echo("Analyzing Docker images for security issues...")
if check_vulns:
click.echo(" Including vulnerability scan of base images...")
findings = analyze_docker_images(db_path, check_vulnerabilities=check_vulns)
# Filter by severity if requested
if severity != "all":
severity_order = {"critical": 4, "high": 3, "medium": 2, "low": 1}
min_severity = severity_order.get(severity.lower(), 0)
findings = [f for f in findings
if severity_order.get(f.get("severity", "").lower(), 0) >= min_severity]
# Count by severity
severity_counts = {}
for finding in findings:
sev = finding.get("severity", "unknown").lower()
severity_counts[sev] = severity_counts.get(sev, 0) + 1
# Display results
if findings:
click.echo(f"\nFound {len(findings)} Docker security issues:")
# Show severity breakdown
for sev in ["critical", "high", "medium", "low"]:
if sev in severity_counts:
click.echo(f" {sev.upper()}: {severity_counts[sev]}")
# Show findings
click.echo("\nFindings:")
for finding in findings:
click.echo(f"\n[{finding['severity'].upper()}] {finding['type']}")
click.echo(f" File: {finding['file']}")
click.echo(f" {finding['message']}")
if finding.get('recommendation'):
click.echo(f" Fix: {finding['recommendation']}")
else:
click.echo("No Docker security issues found")
# Save to file if requested
if output:
output_path = Path(output)
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, 'w') as f:
json.dump({
"findings": findings,
"summary": severity_counts,
"total": len(findings)
}, f, indent=2)
click.echo(f"\nResults saved to: {output}")
# Exit with appropriate code
if severity_counts.get("critical", 0) > 0:
return ExitCodes.CRITICAL_SEVERITY
elif severity_counts.get("high", 0) > 0:
return ExitCodes.HIGH_SEVERITY
else:
return ExitCodes.SUCCESS