Files

106 lines
4.5 KiB
Python
Raw Permalink Normal View History

# ssl_audit.py — SSL/TLS audit and certificate management commands
def ssl_check_cmd(domain):
"""Return bash cmd to check SSL certificate details for a domain."""
return (
f"echo '=== Certificate Info ===' && "
f"echo | openssl s_client -servername {domain} -connect {domain}:443 2>/dev/null | "
f"openssl x509 -noout -subject -issuer -dates -serial -fingerprint 2>&1 && "
f"echo '' && echo '=== Certificate Chain ===' && "
f"echo | openssl s_client -servername {domain} -connect {domain}:443 -showcerts 2>/dev/null | "
f"grep -E '(subject|issuer|depth)' 2>&1"
)
def ssl_expiry_cmd(domain):
"""Return bash cmd to check certificate expiry date and days remaining."""
return (
f"EXPIRY=$(echo | openssl s_client -servername {domain} -connect {domain}:443 2>/dev/null | "
f"openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2) && "
f"EXPIRY_EPOCH=$(date -d \"$EXPIRY\" +%s 2>/dev/null) && "
f"NOW_EPOCH=$(date +%s) && "
f"DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 )) && "
f"echo \"Domain: {domain}\" && "
f"echo \"Expires: $EXPIRY\" && "
f"echo \"Days remaining: $DAYS_LEFT\" && "
f"if [ $DAYS_LEFT -lt 7 ]; then echo 'STATUS: CRITICAL'; "
f"elif [ $DAYS_LEFT -lt 30 ]; then echo 'STATUS: WARNING'; "
f"else echo 'STATUS: OK'; fi"
)
def ssl_expiry_all_cmd():
"""Return bash cmd to check expiry for all certbot-managed certs."""
return "certbot certificates 2>&1"
def ssl_grade_cmd(domain):
"""Return bash cmd to audit TLS configuration quality."""
return (
f"echo '=== Protocol Support ===' && "
f"for proto in tls1 tls1_1 tls1_2 tls1_3; do "
f" result=$(echo | openssl s_client -$proto -connect {domain}:443 2>&1); "
f" if echo \"$result\" | grep -q 'Cipher is'; then "
f" echo \" $proto: ENABLED\"; "
f" else "
f" echo \" $proto: disabled\"; "
f" fi; "
f"done && "
f"echo '' && echo '=== Cipher Suites ===' && "
f"nmap --script ssl-enum-ciphers -p 443 {domain} 2>/dev/null | "
f"grep -E '(TLSv|cipher|strength|compressors)' || "
f"echo '(install nmap for cipher enumeration)' && "
f"echo '' && echo '=== Security Headers ===' && "
f"curl -sI https://{domain} 2>/dev/null | "
f"grep -iE '(strict-transport|content-security|x-frame|x-content-type|x-xss|referrer-policy|permissions-policy)' || "
f"echo ' No security headers found (BAD)' && "
f"echo '' && echo '=== HSTS ===' && "
f"curl -sI https://{domain} 2>/dev/null | grep -i strict-transport || echo ' HSTS: NOT SET (BAD)'"
)
def ssl_renew_cmd():
"""Return bash cmd to force-renew all certbot certificates."""
return "certbot renew --force-renewal 2>&1"
def ssl_renew_dry_cmd():
"""Return bash cmd to do a dry-run renewal check."""
return "certbot renew --dry-run 2>&1"
def ssl_autorenew_status_cmd():
"""Return bash cmd to check if certbot auto-renewal is set up."""
return (
"echo '=== Certbot Timer ===' && "
"systemctl status certbot.timer 2>&1 || "
"echo 'No certbot timer found' && "
"echo '' && echo '=== Certbot Cron ===' && "
"grep -r certbot /etc/cron* 2>/dev/null || echo 'No certbot cron job found'"
)
def security_headers_cmd(domain):
"""Return bash cmd to add security headers to nginx config for a domain."""
headers = (
"add_header X-Frame-Options DENY always;\\n"
"add_header X-Content-Type-Options nosniff always;\\n"
"add_header X-XSS-Protection \\\"1; mode=block\\\" always;\\n"
"add_header Referrer-Policy strict-origin-when-cross-origin always;\\n"
"add_header Permissions-Policy \\\"camera=(), microphone=(), geolocation=()\\\" always;\\n"
"add_header Strict-Transport-Security \\\"max-age=31536000; includeSubDomains; preload\\\" always;"
)
return (
f"CONF=$(ls /etc/nginx/sites-available/{domain}* 2>/dev/null | head -1) && "
f"if [ -z \"$CONF\" ]; then echo 'No nginx config found for {domain}'; exit 1; fi && "
f"cp \"$CONF\" \"$CONF.bak.$(date +%Y%m%d_%H%M%S)\" && "
f"if ! grep -q 'X-Frame-Options' \"$CONF\"; then "
f" sed -i '/server_name/a\\ {headers}' \"$CONF\" && "
f" nginx -t 2>&1 && systemctl reload nginx && "
f" echo 'Security headers added to '$CONF; "
f"else "
f" echo 'Security headers already present in '$CONF; "
f"fi"
)