feat: 节点证书验证启动

pull/5996/head
ssongliu 2024-07-31 18:29:41 +08:00
parent 865b6cba3f
commit 1e9494fa2b
9 changed files with 96 additions and 68 deletions

View File

@ -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
},
}

View File

@ -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)
}

View File

@ -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()
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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"

View File

@ -8,7 +8,7 @@ ErrTransform: "類型轉換失敗: {{ .detail }}"
ErrNotLogin: "用戶未登入: {{ .detail }}"
ErrPasswordExpired: "當前密碼已過期: {{ .detail }}"
ErrNotSupportType: "系統暫不支持當前類型: {{ .detail }}"
ErrProxy: "請求錯誤,請檢查該節點狀態"
ErrProxy: "請求錯誤,請檢查該節點狀態: {{ .detail }}"
#common
ErrNameIsExist: "名稱已存在"

View File

@ -8,7 +8,7 @@ ErrTransform: "类型转换失败: {{ .detail }}"
ErrNotLogin: "用户未登录: {{ .detail }}"
ErrPasswordExpired: "当前密码已过期: {{ .detail }}"
ErrNotSupportType: "系统暂不支持当前类型: {{ .detail }}"
ErrProxy: "请求错误,请检查该节点状态"
ErrProxy: "请求错误,请检查该节点状态: {{ .detail }}"
#common
ErrDemoEnvironment: "演示服务器,禁止此操作!"

View File

@ -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,7 +22,15 @@ func Proxy() gin.HandlerFunc {
return
}
currentNode := c.Request.Header.Get("CurrentNode")
if currentNode == "127.0.0.1" {
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
}
c.Abort()
return
}
sockPath := "/tmp/agent.sock"
if _, err := os.Stat(sockPath); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrProxy, err)
@ -45,18 +53,5 @@ func Proxy() gin.HandlerFunc {
}
proxy.ServeHTTP(c.Writer, c.Request)
c.Abort()
return
}
target, err := url.Parse(fmt.Sprintf("http://%s:9999", currentNode))
if 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
proxy.ServeHTTP(c.Writer, c.Request)
c.Abort()
}
}