From 6cf2891fed4cb7dae1386d3457ad60492f9b5f1f Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 1 Apr 2024 17:05:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20ssh=E7=94=9F=E6=88=90=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?RSA,=E6=94=AF=E6=8C=81=E6=9C=AC=E5=9C=B0=E7=9B=B4=E8=BF=9E?= =?UTF-8?q?=E6=8E=88=E6=9D=83=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/framework/utils/ssh/ssh.go | 64 +++++++++++++++---- .../network_element/controller/ne_host.go | 50 +++++++++++++++ 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src/framework/utils/ssh/ssh.go b/src/framework/utils/ssh/ssh.go index fbee80fb..15423619 100644 --- a/src/framework/utils/ssh/ssh.go +++ b/src/framework/utils/ssh/ssh.go @@ -11,6 +11,7 @@ import ( "time" "be.ems/src/framework/logger" + "be.ems/src/framework/utils/cmd" gossh "golang.org/x/crypto/ssh" ) @@ -96,20 +97,11 @@ func (c *ConnSSH) Close() { func (c *ConnSSH) NewClientByLocalPrivate() (*ConnSSH, error) { c.Port = 22 c.AuthMode = "1" - usr, err := user.Current() + privateKey, err := c.CurrentUserRsaKey(false) if err != nil { - logger.Errorf("NewClientByLocal get current user => %s", err.Error()) return nil, err } - - // 读取用户默认的私钥文件 - keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir) - key, err := os.ReadFile(keyPath) - if err != nil { - logger.Errorf("NewClientByLocal [%s] read private key => %s", usr.Username, err.Error()) - return nil, err - } - c.PrivateKey = string(key) + c.PrivateKey = privateKey return c.NewClient() } @@ -134,7 +126,55 @@ func (c *ConnSSH) RunCMD(cmd string) (string, error) { return c.LastResult, err } -// NewClient 创建SSH客户端会话对象 +// SendToAuthorizedKeys 发送当前用户私钥到远程服务器进行授权密钥 +func (c *ConnSSH) SendToAuthorizedKeys() error { + publicKey, err := c.CurrentUserRsaKey(true) + if err != nil { + return err + } + authorizedKeysEntry := fmt.Sprintln(strings.TrimSpace(publicKey)) + cmdStr := "echo '" + authorizedKeysEntry + "' >> ~/.ssh/authorized_keys" + _, err = c.RunCMD(cmdStr) + if err != nil { + logger.Errorf("SendAuthorizedKeys echo err %s", err.Error()) + return err + } + return nil +} + +// CurrentUserRsaKey 当前用户OMC使用的RSA私钥 +// 默认读取私钥 +// ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa +// ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub +func (c *ConnSSH) CurrentUserRsaKey(publicKey bool) (string, error) { + usr, err := user.Current() + if err != nil { + logger.Errorf("CurrentUserRsaKey get => %s", err.Error()) + return "", err + } + + // 是否存在私钥并创建 + keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir) + if _, err := os.Stat(keyPath); err != nil { + _, err2 := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath) + if err2 != nil { + logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err2.Error()) + } + } + + // 读取用户默认的文件 + if publicKey { + keyPath = keyPath + ".pub" + } + key, err := os.ReadFile(keyPath) + if err != nil { + logger.Errorf("CurrentUserRsaKey [%s] read => %s", usr.Username, err.Error()) + return "", fmt.Errorf("read file %s fail", keyPath) + } + return string(key), nil +} + +// NewClientSession 创建SSH客户端会话对象 func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) { sshSession, err := c.Client.NewSession() if err != nil { diff --git a/src/modules/network_element/controller/ne_host.go b/src/modules/network_element/controller/ne_host.go index 7bf39555..7baca4bd 100644 --- a/src/modules/network_element/controller/ne_host.go +++ b/src/modules/network_element/controller/ne_host.go @@ -354,3 +354,53 @@ func (s *NeHostController) CheckBySSH(c *gin.Context) { c.JSON(200, result.OkData(data)) } + +// 网元主机SSH方式授权免密发送 +// +// POST /authorizedBySSH +func (s *NeHostController) AuthorizedBySSH(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body model.NeHost + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 本地免密创建链接直连 + sshLink := false + lcoalConnSSH := ssh.ConnSSH{ + User: body.User, + Addr: body.Addr, + Port: body.Port, + } + lcoalClient, err := lcoalConnSSH.NewClientByLocalPrivate() + if err == nil { + sshLink = true + } + defer lcoalClient.Close() + if sshLink { + // 连接主机成功,无需重复免密授权认证 + c.JSON(200, result.OkMsg(i18n.TKey(language, "neHost.okBySSHLink"))) + return + } + + // 创建链接SSH客户端 + var connSSH ssh.ConnSSH + body.CopyTo(&connSSH) + client, err := connSSH.NewClient() + if err != nil { + // 连接主机失败,请检查连接参数后重试 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo"))) + return + } + defer client.Close() + + // 发送密钥 + err = client.SendToAuthorizedKeys() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.JSON(200, result.Ok(nil)) +}