[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加密使互联网更安全
在网络安全的圈子里,我们都会隔三差五的听到某某公司遭受恶意软件攻击.或大量的隐私信息被泄露等等事件,此类安全事件往往都有影响范围广.涉及用户众多等特点.不免让人质疑联网的世界越来越危险.然而,在安全专 ...
随机推荐
- 全国产!全志A40i+Logos FPGA核心板(4核ARM Cortex-A7)硬件说明
硬件资源 SOM-TLA40iF核心板板载ARM.FPGA.ROM.RAM.晶振.电源.LED等硬件资源,并通过B2B连接方式引出IO.核心板所有器件(包括B2B连接器)均采用国产工业级方案,国产化率 ...
- yb课堂实战之首页banner轮播图和视频详情接口开发 《四》
开发轮播列表接口 VideoMapper.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCT ...
- Tiny RDM 刚上线就收获一众好评的Redis桌面开源客户端!值得拥有!
相信对Redis有频繁操作需求的用户,大部分会选择一个顺手的图形化界面工具来代替手动命令行操作以提高效率.Tiny RDM作为一款现代化轻量级的跨平台Redis桌面客户端,为用户提供了便捷高效的Red ...
- 解决react native打包apk文件安装好之后进入应用闪退的问题
这个是我一个前端前辈帮我弄的,自己解决的时候不行,她去官网找了相关的问题,然后发给我的. react-native android 的release安装包运行闪退,但是debug运行正常 环境:0.6 ...
- 深度学习 玩游戏 Q-LEARNING
游戏里面非玩家的角色行为,即 AI. 腾讯的 Ai 游戏框架:TencentOpen. 介绍: Agent,behavior tree, 大概意思就是 通过自己的框架来确定 ai 行为,然后通过 ag ...
- pycharm中可以运行脚本(只在控制台运行,Debugger不运行,设置的断点没用)但是不能debug脚本
以前用的时候好好地,但是最近上班突然脚本就不能debug了,debug直接报错,如下所示 上网查过该有的原因: 1.在pycharm中两个地方设置成utf-8,页面右下角和File>settin ...
- 很呆的一个问题:我的新项目又找不到mapper这个bean了
1.选springboot版本 <properties> <java.version>8</java.version> <project.build.sour ...
- Known框架实战演练——进销存财务管理
本文介绍如何实现进销存管理系统的财务对账模块,财务对账模块包括供应商对账和客户对账2个菜单页面.供应商和客户对账字段相同,因此可共用一个页面组件类. 项目代码:JxcLite 开源地址: https: ...
- 【Java-GUI】12 Swing07 JList
列表和下拉选择: package cn.dzz; import javax.swing.*; import javax.swing.border.EtchedBorder; import javax. ...
- 【OracleDB】 07 分组查询 & 分组函数
分组函数 分组函数作用于一组数据,并对一组数据返回一个值. Oracle中分组函数的种类: - 求平均值 AVG - 计数记录数 COUNT - 求最大值 MAX - 求最小值 MIN - 求和 SU ...