[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加密使互联网更安全
在网络安全的圈子里,我们都会隔三差五的听到某某公司遭受恶意软件攻击.或大量的隐私信息被泄露等等事件,此类安全事件往往都有影响范围广.涉及用户众多等特点.不免让人质疑联网的世界越来越危险.然而,在安全专 ...
随机推荐
- 基于附带Attention机制的seq2seq模型架构实现英译法的案例
模型架构 先上图 我们这里选用GRU来实现该任务,因此上图的十个方框框都是GRU块,如第二张图,放第一张图主要是强调编码器的输出是作用在解码器每一次输入的观点,具体的详细流程图将在代码实现部分给出. ...
- 基于RK3588的8K视频解码显示案例分享!引领超高清工业视频时代
8K.4K.2K显示对比 2K分辨率:也称为全高清(FULL HD),它具有1920 x 1080像素的分辨率.这是目前大多数消费者电视和电脑显示器的标准分辨率,可以提供良好的图像质量. 4K分辨率: ...
- 【ClickHouse】6:clickhouse集群高可用
背景介绍: 有四台CentOS7服务器安装了ClickHouse HostName IP 安装程序 程序端口 shard(分片) replica(备份) centf8118.sharding1.db ...
- Java 代码实现POST/GET请求
方式一 package com.cyb.util; import java.io.BufferedReader; import java.io.DataOutputStream; import jav ...
- SurveillanceStation破解版 SurveillanceStation-x86_64-8.2.2-5766
直接手动安装好套件,许可就是65535.安装的时候提示套件损坏,不理继续安装.不过这个版本有时间炸弹问题,使用几个小时后会出现摄像机消失问题,显示摄像机被删除,但是配置其实是在的.只要禁用套件再启用一 ...
- LabVIEW图标编辑器中的文本变得模糊
问题详述 在LabVIEW图标编辑器中将文本添加到VI图标时,如果我将字体大小设置为小于10,文本会变得模糊.当字体大小设置为大于11时,文本会正常地显示,但是字体则变得太大而无法放入图标中. 真难看 ...
- move语义和完美转发
move语义 值类别(value category)如下: lvalue:左值,在内存中有地址,可被程序员访问,可以放在赋值运算符左侧,也可以放在赋值运算符右侧,常见的左值有普通变量.字符串字面值&q ...
- API引用在Element UI (Vue 2)和Element Plus (Vue 3)中的不同
API 变动 样式类名变化: 一些组件的样式类名有所变动,可能需要更新你的自定义样式. 事件名和属性名变化: 某些组件的事件名和属性名发生了变化,需要检查 Element Plus 文档 以了解详细信 ...
- 一文全解:LVM(逻辑卷管理器)
前两篇文章已经讲了关于磁盘分区和磁盘阵列的相关内容: 一文全懂:Linux磁盘分区 一文全懂:独立冗余磁盘阵列(RAID) 但是磁盘分区完后再想扩容或者缩容就比较麻烦了,甚至很多时候不能扩容或者缩容, ...
- Linux 文本文件编辑相关命令简介【Linux 常用命令系列二】
〇.前言 本文介绍了如何通过 vim 命令,对文本文件进行打开.编辑.保存等相关操作,并通过简单的示例演示了常用用法. 一.关于文本文件的操作 1.1 打开,查看(cat).编辑(vim) 打开文本文 ...