mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 08:00:53 +00:00
feat: Modify the certificate auto-renewal logic. (#12430)
Refs https://github.com/1Panel-dev/1Panel/issues/12389
This commit is contained in:
@@ -51,7 +51,6 @@ type WebsiteSSLApply struct {
|
||||
ID uint `json:"ID" validate:"required"`
|
||||
SkipDNSCheck bool `json:"skipDNSCheck"`
|
||||
Nameservers []string `json:"nameservers"`
|
||||
DisableLog bool `json:"disableLog"`
|
||||
}
|
||||
|
||||
type WebsiteSSLObtain struct {
|
||||
|
||||
@@ -5,8 +5,7 @@ import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
@@ -14,6 +13,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
legoLogger "github.com/go-acme/lego/v4/log"
|
||||
"github.com/jinzhu/gorm"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
@@ -27,8 +30,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/req_helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ssl"
|
||||
legoLogger "github.com/go-acme/lego/v4/log"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
)
|
||||
|
||||
type WebsiteSSLService struct {
|
||||
@@ -45,6 +47,7 @@ type IWebsiteSSLService interface {
|
||||
Update(update request.WebsiteSSLUpdate) error
|
||||
Upload(req request.WebsiteSSLUpload) error
|
||||
ObtainSSL(apply request.WebsiteSSLApply) error
|
||||
AutoRenewSSL(id uint) error
|
||||
SyncForRestart() error
|
||||
DownloadFile(id uint) (*os.File, error)
|
||||
ImportMasterSSL(create model.WebsiteSSL) error
|
||||
@@ -210,13 +213,35 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
||||
return create, nil
|
||||
}
|
||||
|
||||
func printSSLLog(logger *log.Logger, msgKey string, params map[string]interface{}, disableLog bool) {
|
||||
if disableLog {
|
||||
func printSSLLog(logger *log.Logger, msgKey string, params map[string]interface{}) {
|
||||
if logger == nil {
|
||||
return
|
||||
}
|
||||
logger.Println(i18n.GetMsgWithMap(msgKey, params))
|
||||
}
|
||||
|
||||
func newWebsiteSSLLogger(websiteSSL *model.WebsiteSSL, autoRenew bool) (*os.File, *log.Logger) {
|
||||
flags := os.O_CREATE | os.O_WRONLY | os.O_TRUNC
|
||||
if autoRenew {
|
||||
flags = os.O_CREATE | os.O_WRONLY | os.O_APPEND
|
||||
}
|
||||
|
||||
logFile, err := os.OpenFile(websiteSSL.GetLogPath(), flags, constant.FilePerm)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("open ssl log file failed, domain: %s, err: %v", websiteSSL.PrimaryDomain, err)
|
||||
return nil, log.New(io.Discard, "", log.LstdFlags)
|
||||
}
|
||||
|
||||
if autoRenew {
|
||||
if info, statErr := logFile.Stat(); statErr == nil && info.Size() > 0 {
|
||||
_, _ = logFile.WriteString("\n")
|
||||
}
|
||||
_, _ = logFile.WriteString(fmt.Sprintf("========== [%s] auto renew attempt ==========\n", time.Now().Format(constant.DateTimeLayout)))
|
||||
}
|
||||
|
||||
return logFile, log.New(logFile, "", log.LstdFlags)
|
||||
}
|
||||
|
||||
func reloadSystemSSL(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
|
||||
if !global.IsMaster {
|
||||
return
|
||||
@@ -226,7 +251,7 @@ func reloadSystemSSL(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
|
||||
fileOp := files.NewFileOp()
|
||||
certPath := path.Join(global.Dir.DataDir, "secret/server.crt")
|
||||
keyPath := path.Join(global.Dir.DataDir, "secret/server.key")
|
||||
printSSLLog(logger, "StartUpdateSystemSSL", nil, logger == nil)
|
||||
printSSLLog(logger, "StartUpdateSystemSSL", nil)
|
||||
if err := fileOp.WriteFile(certPath, strings.NewReader(websiteSSL.Pem), 0600); err != nil {
|
||||
logger.Printf("Failed to update the SSL certificate File for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
|
||||
return
|
||||
@@ -239,11 +264,19 @@ func reloadSystemSSL(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
|
||||
logger.Printf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
|
||||
return
|
||||
}
|
||||
printSSLLog(logger, "UpdateSystemSSLSuccess", nil, logger == nil)
|
||||
printSSLLog(logger, "UpdateSystemSSLSuccess", nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
return w.obtainSSL(apply.ID, false)
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) AutoRenewSSL(id uint) error {
|
||||
return w.obtainSSL(id, true)
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) obtainSSL(id uint, autoRenew bool) error {
|
||||
var (
|
||||
err error
|
||||
websiteSSL *model.WebsiteSSL
|
||||
@@ -254,7 +287,7 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
resource certificate.Resource
|
||||
)
|
||||
|
||||
websiteSSL, err = websiteSSLRepo.GetFirst(repo.WithByID(apply.ID))
|
||||
websiteSSL, err = websiteSSLRepo.GetFirst(repo.WithByID(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -306,17 +339,16 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
}
|
||||
|
||||
go func() {
|
||||
logFile, _ := os.OpenFile(path.Join(global.Dir.SSLLogDir, fmt.Sprintf("%s-ssl-%d.log", websiteSSL.PrimaryDomain, websiteSSL.ID)), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, constant.FilePerm)
|
||||
defer logFile.Close()
|
||||
logger := log.New(logFile, "", log.LstdFlags)
|
||||
legoLogger.Logger = logger
|
||||
if !apply.DisableLog {
|
||||
startMsg := i18n.GetMsgWithMap("ApplySSLStart", map[string]interface{}{"domain": strings.Join(domains, ","), "type": i18n.GetMsgByKey(websiteSSL.Provider)})
|
||||
if websiteSSL.Provider == constant.DNSAccount {
|
||||
startMsg = startMsg + i18n.GetMsgWithMap("DNSAccountName", map[string]interface{}{"name": dnsAccount.Name, "type": dnsAccount.Type})
|
||||
}
|
||||
logger.Println(startMsg)
|
||||
logFile, logger := newWebsiteSSLLogger(websiteSSL, autoRenew)
|
||||
if logFile != nil {
|
||||
defer logFile.Close()
|
||||
}
|
||||
legoLogger.Logger = logger
|
||||
startMsg := i18n.GetMsgWithMap("ApplySSLStart", map[string]interface{}{"domain": strings.Join(domains, ","), "type": i18n.GetMsgByKey(websiteSSL.Provider)})
|
||||
if websiteSSL.Provider == constant.DNSAccount {
|
||||
startMsg = startMsg + i18n.GetMsgWithMap("DNSAccountName", map[string]interface{}{"name": dnsAccount.Name, "type": dnsAccount.Type})
|
||||
}
|
||||
logger.Println(startMsg)
|
||||
if websiteSSL.Provider != constant.DnsManual {
|
||||
privateKey, err := ssl.GetPrivateKeyByType(websiteSSL.KeyType, websiteSSL.PrivateKey)
|
||||
if err != nil {
|
||||
@@ -361,7 +393,7 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||
}
|
||||
websiteSSL.Status = constant.SSLReady
|
||||
printSSLLog(logger, "ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}, apply.DisableLog)
|
||||
printSSLLog(logger, "ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")})
|
||||
saveCertificateFile(websiteSSL, logger)
|
||||
|
||||
if websiteSSL.ExecShell {
|
||||
@@ -369,12 +401,12 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
if websiteSSL.PushDir {
|
||||
workDir = websiteSSL.Dir
|
||||
}
|
||||
printSSLLog(logger, "ExecShellStart", nil, apply.DisableLog)
|
||||
printSSLLog(logger, "ExecShellStart", nil)
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(30*time.Minute), cmd.WithLogger(logger), cmd.WithWorkDir(workDir))
|
||||
if err = cmdMgr.RunBashC(websiteSSL.Shell); err != nil {
|
||||
printSSLLog(logger, "ErrExecShell", map[string]interface{}{"err": err.Error()}, apply.DisableLog)
|
||||
printSSLLog(logger, "ErrExecShell", map[string]interface{}{"err": err.Error()})
|
||||
} else {
|
||||
printSSLLog(logger, "ExecShellSuccess", nil, apply.DisableLog)
|
||||
printSSLLog(logger, "ExecShellSuccess", nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,9 +418,9 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
websites, _ := websiteRepo.GetBy(websiteRepo.WithWebsiteSSLID(websiteSSL.ID))
|
||||
if len(websites) > 0 {
|
||||
for _, website := range websites {
|
||||
printSSLLog(logger, "ApplyWebSiteSSLLog", map[string]interface{}{"name": website.PrimaryDomain}, apply.DisableLog)
|
||||
printSSLLog(logger, "ApplyWebSiteSSLLog", map[string]interface{}{"name": website.PrimaryDomain})
|
||||
if err := createPemFile(website, *websiteSSL); err != nil {
|
||||
printSSLLog(logger, "ErrUpdateWebsiteSSL", map[string]interface{}{"name": website.PrimaryDomain, "err": err.Error()}, apply.DisableLog)
|
||||
printSSLLog(logger, "ErrUpdateWebsiteSSL", map[string]interface{}{"name": website.PrimaryDomain, "err": err.Error()})
|
||||
}
|
||||
}
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
@@ -396,19 +428,19 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
return
|
||||
}
|
||||
if err := opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
|
||||
printSSLLog(logger, "ErrSSLApply", nil, apply.DisableLog)
|
||||
printSSLLog(logger, "ErrSSLApply", nil)
|
||||
return
|
||||
}
|
||||
printSSLLog(logger, "ApplyWebSiteSSLSuccess", nil, apply.DisableLog)
|
||||
printSSLLog(logger, "ApplyWebSiteSSLSuccess", nil)
|
||||
}
|
||||
reloadSystemSSL(websiteSSL, logger)
|
||||
if websiteSSL.PushNode {
|
||||
printSSLLog(logger, "StartPushSSLToNode", nil, apply.DisableLog)
|
||||
printSSLLog(logger, "StartPushSSLToNode", nil)
|
||||
if err = xpack.PushSSLToNode(websiteSSL); err != nil {
|
||||
printSSLLog(logger, "PushSSLToNodeFailed", map[string]interface{}{"err": err.Error()}, apply.DisableLog)
|
||||
printSSLLog(logger, "PushSSLToNodeFailed", map[string]interface{}{"err": err.Error()})
|
||||
return
|
||||
}
|
||||
printSSLLog(logger, "PushSSLToNodeSuccess", nil, apply.DisableLog)
|
||||
printSSLLog(logger, "PushSSLToNodeSuccess", nil)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ func Run() {
|
||||
if _, err := global.Cron.AddJob("@daily", job.NewWebsiteJob()); err != nil {
|
||||
global.LOG.Errorf("can not add website corn job: %s", err.Error())
|
||||
}
|
||||
if _, err := global.Cron.AddJob("@daily", job.NewSSLJob()); err != nil {
|
||||
if _, err := global.Cron.AddJob("0 */6 * * *", job.NewSSLJob()); err != nil {
|
||||
global.LOG.Errorf("can not add ssl corn job: %s", err.Error())
|
||||
}
|
||||
minuteRand, err := rand.Int(rand.Reader, big.NewInt(60))
|
||||
|
||||
@@ -46,10 +46,7 @@ func (ssl *ssl) Run() {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if err := sslService.ObtainSSL(request.WebsiteSSLApply{
|
||||
ID: s.ID,
|
||||
DisableLog: true,
|
||||
}); err != nil {
|
||||
if err := sslService.AutoRenewSSL(s.ID); err != nil {
|
||||
global.LOG.Errorf("Failed to update the SSL certificate for the [%s] domain , err:%s", s.PrimaryDomain, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user