mirror of https://github.com/1Panel-dev/1Panel
feat: 节点证书验证启动
parent
865b6cba3f
commit
1e9494fa2b
|
@ -2,6 +2,8 @@ package migrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
"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/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
|
||||||
|
|
||||||
"github.com/go-gormigrate/gormigrate/v2"
|
"github.com/go-gormigrate/gormigrate/v2"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
@ -159,6 +162,24 @@ var InitSetting = &gormigrate.Migration{
|
||||||
if err := tx.Create(&model.Setting{Key: "SnapshotIgnore", Value: "*.sock"}).Error; err != nil {
|
if err := tx.Create(&model.Setting{Key: "SnapshotIgnore", Value: "*.sock"}).Error; err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/middleware"
|
||||||
rou "github.com/1Panel-dev/1Panel/agent/router"
|
rou "github.com/1Panel-dev/1Panel/agent/router"
|
||||||
"github.com/gin-contrib/gzip"
|
"github.com/gin-contrib/gzip"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -24,6 +25,7 @@ func Routers() *gin.Engine {
|
||||||
PublicGroup.Static("/api/v1/images", "./uploads")
|
PublicGroup.Static("/api/v1/images", "./uploads")
|
||||||
}
|
}
|
||||||
PrivateGroup := Router.Group("/api/v2")
|
PrivateGroup := Router.Group("/api/v2")
|
||||||
|
PrivateGroup.Use(middleware.Certificate())
|
||||||
for _, router := range rou.RouterGroupApp {
|
for _, router := range rou.RouterGroupApp {
|
||||||
router.InitRouter(PrivateGroup)
|
router.InitRouter(PrivateGroup)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,13 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/agent/cron"
|
"github.com/1Panel-dev/1Panel/agent/cron"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
"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/router"
|
||||||
"github.com/1Panel-dev/1Panel/agent/init/validator"
|
"github.com/1Panel-dev/1Panel/agent/init/validator"
|
||||||
"github.com/1Panel-dev/1Panel/agent/init/viper"
|
"github.com/1Panel-dev/1Panel/agent/init/viper"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
@ -40,7 +44,7 @@ func Start() {
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: rootRouter,
|
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")
|
_ = os.Remove("/tmp/agent.sock")
|
||||||
listener, err := net.Listen("unix", "/tmp/agent.sock")
|
listener, err := net.Listen("unix", "/tmp/agent.sock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -49,15 +53,28 @@ func Start() {
|
||||||
_ = server.Serve(listener)
|
_ = server.Serve(listener)
|
||||||
} else {
|
} else {
|
||||||
server.Addr = "0.0.0.0:9999"
|
server.Addr = "0.0.0.0:9999"
|
||||||
type tcpKeepAliveListener struct {
|
settingRepo := repo.NewISettingRepo()
|
||||||
*net.TCPListener
|
certItem, err := settingRepo.Get(settingRepo.WithByKey("ServerCert"))
|
||||||
}
|
|
||||||
ln, err := net.Listen("tcp4", "0.0.0.0:9999")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
global.LOG.Info("listen at http://0.0.0.0:9999")
|
cert, _ := encrypt.StringDecrypt(certItem.Value)
|
||||||
if err := server.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}); err != nil {
|
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)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ ErrTransform: "Type conversion failure: {{ .detail }}"
|
||||||
ErrNotLogin: "User is not Login: {{ .detail }}"
|
ErrNotLogin: "User is not Login: {{ .detail }}"
|
||||||
ErrPasswordExpired: "The current password has expired: {{ .detail }}"
|
ErrPasswordExpired: "The current password has expired: {{ .detail }}"
|
||||||
ErrNotSupportType: "The system does not support the current type: {{ .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
|
#common
|
||||||
ErrNameIsExist: "Name is already exist"
|
ErrNameIsExist: "Name is already exist"
|
||||||
|
|
|
@ -8,7 +8,7 @@ ErrTransform: "類型轉換失敗: {{ .detail }}"
|
||||||
ErrNotLogin: "用戶未登入: {{ .detail }}"
|
ErrNotLogin: "用戶未登入: {{ .detail }}"
|
||||||
ErrPasswordExpired: "當前密碼已過期: {{ .detail }}"
|
ErrPasswordExpired: "當前密碼已過期: {{ .detail }}"
|
||||||
ErrNotSupportType: "系統暫不支持當前類型: {{ .detail }}"
|
ErrNotSupportType: "系統暫不支持當前類型: {{ .detail }}"
|
||||||
ErrProxy: "請求錯誤,請檢查該節點狀態"
|
ErrProxy: "請求錯誤,請檢查該節點狀態: {{ .detail }}"
|
||||||
|
|
||||||
#common
|
#common
|
||||||
ErrNameIsExist: "名稱已存在"
|
ErrNameIsExist: "名稱已存在"
|
||||||
|
|
|
@ -8,7 +8,7 @@ ErrTransform: "类型转换失败: {{ .detail }}"
|
||||||
ErrNotLogin: "用户未登录: {{ .detail }}"
|
ErrNotLogin: "用户未登录: {{ .detail }}"
|
||||||
ErrPasswordExpired: "当前密码已过期: {{ .detail }}"
|
ErrPasswordExpired: "当前密码已过期: {{ .detail }}"
|
||||||
ErrNotSupportType: "系统暂不支持当前类型: {{ .detail }}"
|
ErrNotSupportType: "系统暂不支持当前类型: {{ .detail }}"
|
||||||
ErrProxy: "请求错误,请检查该节点状态"
|
ErrProxy: "请求错误,请检查该节点状态: {{ .detail }}"
|
||||||
|
|
||||||
#common
|
#common
|
||||||
ErrDemoEnvironment: "演示服务器,禁止此操作!"
|
ErrDemoEnvironment: "演示服务器,禁止此操作!"
|
||||||
|
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/core/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/core/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/core/constant"
|
"github.com/1Panel-dev/1Panel/core/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/core/xpack/utlis/proxy"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,40 +22,35 @@ func Proxy() gin.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
currentNode := c.Request.Header.Get("CurrentNode")
|
currentNode := c.Request.Header.Get("CurrentNode")
|
||||||
if currentNode == "127.0.0.1" {
|
if len(currentNode) != 0 && currentNode != "127.0.0.1" {
|
||||||
sockPath := "/tmp/agent.sock"
|
if err := proxy.Proxy(c, currentNode); err != nil {
|
||||||
if _, err := os.Stat(sockPath); err != nil {
|
fmt.Println(err)
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrProxy, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrProxy, err)
|
||||||
return
|
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()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
target, err := url.Parse(fmt.Sprintf("http://%s:9999", currentNode))
|
sockPath := "/tmp/agent.sock"
|
||||||
if err != nil {
|
if _, err := os.Stat(sockPath); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrProxy, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrProxy, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
proxy := httputil.NewSingleHostReverseProxy(target)
|
dialUnix := func() (conn net.Conn, err error) {
|
||||||
c.Request.Host = target.Host
|
return net.Dial("unix", sockPath)
|
||||||
c.Request.URL.Scheme = target.Scheme
|
}
|
||||||
c.Request.URL.Host = target.Host
|
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)
|
proxy.ServeHTTP(c.Writer, c.Request)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue