Skip to content

Commit

Permalink
fix: 解决证书面板过期问题 (#3102)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhengkunwang223 authored Nov 29, 2023
1 parent 8288127 commit fa9d855
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 162 deletions.
4 changes: 2 additions & 2 deletions backend/app/api/v1/website_ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (b *BaseApi) ObtainWebsiteCA(c *gin.Context) {
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteCAService.ObtainSSL(req); err != nil {
if _, err := websiteCAService.ObtainSSL(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
Expand All @@ -131,7 +131,7 @@ func (b *BaseApi) RenewWebsiteCA(c *gin.Context) {
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteCAService.ObtainSSL(request.WebsiteCAObtain{
if _, err := websiteCAService.ObtainSSL(request.WebsiteCAObtain{
SSLID: req.SSLID,
Renew: true,
Unit: "year",
Expand Down
61 changes: 36 additions & 25 deletions backend/app/service/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"net"
"os"
"path"
Expand All @@ -21,7 +22,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3"
)
Expand Down Expand Up @@ -204,7 +204,6 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
}()
return nil
}

if _, err := os.Stat(secretDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(secretDir, os.ModePerm); err != nil {
return err
Expand All @@ -213,49 +212,61 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
if err := settingRepo.Update("SSLType", req.SSLType); err != nil {
return err
}
if req.SSLType == "self" {
var (
secret string
key string
)

switch req.SSLType {
case "self":
if len(req.Domain) == 0 {
return fmt.Errorf("load domain failed")
}
if err := ssl.GenerateSSL(req.Domain); err != nil {
return err
}
}
if req.SSLType == "select" {
sslInfo, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
defaultCA, err := websiteCARepo.GetFirst(commonRepo.WithByName("1Panel"))
if err != nil {
return err
}
req.Cert = sslInfo.Pem
req.Key = sslInfo.PrivateKey
req.SSLType = "import"
if err := settingRepo.Update("SSLID", strconv.Itoa(int(req.SSLID))); err != nil {
return err
}
}
if req.SSLType == "import" {
cert, err := os.OpenFile(path.Join(secretDir, "server.crt.tmp"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
websiteSSL, err := NewIWebsiteCAService().ObtainSSL(request.WebsiteCAObtain{
ID: defaultCA.ID,
KeyType: "P256",
Domains: req.Domain,
Time: 1,
Unit: "year",
AutoRenew: true,
})
if err != nil {
return err
}
defer cert.Close()
if _, err := cert.WriteString(req.Cert); err != nil {
secret = websiteSSL.Pem
key = websiteSSL.PrivateKey
if err := settingRepo.Update("SSLID", strconv.Itoa(int(websiteSSL.ID))); err != nil {
return err
}
key, err := os.OpenFile(path.Join(secretDir, "server.key.tmp"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
case "select":
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
if err != nil {
return err
}
if _, err := key.WriteString(req.Key); err != nil {
secret = websiteSSL.Pem
key = websiteSSL.PrivateKey
if err := settingRepo.Update("SSLID", strconv.Itoa(int(req.SSLID))); err != nil {
return err
}
defer key.Close()
case "import":
secret = req.Cert
key = req.Key
}

fileOp := files.NewFileOp()
if err := fileOp.WriteFile(path.Join(secretDir, "server.crt.tmp"), strings.NewReader(secret), 0600); err != nil {
return err
}
if err := fileOp.WriteFile(path.Join(secretDir, "server.key.tmp"), strings.NewReader(key), 0600); err != nil {
return err
}
if err := checkCertValid(req.Domain); err != nil {
return err
}

fileOp := files.NewFileOp()
if err := fileOp.Rename(path.Join(secretDir, "server.crt.tmp"), path.Join(secretDir, "server.crt")); err != nil {
return err
}
Expand Down
49 changes: 28 additions & 21 deletions backend/app/service/website_ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type IWebsiteCAService interface {
Create(create request.WebsiteCACreate) (*request.WebsiteCACreate, error)
GetCA(id uint) (*response.WebsiteCADTO, error)
Delete(id uint) error
ObtainSSL(req request.WebsiteCAObtain) error
ObtainSSL(req request.WebsiteCAObtain) (*model.WebsiteSSL, error)
}

func NewIWebsiteCAService() IWebsiteCAService {
Expand Down Expand Up @@ -169,10 +169,17 @@ func (w WebsiteCAService) Delete(id uint) error {
if len(ssls) > 0 {
return buserr.New("ErrDeleteCAWithSSL")
}
exist, err := websiteCARepo.GetFirst(commonRepo.WithByID(id))
if err != nil {
return err
}
if exist.Name == "1Panel" {
return buserr.New("ErrDefaultCA")
}
return websiteCARepo.DeleteBy(commonRepo.WithByID(id))
}

func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.WebsiteSSL, error) {
var (
domains []string
ips []net.IP
Expand All @@ -183,11 +190,11 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
if req.Renew {
websiteSSL, err = websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
if err != nil {
return err
return nil, err
}
ca, err = websiteCARepo.GetFirst(commonRepo.WithByID(websiteSSL.CaID))
if err != nil {
return err
return nil, err
}
existDomains := []string{websiteSSL.PrimaryDomain}
if websiteSSL.Domains != "" {
Expand All @@ -203,7 +210,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
} else {
ca, err = websiteCARepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return err
return nil, err
}
websiteSSL = &model.WebsiteSSL{
Provider: constant.SelfSigned,
Expand All @@ -214,7 +221,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
}
if req.PushDir {
if !files.NewFileOp().Stat(req.Dir) {
return buserr.New(constant.ErrLinkPathNotFound)
return nil, buserr.New(constant.ErrLinkPathNotFound)
}
websiteSSL.Dir = req.Dir
}
Expand All @@ -223,7 +230,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
for _, domain := range domainArray {
if !common.IsValidDomain(domain) {
err = buserr.WithName("ErrDomainFormat", domain)
return err
return nil, err
} else {
if ipAddress := net.ParseIP(domain); ipAddress == nil {
domains = append(domains, domain)
Expand All @@ -241,32 +248,32 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {

rootCertBlock, _ := pem.Decode([]byte(ca.CSR))
if rootCertBlock == nil {
return buserr.New("ErrSSLCertificateFormat")
return nil, buserr.New("ErrSSLCertificateFormat")
}
rootCsr, err := x509.ParseCertificate(rootCertBlock.Bytes)
if err != nil {
return err
return nil, err
}
rootPrivateKeyBlock, _ := pem.Decode([]byte(ca.PrivateKey))
if rootPrivateKeyBlock == nil {
return buserr.New("ErrSSLCertificateFormat")
return nil, buserr.New("ErrSSLCertificateFormat")
}

var rootPrivateKey any
if ssl.KeyType(websiteSSL.KeyType) == certcrypto.EC256 || ssl.KeyType(websiteSSL.KeyType) == certcrypto.EC384 {
rootPrivateKey, err = x509.ParseECPrivateKey(rootPrivateKeyBlock.Bytes)
if err != nil {
return err
return nil, err
}
} else {
rootPrivateKey, err = x509.ParsePKCS1PrivateKey(rootPrivateKeyBlock.Bytes)
if err != nil {
return err
return nil, err
}
}
interPrivateKey, interPublicKey, _, err := createPrivateKey(websiteSSL.KeyType)
if err != nil {
return err
return nil, err
}
notAfter := time.Now()
if req.Unit == "year" {
Expand All @@ -287,16 +294,16 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
}
interDer, err := x509.CreateCertificate(rand.Reader, interCsr, rootCsr, interPublicKey, rootPrivateKey)
if err != nil {
return err
return nil, err
}
interCert, err := x509.ParseCertificate(interDer)
if err != nil {
return err
return nil, err
}

_, publicKey, privateKeyBytes, err := createPrivateKey(websiteSSL.KeyType)
if err != nil {
return err
return nil, err
}

csr := &x509.Certificate{
Expand All @@ -314,11 +321,11 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {

der, err := x509.CreateCertificate(rand.Reader, csr, interCert, publicKey, interPrivateKey)
if err != nil {
return err
return nil, err
}
cert, err := x509.ParseCertificate(der)
if err != nil {
return err
return nil, err
}

certBlock := &pem.Block{
Expand All @@ -335,11 +342,11 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {

if req.Renew {
if err := websiteSSLRepo.Save(websiteSSL); err != nil {
return err
return nil, err
}
} else {
if err := websiteSSLRepo.Create(context.Background(), websiteSSL); err != nil {
return err
return nil, err
}
}

Expand All @@ -348,7 +355,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
logger := log.New(logFile, "", log.LstdFlags)
logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}))
saveCertificateFile(websiteSSL, logger)
return nil
return websiteSSL, nil
}

func createPrivateKey(keyType string) (privateKey any, publicKey any, privateKeyBytes []byte, err error) {
Expand Down
37 changes: 36 additions & 1 deletion backend/cron/job/ssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import (
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"path"
"strconv"
"strings"
"time"
)

Expand All @@ -17,7 +21,25 @@ func NewSSLJob() *ssl {
return &ssl{}
}

func getSystemSSL() (bool, uint) {
settingRepo := repo.NewISettingRepo()
sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
if err != nil {
global.LOG.Errorf("load service ssl from setting failed, err: %v", err)
return false, 0
}
if sslSetting.Value == "enable" {
sslID, _ := settingRepo.Get(settingRepo.WithByKey("SSLID"))
idValue, _ := strconv.Atoi(sslID.Value)
if idValue > 0 {
return true, uint(idValue)
}
}
return false, 0
}

func (ssl *ssl) Run() {
systemSSLEnable, sslID := getSystemSSL()
sslRepo := repo.NewISSLRepo()
sslService := service.NewIWebsiteSSLService()
sslList, _ := sslRepo.List()
Expand All @@ -34,7 +56,7 @@ func (ssl *ssl) Run() {
global.LOG.Errorf("Update the SSL certificate for the [%s] domain", s.PrimaryDomain)
if s.Provider == constant.SelfSigned {
caService := service.NewIWebsiteCAService()
if err := caService.ObtainSSL(request.WebsiteCAObtain{
if _, err := caService.ObtainSSL(request.WebsiteCAObtain{
ID: s.CaID,
SSLID: s.ID,
Renew: true,
Expand All @@ -52,6 +74,19 @@ func (ssl *ssl) Run() {
continue
}
}
if systemSSLEnable && sslID == s.ID {
websiteSSL, _ := sslRepo.GetFirst(repo.NewCommonRepo().WithByID(s.ID))
fileOp := files.NewFileOp()
secretDir := path.Join(global.CONF.System.BaseDir, "1panel/secret")
if err := fileOp.WriteFile(path.Join(secretDir, "server.crt"), strings.NewReader(websiteSSL.Pem), 0600); err != nil {
global.LOG.Errorf("Failed to update the SSL certificate File for 1Panel System domain [%s] , err:%s", s.PrimaryDomain, err.Error())
continue
}
if err := fileOp.WriteFile(path.Join(secretDir, "server.key"), strings.NewReader(websiteSSL.PrivateKey), 0600); err != nil {
global.LOG.Errorf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", s.PrimaryDomain, err.Error())
continue
}
}
global.LOG.Errorf("The SSL certificate for the [%s] domain has been successfully updated", s.PrimaryDomain)
}
}
Expand Down
1 change: 1 addition & 0 deletions backend/init/migration/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func Init() {
migrations.AddWebsiteCA,
migrations.AddDockerSockPath,
migrations.AddDatabaseSSL,
migrations.AddDefaultCA,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
Expand Down
22 changes: 22 additions & 0 deletions backend/init/migration/migrations/v_1_9.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package migrations

import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/service"
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
)
Expand Down Expand Up @@ -55,3 +57,23 @@ var AddDatabaseSSL = &gormigrate.Migration{
return nil
},
}

var AddDefaultCA = &gormigrate.Migration{
ID: "20231129-add-default-ca",
Migrate: func(tx *gorm.DB) error {
caService := service.NewIWebsiteCAService()
if _, err := caService.Create(request.WebsiteCACreate{
CommonName: "1Panel-CA",
Country: "CN",
KeyType: "P256",
Name: "1Panel",
Organization: "FIT2CLOUD",
OrganizationUint: "1Panel",
Province: "Beijing",
City: "Beijing",
}); err != nil {
return err
}
return nil
},
}
Loading

0 comments on commit fa9d855

Please sign in to comment.