--- - name: SSL Certificate Management and Monitoring hosts: all gather_facts: yes vars: # 常见证书路径 cert_paths: - /etc/ssl/certs - /etc/letsencrypt/live - /etc/nginx/ssl - /etc/apache2/ssl - /usr/local/share/ca-certificates # 需要检查的服务端口 ssl_services: - { name: "HTTPS", port: 443 } - { name: "SMTPS", port: 465 } - { name: "IMAPS", port: 993 } - { name: "LDAPS", port: 636 } tasks: # 检查证书目录 - name: Check certificate directories stat: path: "{{ item }}" register: cert_dirs loop: "{{ cert_paths }}" - name: List existing certificate directories debug: msg: "📁 Certificate directory {{ item.item }}: {{ 'EXISTS' if item.stat.exists else 'NOT FOUND' }}" loop: "{{ cert_dirs.results }}" # 查找证书文件 - name: Find certificate files find: paths: "{{ cert_paths }}" patterns: "*.crt,*.pem,*.cert" recurse: yes register: cert_files - name: Display found certificates debug: msg: "🔐 Found {{ cert_files.files | length }} certificate files" # 检查证书过期时间 - name: Check certificate expiration shell: | if [ -f "{{ item.path }}" ]; then openssl x509 -in "{{ item.path }}" -noout -enddate 2>/dev/null | cut -d= -f2 fi register: cert_expiry loop: "{{ cert_files.files[:10] }}" # 限制检查前10个证书 failed_when: false - name: Display certificate expiration dates debug: msg: "📅 {{ item.item.path | basename }}: expires {{ item.stdout if item.stdout else 'INVALID/UNREADABLE' }}" loop: "{{ cert_expiry.results }}" when: item.stdout != "" # 检查即将过期的证书 (30天内) - name: Check certificates expiring soon shell: | if [ -f "{{ item.path }}" ]; then exp_date=$(openssl x509 -in "{{ item.path }}" -noout -enddate 2>/dev/null | cut -d= -f2) if [ ! -z "$exp_date" ]; then exp_epoch=$(date -d "$exp_date" +%s 2>/dev/null) now_epoch=$(date +%s) days_left=$(( (exp_epoch - now_epoch) / 86400 )) if [ $days_left -lt 30 ]; then echo "WARNING: $days_left days left" else echo "OK: $days_left days left" fi fi fi register: cert_warnings loop: "{{ cert_files.files[:10] }}" failed_when: false - name: Display certificate warnings debug: msg: "⚠️ {{ item.item.path | basename }}: {{ item.stdout }}" loop: "{{ cert_warnings.results }}" when: item.stdout != "" and "WARNING" in item.stdout # 检查 Let's Encrypt 证书 - name: Check Let's Encrypt certificates shell: certbot certificates 2>/dev/null || echo "Certbot not installed" register: letsencrypt_certs failed_when: false - name: Display Let's Encrypt status debug: msg: "🔒 Let's Encrypt: {{ letsencrypt_certs.stdout_lines }}" when: "'not installed' not in letsencrypt_certs.stdout" # 检查 SSL 服务端口 - name: Check SSL service ports wait_for: port: "{{ item.port }}" timeout: 3 register: ssl_ports loop: "{{ ssl_services }}" failed_when: false - name: Display SSL service status debug: msg: "🔌 {{ item.item.name }} (port {{ item.item.port }}): {{ 'LISTENING' if not item.failed else 'NOT AVAILABLE' }}" loop: "{{ ssl_ports.results }}" # 测试 HTTPS 连接 - name: Test HTTPS connection to localhost uri: url: "https://{{ ansible_default_ipv4.address }}" method: GET validate_certs: no timeout: 5 register: https_test failed_when: false when: ssl_ports.results[0] is defined and not ssl_ports.results[0].failed - name: Display HTTPS test result debug: msg: "🌐 HTTPS Test: {{ 'SUCCESS' if https_test.status is defined else 'FAILED' }}" when: https_test is defined # 检查证书链 - name: Check certificate chain for HTTPS shell: | echo | openssl s_client -connect {{ ansible_default_ipv4.address }}:443 -servername {{ ansible_hostname }} 2>/dev/null | openssl x509 -noout -subject -issuer register: cert_chain failed_when: false when: ssl_ports.results[0] is defined and not ssl_ports.results[0].failed - name: Display certificate chain info debug: msg: "🔗 Certificate Chain: {{ cert_chain.stdout_lines }}" when: cert_chain is defined and cert_chain.rc == 0 # 生成证书健康报告 - name: Generate certificate health summary debug: msg: | 🔐 Certificate Health Summary for {{ inventory_hostname }}: 📁 Certificate directories found: {{ (cert_dirs.results | selectattr('stat.exists') | list | length) }} 📄 Certificate files found: {{ cert_files.files | length }} ⚠️ Certificates expiring soon: {{ (cert_warnings.results | selectattr('stdout', 'search', 'WARNING') | list | length) }} 🔒 Let's Encrypt: {{ 'Configured' if 'not installed' not in letsencrypt_certs.stdout else 'Not installed' }} 🌐 SSL Services: {{ (ssl_ports.results | rejectattr('failed') | list | length) }}/{{ ssl_services | length }} available