shell脚本监控ssl证书到期时间

news/2025/10/10 16:23:44/文章来源:https://www.cnblogs.com/chuanghongmeng/p/19133320

一、需求

说明:

  (1)读取域名列表文件。

  (2)获取域名到期时间,进行告警后邮件提醒。

#!/bin/bash
## 第1步  配置文件
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# 告警阈值(天)
WARNING_DAYS=20
CRITICAL_DAYS=10
ALERT_DAYS=10
# 超时设置(秒)
CONNECT_TIMEOUT=5
# 邮件配置
EMAIL_ENABLED=false
EMAIL_TO="xxxxxxx@qq.com"     # 目标邮箱地址
EMAIL_COMMAND="mailx"             # 邮件发送命令
EMAIL_SUBJECT_PREFIX="SSL证书检查报告" # 邮件主题前缀
# 全局变量
ALERT_DOMAINS=()  # 存储需要告警的域名
ALL_CERTIFICATES=()  # 存储所有证书检查结果
DOMAIN_LIST_FILE="domains.txt"# 日志函数
log() {local level=$1local message=$2local timestamp=$(date '+%Y-%m-%d %H:%M:%S')echo -e "[$timestamp] [$level] $message"
}
## 第4步 
# 显示使用帮助
show_usage() {echo -e "${GREEN}SSL证书到期监控脚本${NC}"echo "使用方法: $0 [选项]"echo ""echo "选项:"echo "  -f, --file <文件>    从文件读取域名列表 (默认: $DOMAIN_LIST_FILE)"echo "  -d, --detailed       显示详细证书信息"echo "  -q, --quick          快速检查模式(默认)"echo "  -t, --timeout <秒>   设置连接超时时间(默认: ${CONNECT_TIMEOUT}秒)"echo "  -m, --mail           启用邮件发送功能"echo "  -h, --help           显示此帮助信息"echo ""echo "示例:"echo "  $0 -f domains.txt        # 从文件检查"echo "  $0 -f domains.txt -d     # 详细模式检查"echo "  $0 -f domains.txt -m     # 检查并发送邮件"echo ""echo "域名列表文件格式:"echo "  # 注释行"echo "  example.com"echo "  google.com"echo "  mysite.com:8443"
}
## 第9步 
# 带超时的SSL连接检查
ssl_connect_with_timeout() {local domain=$1local port=$2# 使用timeout命令设置超时if command -v timeout >/dev/null 2>&1; then# 如果有timeout命令timeout $CONNECT_TIMEOUT bash -c "echo | openssl s_client -connect \"$domain:$port\" -servername \"$domain\" 2>/dev/null" 2>/dev/nullelse# 如果没有timeout命令,使用其他方法实现超时local pid# local result# 在后台执行openssl命令(echo | openssl s_client -connect "$domain:$port" -servername "$domain" 2>/dev/null) &pid=$!# 等待进程结束,最多等待CONNECT_TIMEOUT秒local count=0while [ $count -lt $CONNECT_TIMEOUT ]; doif ! kill -0 $pid 2>/dev/null; then# 进程已经结束breakfisleep 1count=$((count + 1))done# 如果进程还在运行,杀死它if kill -0 $pid 2>/dev/null; thenkill $pid 2>/dev/nullwait $pid 2>/dev/nullreturn 124  # 超时返回码else# 获取命令执行结果wait $pidreturn $?fifi
}## 第8步 
# 获取SSL证书剩余天数
get_ssl_days_remaining() {local domain=$1local port=${2:-443}# 获取证书到期时间(带超时)local not_afternot_after=$(ssl_connect_with_timeout "$domain" "$port" | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)local ssl_result=$?if [ $ssl_result -eq 124 ]; thenecho "TIMEOUT"return 1elif [ $ssl_result -ne 0 ] || [ -z "$not_after" ]; thenecho "ERROR"return 1fi# 转换为时间戳local expiry_timestampexpiry_timestamp=$(date -d "$not_after" +%s 2>/dev/null)if [ $? -ne 0 ]; thenecho "ERROR"return 1filocal current_timestamp=$(date +%s)local days_remaining=$(( (expiry_timestamp - current_timestamp) / 86400 ))echo "$days_remaining"
}## 第7步 
# 快速检查模式(只检查剩余天数)
quick_check_domain() {local domain=$1local port=${2:-443}local days_remaining=$(get_ssl_days_remaining "$domain" "$port")if [ "$days_remaining" == "TIMEOUT" ]; thenecho -e "${RED}⏰ $domain: 连接超时 (${CONNECT_TIMEOUT}秒)${NC}"ALERT_DOMAINS+=("${RED}⏰ $domain: 连接超时${NC}")ALL_CERTIFICATES+=("${RED}⏰ $domain: 连接超时${NC}")elif [ "$days_remaining" == "ERROR" ]; thenecho -e "${RED}❌ $domain: 检查失败${NC}"ALERT_DOMAINS+=("${RED}❌ $domain: 检查失败${NC}")ALL_CERTIFICATES+=("${RED}❌ $domain: 检查失败${NC}")elif [ "$days_remaining" -lt 0 ]; thenecho -e "${RED}🔴 $domain: 已过期 $(( -days_remaining )) 天!${NC}"ALERT_DOMAINS+=("${RED}🔴 $domain: 已过期 $(( -days_remaining )) 天${NC}")ALL_CERTIFICATES+=("${RED}🔴 $domain: 已过期 $(( -days_remaining )) 天${NC}")elif [ "$days_remaining" -le "$ALERT_DAYS" ]; thenecho -e "${RED}🔴 $domain: 剩余 $days_remaining 天 (需处理)${NC}"ALERT_DOMAINS+=("${RED}🔴 $domain: 剩余 $days_remaining 天${NC}")ALL_CERTIFICATES+=("${RED}🔴 $domain: 剩余 $days_remaining 天${NC}")elif [ "$days_remaining" -le "$WARNING_DAYS" ]; thenecho -e "${YELLOW}🟡 $domain: 剩余 $days_remaining 天${NC}"ALL_CERTIFICATES+=("${YELLOW}🟡 $domain: 剩余 $days_remaining 天${NC}")elseecho -e "${GREEN}✅ $domain: 剩余 $days_remaining 天${NC}"ALL_CERTIFICATES+=("${GREEN}✅ $domain: 剩余 $days_remaining 天${NC}")fi
}## 第6步 
# 从文件读取域名列表
read_domains_from_file() {local file_path=$1local domains=()if [ ! -f "$file_path" ]; thenecho -e "${RED}错误: 域名列表文件 $file_path 不存在${NC}" >&2return 1fiwhile IFS= read -r line || [ -n "$line" ]; do# 跳过空行和注释行line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')[[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continuedomains+=("$line")done < "$file_path"printf '%s\n' "${domains[@]}"
}## 第5步 
# 批量检查域名
check_multiple_domains() {local mode=$1local file_path=$2local domains=()# 从文件读取域名if [ -n "$file_path" ] && [ -f "$file_path" ]; thenmapfile -t domains < <(read_domains_from_file "$file_path")if [ $? -ne 0 ]; thenecho -e "${RED}错误: 无法读取域名列表文件${NC}"return 1fielseecho -e "${RED}错误: 域名列表文件不存在${NC}"return 1fiecho -e "${BLUE}开始检查 ${#domains[@]} 个域名的SSL证书...${NC}"echo "告警阈值: ${ALERT_DAYS}天"echo "超时设置: ${CONNECT_TIMEOUT}秒"echo "模式: $mode"echo "=========================================="for domain_entry in "${domains[@]}"; do# 支持 domain:port 格式if [[ "$domain_entry" == *":"* ]]; thendomain="${domain_entry%:*}"port="${domain_entry#*:}"elsedomain="$domain_entry"port="443"fi# 清理域名domain=$(echo "$domain" | sed -e 's|^https://||' -e 's|^http://||' -e 's|/.*$||')case "$mode" in"detailed")get_ssl_cert_info "$domain" "$port" "$days_remaining";;"quick"|*)quick_check_domain "$domain" "$port";;esacdone
}## 第10步 
# 显示告警汇总
show_alerts() {if [ ${#ALERT_DOMAINS[@]} -eq 0 ]; thenecho -e "\n${GREEN}🎉 所有证书状态正常,无需处理!${NC}"returnfiecho -e "\n${RED}🚨 证书告警汇总 (剩余 ≤ ${ALERT_DAYS} 天/连接问题):${NC}"echo "=========================================="local has_critical_alerts=0for alert in "${ALERT_DOMAINS[@]}"; doif [[ "$alert" == *"剩余 $ALERT_DAYS"* ]] || [[ "$alert" == *"已过期"* ]] || [[ "$alert" == *"检查失败"* ]] || [[ "$alert" == *"连接超时"* ]]; thenecho -e "$alert"has_critical_alerts=1fidoneif [ $has_critical_alerts -eq 0 ]; thenecho -e "${GREEN}暂无紧急告警${NC}"fiecho "=========================================="
}## 第11步 
# 检查是否有需要告警的证书
has_alert_certificates() {for alert in "${ALERT_DOMAINS[@]}"; doreturn 0donereturn 1  # 没有需要告警的证书
}## 第13步
# 生成邮件内容
generate_email_content() {local email_content=""email_content+="SSL证书检查报告\n检查时间: $(date)\n\n"# 显示所有证书状态if [ ${#ALL_CERTIFICATES[@]} -gt 0 ]; thenemail_content+="📋 所有证书检查结果:\n"email_content+="==========================================\n"for cert in "${ALL_CERTIFICATES[@]}"; doemail_content+="$cert\n"doneemail_content+="==========================================\n\n"fi# 显示告警证书email_content+="🚨 证书告警汇总 (剩余 ≤ ${ALERT_DAYS} 天/连接问题)"    if [ ${#ALERT_DOMAINS[@]} -eq 0 ]; thenemail_content+="\n${GREEN}🎉 所有证书状态正常,无需处理!${NC}"elif [ ${#ALERT_DOMAINS[@]} -gt 0 ]; thenemail_content+="\n==========================================\n"local has_critical_alerts=0for alert in "${ALERT_DOMAINS[@]}"; doemail_content+="$alert\n" has_critical_alerts=1donefi  echo -e "$email_content"
}## 第12步
# 发送邮件
send_email() {local subject="${EMAIL_SUBJECT_PREFIX} - $(date '+%Y-%m-%d %H:%M')"local contentcontent=$(generate_email_content)#echo "$content"echo "--------------------------------------------------1111---------------------------------------------------- "echo "$content"echo "--------------------------------------------------1111---------------------------------------------------- "# 检查是否启用邮件发送if [ "$EMAIL_ENABLED" != "true" ]; thenecho -e "${YELLOW}邮件发送未启用${NC}"return 0fi# 检查邮件命令是否存在if ! command -v "$EMAIL_COMMAND" >/dev/null 2>&1; thenecho -e "${RED}错误: 邮件命令 '$EMAIL_COMMAND' 不存在${NC}"return 1fi# 发送邮件echo -e "$content" | sed 's/\x1b\[[0-9;]*m//g' | $EMAIL_COMMAND -s "$subject" "$EMAIL_TO"local mail_result=$?if [ $mail_result -eq 0 ]; thenecho -e "${GREEN}邮件发送成功${NC}"return 0elseecho -e "${RED}邮件发送失败 (返回码: $mail_result)${NC}"return 1fi
}## 第3步 
# 主函数
main() {local mode="quick"local file_path=""# 处理命令行参数while [[ $# -gt 0 ]]; docase $1 in-f|--file)if [ -n "$2" ]; thenfile_path="$2"shift 2elseecho -e "${RED}错误: --file 需要参数${NC}"show_usageexit 1fi;;-q|--quick)mode="quick"shift;;-t|--timeout)if [ -n "$2" ] && [[ "$2" =~ ^[0-9]+$ ]]; thenCONNECT_TIMEOUT="$2"shift 2elseecho -e "${RED}错误: --timeout 需要数字参数${NC}"show_usageexit 1fi;;-m|--mail)EMAIL_ENABLED=trueshift;;-h|--help)show_usageexit 0;;-*)echo -e "${RED}错误: 未知选项 $1${NC}"show_usageexit 1;;*)echo -e "${RED}错误: 不支持的参数 $1${NC}"show_usageexit 1;;esacdone# 如果没有指定文件,使用默认文件if [ -z "$file_path" ]; thenif [ -f "$DOMAIN_LIST_FILE" ]; thenfile_path="$DOMAIN_LIST_FILE"elseecho -e "${RED}错误: 未指定域名文件且默认文件 $DOMAIN_LIST_FILE 不存在${NC}"show_usageexit 1fifi# 执行检查check_multiple_domains "$mode" "$file_path"# 显示告警汇总show_alerts# 发送邮件(如果启用且有需要告警的证书)if [ "$EMAIL_ENABLED" == "true" ]; thenif has_alert_certificates; thenecho -e "\n${BLUE}检测到需要告警的证书,正在发送邮件...${NC}"send_emailelseecho -e "\n${GREEN}无需要告警的证书,无需发送邮件${NC}"fifi}## 第2步 
# 执行主函数
main "$@"

然后执行命令

./ssl_alert.sh -f domains.txt -m

在crontab中添加定时任务,进行定期执行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/934223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI如何通过卫星图像识别刺猬栖息地

剑桥大学研究人员利用卫星图像和机器学习技术,通过识别黑莓灌木丛来绘制刺猬潜在栖息地地图,为保护这种濒危物种提供创新解决方案。AI如何通过卫星图像识别刺猬栖息地 你不能从太空中直接发现刺猬,但通过寻找黑莓灌…

04-补充mybatis-plus的Service接口

04-补充mybatis-plus的Service接口$(".postTitle2").removeClass("postTitle2").addClass("singleposttitle");常用方法查询相关方法以前是我们自己实现的Service接口和方法先在mp给我们…

LeetCode热题100-75、跳跃游戏

LeetCode热题100-75、跳跃游戏给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回…

rust 模块和引用

rust的模块声明有两种方式: 1、mod.rs文件方式 在 2018 年后的版本中已逐渐被新的模块系统取代,Rust 官方文档中已删除对 mod.rs 的介绍,主要因为该功能在 Rust 1.30 版本后被新的模块命名约定替代。 目录结构为: …

moectf2025-reverse-wp

moectf2025-reverse-wp upx 壳是什么?upx是什么?upx可以用来干什么?用自己的upx脱壳 upx -d +文件地址然后就去ida里面编译但是找不到main函数 我们直接shift+F12查看字符串然后点进去鼠标移到这里 按X 然后定位到主…

国标GB28181网页直播平台EasyGBS如何构建智慧社区一体化视频监控方案?

国标GB28181网页直播平台EasyGBS如何构建智慧社区一体化视频监控方案?随着科技的飞速发展,智慧社区的概念逐渐深入人心。智慧社区旨在通过先进的信息技术手段,实现社区的智能化管理和服务,提升居民的生活质量和社区…

完整教程:【论文阅读】纯视觉语言动作(VLA)模型:全面综述

完整教程:【论文阅读】纯视觉语言动作(VLA)模型:全面综述2025-10-10 16:09 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !importan…

TypeScript Declaration Merging(声明合并)使用说明

最近在进行前端开发的时候,为了拓展引用,使用了TS声明合并的特性,完整的了解了一下该特性,特此记录成笔记。 声明合并指在TypeScript里面,编译器将两个或者多个独立的相同名称的声明合并到一起。合并后的定义同时…

第七章 手写数字识别V5

# 优化: # 新建Model类,将神经网络的结构定义、训练流程(前向/后向)和预测逻辑统一封装起来 # 何将权重更新的职责从网络层(Linear)中分离出来,交给优化器(SGD)来完成 # 使用动量梯度下降优化算法(MSGD) # …

关于根据距离列表排序sql

关于根据距离列表排序sql//第一种 根据经纬度排序 $map = "1=1 ";if ($loadCode && $unloadCode) {$map .= " AND load_city_id = $loadCode and unload_city_id = $unloadCode";}…

2025年高适配铝型材厂家推荐:深圳市方达铝业领衔,3家企业覆盖多场景

随着科技的进步与工业的发展,铝型材作为一种轻质、高强度且耐腐蚀的材料,广泛应用于 3C 数码、智能家居、工业设备等多个领域。然而,市场上铝型材厂家众多,产品质量与服务水平参差不齐,给消费者的选择带来了困扰。…

注册c模块到lua中使用

#define REGISTER_CUSTOM_LIBRARY(name, lua_c_fn) \ int lua_c_fn(lua_State*); \ luaL_requiref(L, name, lua_c_fn, 0); \ lua_pop(L, 1) /* remove lib */ //注册c模块void open_custom_libs(lua_State* …

S3Bucket安全评分与合规状态逻辑修复:全面提升云存储安全评估准确性 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

DNA权威书籍

《基因XII》- 本杰明卢因分子生物学“圣经”。 这是全球最经典、最权威的分子生物学教材,每隔几年就会更新一版。内容极其全面、系统,从DNA结构、复制、转录、翻译到基因调控、基因组学、新技术都有详尽的阐述。插图…

220V转5V500mA非隔离电源芯片WT5105

220V转5V500mA非隔离电源芯片WT5105 WT5105 是一款集成非隔离式电源控制器,可将 220V 电压转换为 5V、500mA 的稳定输出,为低功率设备提供稳定、高效的供电解决方案。以下是其相关介绍:核心参数:输出电压为 5V,输…

linux基础-find查找

linux基础-find查找 1.认识 实时查找工具,通过便利指定路径完成文件的查找工作特点:(1)精确查找(2)实时查找(3)查找速度慢(4)可能之搜索用户具备读取和执行权限的目录语法 :   find [OPTION]... [查找路径…

220V转12V电机水泵供电驱动WT5105

220V转12V电机水泵供电驱动WT5105 WT5105是一款AC-DC开关电源驱动芯片,适用于220V转12V的电机水泵应用。以下是详细介绍:基本参数输入电压:85V~265V AC(覆盖220V市电)输出电压:可调,支持12V输出输出功率:5V-15…

ansys安装时无法修改安装路径--灰色无法修改

ansys安装时无法修改安装路径,是因为有ansys程序运行、曾经安装没有卸载干净 1、卸载 2、清除注册表(工具) 3、参考官方方法 Uninstalling the Ansys license manager – Ansys Optics以下是官网卸载方法 Uninstall…

Qwen2.5-VL技术报告

原文:https://mp.weixin.qq.com/s/IbfY50w_w27WO3ZzRSsyDg 全文摘要Qwen2.5-VL模型在视觉语言系列中具有显著的基础能力和创新功能上的提升。通过增强的视觉识别、精确的对象定位、稳健的文档解析和长视频理解等能力,…