[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加密使互联网更安全
在网络安全的圈子里,我们都会隔三差五的听到某某公司遭受恶意软件攻击.或大量的隐私信息被泄露等等事件,此类安全事件往往都有影响范围广.涉及用户众多等特点.不免让人质疑联网的世界越来越危险.然而,在安全专 ...
随机推荐
- Vue Element-UI 按需引入提示Cannot find module 'babel-preset-es2015'
1.我的开发环境和操作步骤 1.1.使用VUE-CLI创建 2.x 脚手架 1.2.安装 npm i element-ui(参照官网) 1.3.安装 npm install babel-plugin ...
- vol2以及mimikatz插件安装教程
volatility2安装 https://github.com/volatilityfoundation/volatility git clone https://github.com/volati ...
- SpringBoot 启动时报错Unable to start embedded Tomcat
导读 最近公司有个gradle构建的工程,需要改造成maven方式构建(点我直达).转为maven后,启动时一直报tomcat错误,最终排查是因为servlet-api这个包导致的依赖冲突,将这个依赖 ...
- Mac Docker设置国内镜像加速器
安装docker 点我直达 设置国内加速镜像 { "experimental": false, "features": { "buildkit&quo ...
- MyBatis-Plus 整理
# 前言 代码生成器插件选择去这里:https://www.cnblogs.com/zixq/p/16726534.html 相关插件在那里面已经提到了 # 上手 MyBatis-Plus 是一个 M ...
- 全网最适合入门的面向对象编程教程:02 类和对象的Python实现-使用Python创建类
全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类 摘要 本文主要介绍了串口通信协议的基本概念.串口通信的基本流程.如何使用 Python 语言创建一个 ...
- django如何将查询结果的栏位和数值自动遍历出来
在Django中,MT003HModel.objects.all() 返回的是一个 QuerySet 对象,你可以使用迭代器来遍历其中的每个对象,然后访问对象的属性来获取栏位和数值. 以下是一个简单的 ...
- JavaScript 常用 Web APIs
Web APIs Web APIs DOM 页面文档对象模型 DOM 树 获取元素 事件 监听事件 事件解绑 操作元素 样式属性操作 结点操作 结点关系 创建节点 DOM 事件流 事件对象 常用鼠标事 ...
- 【Java】Applet开发
一.Applet开发环境准备 IDEA在2018版本默认提供了Applet启动配置 创建一个Applet应用配置: 在IDEA2019版本之后,这个应用配置选项被移除了,改为Java Applet S ...
- 【Vue2】Axios、Async+Await、解构赋值
Axios入门使用,Async和Await用法,解构赋值语法 <!DOCTYPE html> <html lang="en"> <head> & ...