firest
This commit is contained in:
parent
e1fd7b890a
commit
ac6f3243ab
26 changed files with 1938 additions and 1 deletions
377
scripts/tlsupdatev1/main.go
Normal file
377
scripts/tlsupdatev1/main.go
Normal file
|
@ -0,0 +1,377 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
|
||||
elb "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3"
|
||||
elbModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/model"
|
||||
elbRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/region"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
cfgFile string
|
||||
action string
|
||||
region string
|
||||
id string
|
||||
msg string
|
||||
notice bool = false
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "tlsupdate",
|
||||
Short: "check and update tls",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// 如果配置文件存在,则读取配置文件
|
||||
if cfgFile != "" {
|
||||
viper.SetConfigFile(cfgFile)
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
fmt.Println("Error reading config file:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
ak := viper.GetString("huawei.ak")
|
||||
sk := viper.GetString("huawei.sk")
|
||||
notify := viper.GetString("notify")
|
||||
webhook := viper.GetString("webhook")
|
||||
tlsConfig := viper.Get("tls").([]interface{})
|
||||
|
||||
// 获取证书id列表
|
||||
var ids []string
|
||||
for _, tls := range tlsConfig {
|
||||
tlsConfigMap := tls.(map[string]interface{})
|
||||
ids = append(ids, tlsConfigMap["id"].(string))
|
||||
}
|
||||
|
||||
// 如果配置文件中提供飞书链接,则通知用户
|
||||
if notify != "" {
|
||||
// 是否通知
|
||||
notice = true
|
||||
}
|
||||
//发送用户格式,默认是text文本
|
||||
post := false
|
||||
// 富文本中的链接
|
||||
postUrl := ""
|
||||
|
||||
// 遍历配置中tls列表,如果id匹配,即更新或查看证书状态
|
||||
for _, t := range tlsConfig {
|
||||
tlsConfigmap := t.(map[string]interface{})
|
||||
if id == "" {
|
||||
// id为空不能更新,不支持批量更新所有证书
|
||||
if action == "update" {
|
||||
msg = "请求出错,只能指定id更新tls"
|
||||
os.Exit(1)
|
||||
}
|
||||
// id为空,即获取所有证书的有效期
|
||||
if action == "status" {
|
||||
for _, i := range ids {
|
||||
if tlsConfigmap["id"].(string) == i {
|
||||
region = tlsConfigmap["region"].(string)
|
||||
// 如果未配置region,默认为上海-1
|
||||
if region == "" {
|
||||
region = "cn-east-3"
|
||||
}
|
||||
// 获取状态信息
|
||||
post, msg = genStatusMsg(region, ak, sk, i)
|
||||
// 构造post请求链接
|
||||
postUrl = generateUrl(webhook, "", map[string]interface{}{
|
||||
"action": "update",
|
||||
"id": id,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// id不为空,根据id更新或查看证书有效期
|
||||
if tlsConfigmap["id"].(string) == id {
|
||||
key, err := readFile(tlsConfigmap["private_key"].(string))
|
||||
if err != nil {
|
||||
msg = fmt.Sprintf("读取key文件出错:%s", err)
|
||||
}
|
||||
cert, err := readFile(tlsConfigmap["certificate"].(string))
|
||||
if err != nil {
|
||||
msg = fmt.Sprintf("读取cert文件出错:%s", err)
|
||||
}
|
||||
region = tlsConfigmap["region"].(string)
|
||||
if region == "" {
|
||||
region = "cn-east-3"
|
||||
}
|
||||
if action == "status" {
|
||||
post, msg = genStatusMsg(region, ak, sk, id)
|
||||
}
|
||||
if action == "update" {
|
||||
msg = genUpdateMsg(region, ak, sk, id, key, cert)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果配置有通知链接,则发送通知信息
|
||||
if notice {
|
||||
// 如果有通知信息,则发送通知
|
||||
if msg != "" {
|
||||
// 如果post为true,即发送飞书富文本信息
|
||||
if post {
|
||||
// 构造富文本信息
|
||||
postData := FeishuPostMessage{
|
||||
MsgType: "post",
|
||||
Content: PostContent{
|
||||
Post: &Post{
|
||||
ZhCn: &Message{
|
||||
Title: "华为云TLS",
|
||||
Content: [][]ContentItem{
|
||||
{
|
||||
{
|
||||
Tag: "text",
|
||||
TextContent: &TextContent{
|
||||
Text: msg,
|
||||
},
|
||||
},
|
||||
{
|
||||
Tag: "a",
|
||||
AContent: &AContent{
|
||||
Text: "点击续签TLS证书",
|
||||
Href: postUrl,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 发送通知富文本信息
|
||||
if err := postRequest(notify, postData); err != nil {
|
||||
fmt.Println("Error sending message:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// 发送text文本信息
|
||||
// 构造文本信息
|
||||
textData := FeishuTextMessage{
|
||||
MsgType: "text",
|
||||
Content: TextContent{
|
||||
Text: msg,
|
||||
},
|
||||
}
|
||||
// 发送通知
|
||||
if err := postRequest(notify, textData); err != nil {
|
||||
fmt.Println("Error sending message:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
rootCmd.Flags().StringVarP(&cfgFile, "config", "c", "", "Config file (default is $HOME/config.yaml, ./config.yaml, or BINARY/config.yaml)")
|
||||
rootCmd.Flags().StringVarP(&action, "action", "a", "status", "update or status")
|
||||
rootCmd.Flags().StringVarP(&id, "id", "i", "", "tls id")
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化配置文件
|
||||
func initConfig() {
|
||||
if cfgFile != "" {
|
||||
viper.SetConfigFile(cfgFile)
|
||||
} else {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
exec, err := os.Executable()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
exPath := filepath.Dir(exec)
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath(home)
|
||||
viper.AddConfigPath(exPath)
|
||||
viper.SetConfigName("config")
|
||||
}
|
||||
|
||||
viper.AutomaticEnv() // 从环境变量中读取配置
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||
}
|
||||
}
|
||||
|
||||
// 构建url
|
||||
func generateUrl(baseUrl, source string, parameters map[string]interface{}) string {
|
||||
base, err := url.Parse(baseUrl)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
base.Path += "/" + source
|
||||
query := base.Query()
|
||||
for param, value := range parameters {
|
||||
query.Add(param, fmt.Sprintf("%v", value))
|
||||
}
|
||||
base.RawQuery = query.Encode()
|
||||
|
||||
return base.String()
|
||||
}
|
||||
|
||||
// post请求
|
||||
func postRequest(url string, data interface{}) error {
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("HTTP status code: %d", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 读取文件
|
||||
func readFile(path string) (string, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
// 华为云ak,sk登录校验
|
||||
func authenticate(region, ak, sk string) *elb.ElbClient {
|
||||
auth, err := basic.NewCredentialsBuilder().
|
||||
WithAk(ak).
|
||||
WithSk(sk).
|
||||
SafeBuild()
|
||||
if err != nil {
|
||||
fmt.Println("Error creating credentials:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
r, err := elbRegion.SafeValueOf(region)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating credentials:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
elbClient, err := elb.ElbClientBuilder().WithRegion(r).WithCredential(auth).SafeBuild()
|
||||
if err != nil {
|
||||
fmt.Println("Error creating credentials:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
client := elb.NewElbClient(elbClient)
|
||||
return client
|
||||
}
|
||||
|
||||
// tls有效期
|
||||
func tlsValidity(region, ak, sk, id string) ([]string, string, error) {
|
||||
client := authenticate(region, ak, sk)
|
||||
request := &elbModel.ShowCertificateRequest{
|
||||
CertificateId: id,
|
||||
}
|
||||
response, err := client.ShowCertificate(request)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating credentials:", err)
|
||||
return nil, "", err
|
||||
}
|
||||
return *response.Certificate.SubjectAlternativeNames, response.Certificate.ExpireTime, nil
|
||||
}
|
||||
|
||||
// 时间差
|
||||
func timeDiff(expire string) (bool, error) {
|
||||
|
||||
// 解析时间字符串
|
||||
t, err := time.Parse(time.RFC3339, expire)
|
||||
if err != nil {
|
||||
fmt.Println("解析证书过期时间错误:", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 获取当前时间
|
||||
now := time.Now()
|
||||
|
||||
// 计算时间差
|
||||
duration := now.Sub(t)
|
||||
|
||||
// 检查时间差是否小于1天
|
||||
if duration > -24*time.Hour {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
// 更新tls
|
||||
func updateTLS(region, ak, sk, id, key, cert string) ([]string, error) {
|
||||
client := authenticate(region, ak, sk)
|
||||
request := &elbModel.UpdateCertificateRequest{
|
||||
CertificateId: id,
|
||||
}
|
||||
certificatebody := &elbModel.UpdateCertificateOption{
|
||||
|
||||
PrivateKey: &key,
|
||||
Certificate: &cert,
|
||||
}
|
||||
request.Body = &elbModel.UpdateCertificateRequestBody{
|
||||
Certificate: certificatebody,
|
||||
}
|
||||
response, err := client.UpdateCertificate(request)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating credentials:", err)
|
||||
return []string{}, err
|
||||
}
|
||||
return *response.Certificate.SubjectAlternativeNames, nil
|
||||
}
|
||||
|
||||
// 构造状态通知信息
|
||||
func genStatusMsg(region, ak, sk, id string) (bool, string) {
|
||||
var message string
|
||||
domain, expire, err := tlsValidity(region, ak, sk, id)
|
||||
if err != nil {
|
||||
message = fmt.Sprintf("获取证书信息失败,请检查配置文件或代码,错误信息:%v", err)
|
||||
return false, message
|
||||
}
|
||||
diff, err := timeDiff(expire)
|
||||
if err != nil {
|
||||
message = fmt.Sprintf("解析证书过期时间错误,请检查:%v", err)
|
||||
return false, message
|
||||
}
|
||||
|
||||
if diff {
|
||||
message = fmt.Sprintf("域名:%v\n\n证书有效期不足一天,请及时更新:", domain)
|
||||
return true, message
|
||||
}
|
||||
return false, message
|
||||
}
|
||||
|
||||
// 构造更新通知信息
|
||||
func genUpdateMsg(region, ak, sk, id, key, cert string) string {
|
||||
var message string
|
||||
domain, err := updateTLS(region, ak, sk, id, key, cert)
|
||||
if err != nil {
|
||||
message = fmt.Sprintf("Error updating TLS: %v", err)
|
||||
return message
|
||||
}
|
||||
message = fmt.Sprintf("域名:%v\nhttps证书更新成功", domain)
|
||||
return message
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue