# 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" )