diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go index d7b95c332..91928ecb7 100644 --- a/agent/init/migration/migrations/init.go +++ b/agent/init/migration/migrations/init.go @@ -2,6 +2,8 @@ package migrations import ( "fmt" + "os" + "path" "github.com/1Panel-dev/1Panel/agent/app/dto/request" "github.com/1Panel-dev/1Panel/agent/app/model" @@ -9,6 +11,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/common" + "github.com/1Panel-dev/1Panel/agent/utils/encrypt" "github.com/go-gormigrate/gormigrate/v2" "gorm.io/gorm" @@ -159,6 +162,24 @@ var InitSetting = &gormigrate.Migration{ if err := tx.Create(&model.Setting{Key: "SnapshotIgnore", Value: "*.sock"}).Error; err != nil { return err } + + if _, err := os.Stat(path.Join(global.CONF.System.DataDir, "ssl", "server.key")); err != nil { + return err + } + serverKey, _ := os.ReadFile(path.Join(global.CONF.System.DataDir, "ssl", "server.key")) + itemKey, _ := encrypt.StringEncrypt(string(serverKey)) + if err := tx.Create(&model.Setting{Key: "ServerKey", Value: itemKey}).Error; err != nil { + return err + } + if _, err := os.Stat(path.Join(global.CONF.System.DataDir, "ssl", "server.crt")); err != nil { + return err + } + serverCrt, _ := os.ReadFile(path.Join(global.CONF.System.DataDir, "ssl", "server.crt")) + itemCrt, _ := encrypt.StringEncrypt(string(serverCrt)) + if err := tx.Create(&model.Setting{Key: "ServerCert", Value: string(itemCrt)}).Error; err != nil { + return err + } + return nil }, } diff --git a/agent/init/router/router.go b/agent/init/router/router.go index 15ea31a91..51923545d 100644 --- a/agent/init/router/router.go +++ b/agent/init/router/router.go @@ -2,6 +2,7 @@ package router import ( "github.com/1Panel-dev/1Panel/agent/i18n" + "github.com/1Panel-dev/1Panel/agent/middleware" rou "github.com/1Panel-dev/1Panel/agent/router" "github.com/gin-contrib/gzip" "github.com/gin-gonic/gin" @@ -24,6 +25,7 @@ func Routers() *gin.Engine { PublicGroup.Static("/api/v1/images", "./uploads") } PrivateGroup := Router.Group("/api/v2") + PrivateGroup.Use(middleware.Certificate()) for _, router := range rou.RouterGroupApp { router.InitRouter(PrivateGroup) } diff --git a/agent/middleware/certificate.go b/agent/middleware/certificate.go new file mode 100644 index 000000000..c4ca58f12 --- /dev/null +++ b/agent/middleware/certificate.go @@ -0,0 +1,25 @@ +package middleware + +import ( + "errors" + "fmt" + + "github.com/1Panel-dev/1Panel/agent/app/api/v1/helper" + "github.com/1Panel-dev/1Panel/agent/constant" + "github.com/gin-gonic/gin" +) + +func Certificate() gin.HandlerFunc { + return func(c *gin.Context) { + if !c.Request.TLS.HandshakeComplete || len(c.Request.TLS.PeerCertificates) == 0 { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("no such tls peer certificates")) + return + } + cert := c.Request.TLS.PeerCertificates[0] + if cert.Subject.CommonName != "panel_client" { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, fmt.Errorf("err certificate")) + return + } + c.Next() + } +} diff --git a/agent/middleware/helper.go b/agent/middleware/helper.go deleted file mode 100644 index 4a9a7d62c..000000000 --- a/agent/middleware/helper.go +++ /dev/null @@ -1,32 +0,0 @@ -package middleware - -import ( - "net/http" - - "github.com/1Panel-dev/1Panel/agent/app/repo" -) - -func LoadErrCode(errInfo string) int { - settingRepo := repo.NewISettingRepo() - codeVal, err := settingRepo.Get(settingRepo.WithByKey("NoAuthSetting")) - if err != nil { - return 500 - } - - switch codeVal.Value { - case "400": - return http.StatusBadRequest - case "401": - return http.StatusUnauthorized - case "403": - return http.StatusForbidden - case "404": - return http.StatusNotFound - case "408": - return http.StatusRequestTimeout - case "416": - return http.StatusRequestedRangeNotSatisfiable - default: - return http.StatusOK - } -} diff --git a/agent/server/server.go b/agent/server/server.go index 1872ffeba..cfd13e753 100644 --- a/agent/server/server.go +++ b/agent/server/server.go @@ -1,10 +1,13 @@ package server import ( + "crypto/tls" + "fmt" "net" "net/http" "os" + "github.com/1Panel-dev/1Panel/agent/app/repo" "github.com/1Panel-dev/1Panel/agent/cron" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/i18n" @@ -17,6 +20,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/init/router" "github.com/1Panel-dev/1Panel/agent/init/validator" "github.com/1Panel-dev/1Panel/agent/init/viper" + "github.com/1Panel-dev/1Panel/agent/utils/encrypt" "github.com/gin-gonic/gin" ) @@ -40,7 +44,7 @@ func Start() { server := &http.Server{ Handler: rootRouter, } - if len(global.CurrentNode) == 0 || global.CurrentNode == "127.0.0.1" { + if global.CurrentNode == "127.0.0.1" { _ = os.Remove("/tmp/agent.sock") listener, err := net.Listen("unix", "/tmp/agent.sock") if err != nil { @@ -49,15 +53,28 @@ func Start() { _ = server.Serve(listener) } else { server.Addr = "0.0.0.0:9999" - type tcpKeepAliveListener struct { - *net.TCPListener - } - ln, err := net.Listen("tcp4", "0.0.0.0:9999") + settingRepo := repo.NewISettingRepo() + certItem, err := settingRepo.Get(settingRepo.WithByKey("ServerCert")) if err != nil { panic(err) } - global.LOG.Info("listen at http://0.0.0.0:9999") - if err := server.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}); err != nil { + cert, _ := encrypt.StringDecrypt(certItem.Value) + keyItem, err := settingRepo.Get(settingRepo.WithByKey("ServerKey")) + if err != nil { + panic(err) + } + key, _ := encrypt.StringDecrypt(keyItem.Value) + tlsCert, err := tls.X509KeyPair([]byte(cert), []byte(key)) + if err != nil { + fmt.Printf("failed to load X.509 key pair: %s\n", err) + return + } + server.TLSConfig = &tls.Config{ + Certificates: []tls.Certificate{tlsCert}, + ClientAuth: tls.RequireAnyClientCert, + } + global.LOG.Info("listen at https://0.0.0.0:9999") + if err := server.ListenAndServeTLS("", ""); err != nil { panic(err) } } diff --git a/core/i18n/lang/en.yaml b/core/i18n/lang/en.yaml index b7522d691..fe407f845 100644 --- a/core/i18n/lang/en.yaml +++ b/core/i18n/lang/en.yaml @@ -8,7 +8,7 @@ ErrTransform: "Type conversion failure: {{ .detail }}" ErrNotLogin: "User is not Login: {{ .detail }}" ErrPasswordExpired: "The current password has expired: {{ .detail }}" ErrNotSupportType: "The system does not support the current type: {{ .detail }}" -ErrProxy: "Request error, please check the node status" +ErrProxy: "Request error, please check the node status: {{ .detail }}" #common ErrNameIsExist: "Name is already exist" diff --git a/core/i18n/lang/zh-Hant.yaml b/core/i18n/lang/zh-Hant.yaml index ece14379d..10d7d64f7 100644 --- a/core/i18n/lang/zh-Hant.yaml +++ b/core/i18n/lang/zh-Hant.yaml @@ -8,7 +8,7 @@ ErrTransform: "類型轉換失敗: {{ .detail }}" ErrNotLogin: "用戶未登入: {{ .detail }}" ErrPasswordExpired: "當前密碼已過期: {{ .detail }}" ErrNotSupportType: "系統暫不支持當前類型: {{ .detail }}" -ErrProxy: "請求錯誤,請檢查該節點狀態" +ErrProxy: "請求錯誤,請檢查該節點狀態: {{ .detail }}" #common ErrNameIsExist: "名稱已存在" diff --git a/core/i18n/lang/zh.yaml b/core/i18n/lang/zh.yaml index c9efe0033..36a0809cc 100644 --- a/core/i18n/lang/zh.yaml +++ b/core/i18n/lang/zh.yaml @@ -8,7 +8,7 @@ ErrTransform: "类型转换失败: {{ .detail }}" ErrNotLogin: "用户未登录: {{ .detail }}" ErrPasswordExpired: "当前密码已过期: {{ .detail }}" ErrNotSupportType: "系统暂不支持当前类型: {{ .detail }}" -ErrProxy: "请求错误,请检查该节点状态" +ErrProxy: "请求错误,请检查该节点状态: {{ .detail }}" #common ErrDemoEnvironment: "演示服务器,禁止此操作!" diff --git a/core/middleware/proxy.go b/core/middleware/proxy.go index 0f4cf4522..edd066713 100644 --- a/core/middleware/proxy.go +++ b/core/middleware/proxy.go @@ -6,12 +6,12 @@ import ( "net" "net/http" "net/http/httputil" - "net/url" "os" "strings" "github.com/1Panel-dev/1Panel/core/app/api/v1/helper" "github.com/1Panel-dev/1Panel/core/constant" + "github.com/1Panel-dev/1Panel/core/xpack/utlis/proxy" "github.com/gin-gonic/gin" ) @@ -22,40 +22,35 @@ func Proxy() gin.HandlerFunc { return } currentNode := c.Request.Header.Get("CurrentNode") - if currentNode == "127.0.0.1" { - sockPath := "/tmp/agent.sock" - if _, err := os.Stat(sockPath); err != nil { + if len(currentNode) != 0 && currentNode != "127.0.0.1" { + if err := proxy.Proxy(c, currentNode); err != nil { + fmt.Println(err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrProxy, err) return } - dialUnix := func() (conn net.Conn, err error) { - return net.Dial("unix", sockPath) - } - transport := &http.Transport{ - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return dialUnix() - }, - } - proxy := &httputil.ReverseProxy{ - Director: func(req *http.Request) { - req.URL.Scheme = "http" - req.URL.Host = "unix" - }, - Transport: transport, - } - proxy.ServeHTTP(c.Writer, c.Request) c.Abort() return } - target, err := url.Parse(fmt.Sprintf("http://%s:9999", currentNode)) - if err != nil { + sockPath := "/tmp/agent.sock" + if _, err := os.Stat(sockPath); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrProxy, err) return } - proxy := httputil.NewSingleHostReverseProxy(target) - c.Request.Host = target.Host - c.Request.URL.Scheme = target.Scheme - c.Request.URL.Host = target.Host + dialUnix := func() (conn net.Conn, err error) { + return net.Dial("unix", sockPath) + } + transport := &http.Transport{ + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + return dialUnix() + }, + } + proxy := &httputil.ReverseProxy{ + Director: func(req *http.Request) { + req.URL.Scheme = "http" + req.URL.Host = "unix" + }, + Transport: transport, + } proxy.ServeHTTP(c.Writer, c.Request) c.Abort() }