[golang]查询ssl证书剩余有效天数并邮件提醒
前言
自从云厂商的免费ssl证书改成3个月,而且证书数量还是20个之后,自己网站的ssl证书就换成了其它免费方案。但是免费方案不会提醒证书过期,所以写个工具每天定时查询证书剩余有效天数,如果证书即将过期,就发送邮件提醒。
基本实现
最基本的代码功能就是检测网站ssl证书的有效天数,可以用命令行传参的方式指定网站域名。
package main
import (
"crypto/tls"
"flag"
"fmt"
"net"
"os"
"sync"
"time"
)
var (
port int
wg sync.WaitGroup
)
func checkssl(domain string, port int) {
defer wg.Done()
host := fmt.Sprintf("%s:%d", domain, port)
conn, err := tls.DialWithDialer(&net.Dialer{
Timeout: time.Second * 5,
Deadline: time.Now().Add(time.Second * 5),
}, "tcp", host, &tls.Config{InsecureSkipVerify: true})
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
stats := conn.ConnectionState()
certs := stats.PeerCertificates[0]
localtz, _ := time.LoadLocation("Asia/Shanghai")
issueTime := certs.NotBefore.In(localtz)
expireTime := certs.NotAfter.In(localtz)
today := time.Now().In(localtz)
dayLeft := int(expireTime.Sub(today).Hours() / 24)
fmt.Printf("%s, issue time: %v, expire time: %v, days left: %v\n", domain, issueTime, expireTime, dayLeft)
}
func main() {
flag.IntVar(&port, "p", 443, "port, example: ./checkssl -p 1443 <domain name>")
flag.Parse()
positionArgs := flag.Args()
if len(positionArgs) == 0 {
fmt.Println("Error: Missing domain name")
fmt.Println("Usage: ./checkssl <domain name>")
os.Exit(1)
}
wg.Add(len(positionArgs))
for _, arg := range positionArgs {
go checkssl(arg, port)
}
wg.Wait()
}
使用示例
# 1. 编译
go build
# 2. 命令行传参的方式指定域名
./check-ssl baidu.com ithome.com qq.com
# 输出
baidu.com, issue time: 2024-01-30 08:00:00 +0800 CST, expire time: 2025-03-02 07:59:59 +0800 CST, days left: 187
ithome.com, issue time: 2024-01-22 08:00:00 +0800 CST, expire time: 2025-02-22 07:59:59 +0800 CST, days left: 179
qq.com, issue time: 2024-06-04 08:00:00 +0800 CST, expire time: 2025-06-11 07:59:59 +0800 CST, days left: 288
完善功能
需要完善的功能主要是发送邮件,这里使用SMTP协议来发送邮件。如果跟我一样用的是163邮箱,则需要先去获取一个SMTP的授权码。
因为需要配置SMTP的连接信息,所以改成了用文件来传入配置,也方便后期修改。配置文件config.yaml
示例:
domains:
- baidu.com
- qq.com
email:
smtp:
host: "smtp.163.com" # smtp服务器的地址
port: 465 # 因为云服务器屏蔽了25端口, 只能使用tls加密的465端口
from: "" # 发送方邮箱
token: "" # 授权码
sendto:
- "qq@qq.com" # 接收方的邮箱地址
expire: 7 # 证书剩余有效天数, 小于7天时发送邮件提醒
读取配置的代码文件config.go
,使用viper
来读取配置文件。
package main
import "github.com/spf13/viper"
var (
v *viper.Viper
)
type SMTPServer struct {
Host string
Port int
Token string
From string
}
func initViper() {
v = viper.New()
v.AddConfigPath(".")
v.SetConfigType("yaml")
v.SetConfigFile(configfile)
err := v.ReadInConfig()
if err != nil {
panic(err)
}
}
type configer struct{}
func NewConfiger() configer {
if v == nil {
initViper()
}
return configer{}
}
func (c configer) GetSMTPServer() SMTPServer {
return SMTPServer{
Host: v.GetString("email.smtp.host"),
Port: v.GetInt("email.smtp.port"),
Token: v.GetString("email.smtp.token"),
From: v.GetString("email.smtp.from"),
}
}
func (c configer) GetDomains() []string {
return v.GetStringSlice("domains")
}
func (c configer) GetSendTos() []string {
return v.GetStringSlice("email.sendto")
}
func (c configer) GetExpiry() int {
return v.GetInt("email.expire")
}
发送邮件的相关代码文件:notify.go
package main
import (
"crypto/tls"
"fmt"
"net/smtp"
"github.com/jordan-wright/email"
)
type Postman struct {
SmtpServer SMTPServer
SendTos []string
}
func (p Postman) SendEmail(domain string, dayleft int) {
auth := smtp.PlainAuth("", p.SmtpServer.From, p.SmtpServer.Token, p.SmtpServer.Host)
e := &email.Email{
To: p.SendTos,
From: fmt.Sprintf("YXHYW <%s>", p.SmtpServer.From),
Subject: fmt.Sprintf("域名 %s SSL证书过期提醒", domain),
Text: []byte(fmt.Sprintf("域名 %s 的SSL证书即将过期, 剩余有效期 %d 天", domain, dayleft)),
}
// err := e.Send(fmt.Sprintf("%s:%d", p.SmtpServer.Host, p.SmtpServer.Port), auth)
addr := fmt.Sprintf("%s:%d", p.SmtpServer.Host, p.SmtpServer.Port)
fmt.Println("SMTP Server addr: ", addr)
err := e.SendWithTLS(addr, auth, &tls.Config{
InsecureSkipVerify: false,
ServerName: p.SmtpServer.Host,
})
if err != nil {
fmt.Printf("Send email failed, %v\n", err)
}
}
主体代码文件main.go
,主要修改地方:检测到证书即将过期后,调用发送邮件的相关方法。
package main
import (
"crypto/tls"
"flag"
"fmt"
"net"
"sync"
"time"
)
var (
port int
configfile string
wg sync.WaitGroup
c configer = NewConfiger()
)
func checkssl(domain string, port int) {
defer wg.Done()
host := fmt.Sprintf("%s:%d", domain, port)
conn, err := tls.DialWithDialer(&net.Dialer{
Timeout: time.Second * 5,
Deadline: time.Now().Add(time.Second * 5),
}, "tcp", host, &tls.Config{InsecureSkipVerify: true})
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
stats := conn.ConnectionState()
certs := stats.PeerCertificates[0]
localtz, _ := time.LoadLocation("Asia/Shanghai")
issueTime := certs.NotBefore.In(localtz)
expireTime := certs.NotAfter.In(localtz)
today := time.Now().In(localtz)
dayLeft := int(expireTime.Sub(today).Hours() / 24)
fmt.Printf("%s, issue time: %v, expire time: %v, days left: %v\n", domain, issueTime, expireTime, dayLeft)
// c := NewConfiger()
if dayLeft < c.GetExpiry() {
p := Postman{SmtpServer: c.GetSMTPServer(), SendTos: c.GetSendTos()}
p.SendEmail(domain, dayLeft)
}
}
func main() {
flag.IntVar(&port, "p", 443, "port, example: ./check-ssl -p 1443 <domain name>")
flag.StringVar(&configfile, "c", "config.yaml", "config file")
flag.Parse()
conf := NewConfiger()
domains := conf.GetDomains()
wg.Add(len(domains))
for _, arg := range domains {
go checkssl(arg, port)
}
wg.Wait()
}
本地测试通过后,可以配到服务器的crontab
中每天执行。
[golang]查询ssl证书剩余有效天数并邮件提醒的更多相关文章
- SSL证书/TLS证书是什么
https://blog.csdn.net/donghaixiaolongwang/article/details/79193695 A. SSL协议与TLS是什么?它们的功能是什么? 答:SSL(S ...
- 检查阿里云ssl证书到期情况
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2019-06-10 16:00 # @Author : Anthony.long # ...
- 为你的Android App实现自签名的 SSL 证书(转)
介绍 网络安全已成为大家最关心的问题. 如果你利用服务器存储客户资料, 那你应该考虑使用 SSL 加密客户跟服务器之间的通讯. 随着这几年手机应用迅速崛起. 黑客也开始向手机应用转移, 原因有下列3点 ...
- StartCom 申请 SSL 证书及 Nginx HTTPS 支持配置全攻略
来源:https://www.williamyao.com/index.php/archives/1397/ 前言 最近收到 StartCom 的邮件,数字证书即将过期,想到去年在 StartSSL ...
- 微信小程序免费SSL证书https、TLS版本问题的解决方案
微信小程序与第三方服务器通讯的域名5个必要条件1.一个已备案的域名,不是localhost.也不是127.0.0.1,域名不能加端口2.加ssl证书,也就是https://~~~4.HTTPS 服务器 ...
- Let’s encrypt 计划为网站提供免费的基本 SSL 证书,以加速互联网从 HTTP 向 HTTPS 过渡。
Let’s encrypt 计划为网站提供免费的基本 SSL 证书,以加速互联网从 HTTP 向 HTTPS 过渡. 该项目由Mozilla.Cisco.Akamai.IdenTrust.EFF 和密 ...
- 购买SSL证书到部署网站遇到的若干问题
作为一个菜鸟,对于SSL证书,我了解不多,只知道用了它网站更安全,所以这次使用SSL证书途中遇到了各方面的各种问题,到今天为止终于全部解决. 一.证书格式 前两天在那什么云上面买了个SSL证书,是Wo ...
- openSSL命令、PKI、CA、SSL证书原理
相关学习资料 http://baike.baidu.com/view/7615.htm?fr=aladdin http://www.ibm.com/developerworks/cn/security ...
- linux nginx 配置ssl证书访问
http://www.linuxidc.com/Linux/2013-08/88271.htm 一.什么是 SSL 证书,什么是 HTTPSSSL 证书是一种数字证书,它使用 Secure Socke ...
- SSL证书:Web加密使互联网更安全
在网络安全的圈子里,我们都会隔三差五的听到某某公司遭受恶意软件攻击.或大量的隐私信息被泄露等等事件,此类安全事件往往都有影响范围广.涉及用户众多等特点.不免让人质疑联网的世界越来越危险.然而,在安全专 ...
随机推荐
- 嵌入式必读!瑞芯微RK3568J/RK3568B2开发板规格书
评估板简介 创龙科技TL3568-EVM是一款基于瑞芯微RK3568J/RK3568B2处理器设计的四核ARM Cortex-A55国产工业评估板,每核主频高达1.8GHz/2.0GHz,由核心板和评 ...
- .NET 6 Entity Framework Core Db First(2) 增删改查
基础代码 在Program.cs注入DemoContext 新建HomeController,继承ControllerBase 添加Controller特性,[ApiController] [Rout ...
- 常用 Java 组件和框架分类
WEB 容器 Tomcat https://tomcat.apache.org/ Jetty https://www.jetty.com/ JBoss https://www.jboss.org/ R ...
- Java反射机制原理详解
什么是反射? Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法.本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息 ...
- Java 中的泛型 集合(List,Set) Map
泛型 集合(List,Set) Map 泛型 泛型的本质是参数化类型,即允许在编译时对集合进行类型检查,从而避免安全问题,提高代码的复用性 泛型的具体定义与作用 定义:泛型是一种在编译阶段进行类型检查 ...
- P1546
[USACO3.1]最短网络 Agri-Net 题意描述 FJ 已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场.为了用最小的消费,他想铺设最短的光纤去连接所有的农场. 你将得到一 ...
- 2 - 【RocketMQ 系列】CentOS 7.6 安装部署RocketMQ
二.开始安装部署RocketMQ 官方网站:https://rocketmq.apache.org/ 各版本要求: 1.版本选取 下载地址: https://github.com/apache/roc ...
- 也说一说IDEA热部署Web项目最终解决方案,确实大大提高工作效率
热部署就是正在运行状态的应用,修改了它的源码之后,在不重新启动的情况下能够自动把增量内容编译并部署到服务器上,使得修改立即生效.热部署为了解决的问题有两个: 1.在开发的时候,修改代码后不需要重启应用 ...
- 修改PE文件来实现管理员权限
在Windows我们常用的方法就是给应用添加app.manifest清单文件,然后生成的Exe就会具有管理员权限. 近期我在使用Wix制作Exe安装包时,发现此方法不通,我在github上和Stack ...
- [SDR] GNU Radio 系列教程 —— GNU Radio TX PDU (发送数据包操作)的基础知识(超全)
目录 1 PDU 概述 2 Demo 详解 2.1 Random PDU Generator 2.2 Async CRC32 2.3 Protocol Formatter (Async) 2.4 将 ...