奇怪的知识:golang 通过 ssh 连接另一个ssh 执行命令该如何实现呢?
spooking 归属分类: 开发运维 评论数: 0 个

纯粹是突发奇想,有奇葩思路的可以借鉴借鉴,?。

package main

import (
    "bytes"
    "fmt"

    "io/ioutil"
    "log"

    "golang.org/x/crypto/ssh"
)

type Endpoint struct {
    Host string
    Port int
}

func (endpoint *Endpoint) String() string {
    return fmt.Sprintf("%s:%d", endpoint.Host, endpoint.Port)
}

func publicKeyFile(file string) ssh.AuthMethod {
    buffer, err := ioutil.ReadFile(file)
    if err != nil {
        log.Fatalln(fmt.Sprintf("Cannot read SSH public key file %s", file))
        return nil
    }

    key, err := ssh.ParsePrivateKey(buffer)
    if err != nil {
        log.Fatalln(fmt.Sprintf("Cannot parse SSH public key file %s", file))
        return nil
    }
    return ssh.PublicKeys(key)
}

// 服务器1(公网),可以理解为跳板机、堡垒机
var serverEndpoint = Endpoint{
    Host: "183.2.172.185",
    Port: 22,
}

// 服务器2(内网)
var remoteEndpoint = Endpoint{
    Host: "192.168.1.100",
    Port: 12701,
}

func main() {

        //服务器1 的 ssh 连接配置,通过秘钥
    sshConfig := &ssh.ClientConfig{
        User: "user1",
        Auth: []ssh.AuthMethod{
            publicKeyFile("./user1_id_rsa"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
        //服务器2 的 ssh 连接配置,通过密码
    sshConfig2 := &ssh.ClientConfig{
        User: "root",
        Auth: []ssh.AuthMethod{
            ssh.Password("123456"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
        //连接服务器1
    serverConn, err := ssh.Dial("tcp", serverEndpoint.String(), sshConfig)
    if err != nil {
        log.Fatalln(fmt.Printf("连接服务器1 出错: %s", err))
    }

    //通过服务器1中转,连接服务器2的ssh端口
    listener, err := serverConn.Dial("tcp", remoteEndpoint.String())
    if err != nil {
        log.Fatalln(fmt.Printf("连接客户机失败: %s", err))
    }
    defer listener.Close()

        //简介服务器2
    c, chans, reqs, err := ssh.NewClientConn(listener, remoteEndpoint.String(), sshConfig2)
    if err != nil {
        log.Fatalln(fmt.Printf("连接服务器2的 SSH 出错: %s", err))
    }

    client := ssh.NewClient(c, chans, reqs)

    defer client.Close()

    session, err := client.NewSession()
    if err != nil {
        log.Fatal("创建 session 出错: ", err)
    }
    defer session.Close()

    var b bytes.Buffer
    session.Stdout = &b
    if err := session.Run("ls /"); err != nil {
        log.Fatal("运行命令失败: " + err.Error())
    }
    fmt.Println(b.String())

}