Skip to content

Commit c3565f7

Browse files
feat(system-security): Support Hot Reloading of System Certificates (#7152)
Refs #7129
1 parent 7fdb0a5 commit c3565f7

File tree

18 files changed

+89
-117
lines changed

18 files changed

+89
-117
lines changed

backend/app/service/website_ca.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,9 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
381381
logger.Println(i18n.GetMsgByKey("ExecShellSuccess"))
382382
}
383383
}
384+
385+
reloadSystemSSL(websiteSSL, logger)
386+
384387
return websiteSSL, nil
385388
}
386389

backend/app/service/website_ssl.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package service
33
import (
44
"context"
55
"crypto"
6+
"crypto/tls"
67
"crypto/x509"
78
"encoding/pem"
89
"fmt"
@@ -188,6 +189,31 @@ func printSSLLog(logger *log.Logger, msgKey string, params map[string]interface{
188189
logger.Println(i18n.GetMsgWithMap(msgKey, params))
189190
}
190191

192+
func reloadSystemSSL(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
193+
systemSSLEnable, sslID := GetSystemSSL()
194+
if systemSSLEnable && sslID == websiteSSL.ID {
195+
fileOp := files.NewFileOp()
196+
certPath := path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt")
197+
keyPath := path.Join(global.CONF.System.BaseDir, "1panel/secret/server.key")
198+
printSSLLog(logger, "StartUpdateSystemSSL", nil, logger == nil)
199+
if err := fileOp.WriteFile(certPath, strings.NewReader(websiteSSL.Pem), 0600); err != nil {
200+
logger.Printf("Failed to update the SSL certificate File for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
201+
return
202+
}
203+
if err := fileOp.WriteFile(keyPath, strings.NewReader(websiteSSL.PrivateKey), 0600); err != nil {
204+
logger.Printf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
205+
return
206+
}
207+
newCert, err := tls.X509KeyPair([]byte(websiteSSL.Pem), []byte(websiteSSL.PrivateKey))
208+
if err != nil {
209+
logger.Printf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
210+
return
211+
}
212+
printSSLLog(logger, "UpdateSystemSSLSuccess", nil, logger == nil)
213+
constant.CertStore.Store(&newCert)
214+
}
215+
}
216+
191217
func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
192218
var (
193219
err error
@@ -344,6 +370,8 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
344370
}
345371
printSSLLog(logger, "ApplyWebSiteSSLSuccess", nil, apply.DisableLog)
346372
}
373+
374+
reloadSystemSSL(websiteSSL, logger)
347375
}()
348376

349377
return nil

backend/app/service/website_utils.go

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,23 +1002,22 @@ func saveCertificateFile(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
10021002
}
10031003
}
10041004

1005-
func GetSystemSSL() (bool, bool, uint) {
1005+
func GetSystemSSL() (bool, uint) {
10061006
sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
10071007
if err != nil {
10081008
global.LOG.Errorf("load service ssl from setting failed, err: %v", err)
1009-
return false, false, 0
1009+
return false, 0
10101010
}
10111011
if sslSetting.Value == "enable" {
10121012
sslID, _ := settingRepo.Get(settingRepo.WithByKey("SSLID"))
10131013
idValue, _ := strconv.Atoi(sslID.Value)
10141014
if idValue <= 0 {
1015-
return false, false, 0
1015+
return false, 0
10161016
}
10171017

1018-
auto, _ := settingRepo.Get(settingRepo.WithByKey("AutoRestart"))
1019-
return true, auto.Value == "enable", uint(idValue)
1018+
return true, uint(idValue)
10201019
}
1021-
return false, false, 0
1020+
return false, 0
10221021
}
10231022

10241023
func UpdateSSLConfig(websiteSSL model.WebsiteSSL) error {
@@ -1037,22 +1036,7 @@ func UpdateSSLConfig(websiteSSL model.WebsiteSSL) error {
10371036
return buserr.WithErr(constant.ErrSSLApply, err)
10381037
}
10391038
}
1040-
enable, auto, sslID := GetSystemSSL()
1041-
if enable && sslID == websiteSSL.ID {
1042-
fileOp := files.NewFileOp()
1043-
secretDir := path.Join(global.CONF.System.BaseDir, "1panel/secret")
1044-
if err := fileOp.WriteFile(path.Join(secretDir, "server.crt"), strings.NewReader(websiteSSL.Pem), 0600); err != nil {
1045-
global.LOG.Errorf("Failed to update the SSL certificate File for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
1046-
return err
1047-
}
1048-
if err := fileOp.WriteFile(path.Join(secretDir, "server.key"), strings.NewReader(websiteSSL.PrivateKey), 0600); err != nil {
1049-
global.LOG.Errorf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
1050-
return err
1051-
}
1052-
if auto {
1053-
_, _ = cmd.Exec("systemctl restart 1panel.service")
1054-
}
1055-
}
1039+
reloadSystemSSL(&websiteSSL, nil)
10561040
return nil
10571041
}
10581042

backend/constant/common.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package constant
22

3+
import "sync/atomic"
4+
35
type DBContext string
46

57
const (
@@ -123,3 +125,5 @@ var DynamicRoutes = []string{
123125
`^/databases/postgresql/setting/[^/]+/[^/]+$`,
124126
`^/websites/[^/]+/config/[^/]+$`,
125127
}
128+
129+
var CertStore atomic.Value

backend/cron/job/ssl.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
package job
22

33
import (
4-
"path"
5-
"strings"
64
"time"
75

86
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
97
"github.com/1Panel-dev/1Panel/backend/app/repo"
108
"github.com/1Panel-dev/1Panel/backend/app/service"
119
"github.com/1Panel-dev/1Panel/backend/constant"
1210
"github.com/1Panel-dev/1Panel/backend/global"
13-
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
1411
"github.com/1Panel-dev/1Panel/backend/utils/common"
15-
"github.com/1Panel-dev/1Panel/backend/utils/files"
1612
)
1713

1814
type ssl struct {
@@ -23,7 +19,6 @@ func NewSSLJob() *ssl {
2319
}
2420

2521
func (ssl *ssl) Run() {
26-
systemSSLEnable, auto, sslID := service.GetSystemSSL()
2722
sslRepo := repo.NewISSLRepo()
2823
sslService := service.NewIWebsiteSSLService()
2924
sslList, _ := sslRepo.List()
@@ -59,22 +54,6 @@ func (ssl *ssl) Run() {
5954
continue
6055
}
6156
}
62-
if systemSSLEnable && sslID == s.ID {
63-
websiteSSL, _ := sslRepo.GetFirst(repo.NewCommonRepo().WithByID(s.ID))
64-
fileOp := files.NewFileOp()
65-
secretDir := path.Join(global.CONF.System.BaseDir, "1panel/secret")
66-
if err := fileOp.WriteFile(path.Join(secretDir, "server.crt"), strings.NewReader(websiteSSL.Pem), 0600); err != nil {
67-
global.LOG.Errorf("Failed to update the SSL certificate File for 1Panel System domain [%s] , err:%s", s.PrimaryDomain, err.Error())
68-
continue
69-
}
70-
if err := fileOp.WriteFile(path.Join(secretDir, "server.key"), strings.NewReader(websiteSSL.PrivateKey), 0600); err != nil {
71-
global.LOG.Errorf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", s.PrimaryDomain, err.Error())
72-
continue
73-
}
74-
if auto {
75-
_, _ = cmd.Exec("systemctl restart 1panel.service")
76-
}
77-
}
7857
global.LOG.Infof("The SSL certificate for the [%s] domain has been successfully updated", s.PrimaryDomain)
7958
}
8059
}

backend/i18n/lang/en.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ ErrDefaultCA: "The default organization cannot be deleted"
127127
ApplyWebSiteSSLLog: "Start updating {{ .name }} website certificate"
128128
ErrUpdateWebsiteSSL: "{{ .name }} website failed to update certificate: {{ .err }}"
129129
ApplyWebSiteSSLSuccess: "Update website certificate successfully"
130+
StartUpdateSystemSSL: "Start updating system certificate"
131+
UpdateSystemSSLSuccess: "Update system certificate successfully"
130132

131133
#mysql
132134
ErrUserIsExist: "The current user already exists. Please enter a new user"

backend/i18n/lang/zh-Hant.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ ErrDefaultCA: "默認機構不能刪除"
126126
ApplyWebSiteSSLLog: "開始更新 {{ .name }} 網站憑證"
127127
ErrUpdateWebsiteSSL: "{{ .name }} 網站更新憑證失敗: {{ .err }}"
128128
ApplyWebSiteSSLSuccess: "更新網站憑證成功"
129+
StartUpdateSystemSSL: "開始更新系統證書"
130+
UpdateSystemSSLSuccess: "更新系統證書成功"
129131

130132

131133
#mysql

backend/i18n/lang/zh.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ ApplyWebSiteSSLSuccess: "更新网站证书成功"
130130
ErrExecShell: "执行脚本失败 {{ .err }}"
131131
ExecShellStart: "开始执行脚本"
132132
ExecShellSuccess: "脚本执行成功"
133+
StartUpdateSystemSSL: "开始更新系统证书"
134+
UpdateSystemSSLSuccess: "更新系统证书成功"
133135

134136
#mysql
135137
ErrUserIsExist: "当前用户已存在,请重新输入"

backend/server/server.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import (
44
"crypto/tls"
55
"encoding/gob"
66
"fmt"
7+
"github.com/1Panel-dev/1Panel/backend/constant"
8+
"github.com/1Panel-dev/1Panel/backend/i18n"
79
"net"
810
"net/http"
911
"os"
1012
"path"
1113

12-
"github.com/1Panel-dev/1Panel/backend/i18n"
13-
1414
"github.com/1Panel-dev/1Panel/backend/init/app"
1515
"github.com/1Panel-dev/1Panel/backend/init/business"
1616

@@ -81,12 +81,16 @@ func Start() {
8181
if err != nil {
8282
panic(err)
8383
}
84+
constant.CertStore.Store(&cert)
85+
8486
server.TLSConfig = &tls.Config{
85-
Certificates: []tls.Certificate{cert},
87+
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
88+
return constant.CertStore.Load().(*tls.Certificate), nil
89+
},
8690
}
8791
global.LOG.Infof("listen at https://%s:%s [%s]", global.CONF.System.BindAddress, global.CONF.System.Port, tcpItem)
8892

89-
if err := server.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, certPath, keyPath); err != nil {
93+
if err := server.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, "", ""); err != nil {
9094
panic(err)
9195
}
9296
} else {

frontend/src/api/interface/setting.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ export namespace Setting {
2929
bindAddress: string;
3030
ssl: string;
3131
sslType: string;
32-
autoRestart: string;
3332
allowIPs: string;
3433
bindDomain: string;
3534
securityEntrance: string;

0 commit comments

Comments
 (0)