如何在golang CLI中在远程计算机上执行命令?

n8g*_*ard 11 ssh command-line-interface go

如何在golang CLI中在远程计算机上执行命令?我需要编写一个golang CLI,它可以通过密钥SSH连接到远程机器并执行shell命令.此外,我需要能够做到这一步.例如,SSH进入机器(如云堡垒),然后SSH到另一台内部机器并执行shell命令.

我还没有找到任何这方面的例子.

Per*_*erd 11

尝试使用os/exec https://golang.org/pkg/os/exec/来执行ssh

package main

import (
    "bytes"
    "log"
    "os/exec"
)

func main() {
    cmd := exec.Command("ssh", "remote-machine", "bash-command")
    var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
}
Run Code Online (Sandbox Code Playgroud)

要跳过计算机,请在ssh配置文件中使用ProxyCommand指令.

Host remote_machine_name
  ProxyCommand ssh -q bastion nc remote_machine_ip 22
Run Code Online (Sandbox Code Playgroud)

  • 您可以在ssh中使用`-W`选项,而不是生成`nc`进程 (3认同)
  • 如果远程机器需要密码怎么办?有没有办法传递密码? (2认同)

djd*_*jd0 6

您可以使用该"golang.org/x/crypto/ssh"软件包通过SSH在远程计算机上运行命令。

这是一个示例函数,演示了在远程计算机上运行单个命令并返回输出的简单用法:

//e.g. output, err := remoteRun("root", "MY_IP", "PRIVATE_KEY", "ls")
func remoteRun(user string, addr string, privateKey string, cmd string) (string, error) {
    // privateKey could be read from a file, or retrieved from another storage
    // source, such as the Secret Service / GNOME Keyring
    key, err := ssh.ParsePrivateKey([]byte(privateKey))
    if err != nil {
        return "", err
    }
    // Authentication
    config := &ssh.ClientConfig{
        User: user,
        Auth: []ssh.AuthMethod{
            ssh.PublicKeys(key),
        },
        //alternatively, you could use a password
        /*
            Auth: []ssh.AuthMethod{
                ssh.Password("PASSWORD"),
            },
        */
    }
    // Connect
    client, err := ssh.Dial("tcp", net.JoinHostPort(addr, "22"), config)
    if err != nil {
        return "", err
    }
    // Create a session. It is one session per command.
    session, err := client.NewSession()
    if err != nil {
        return "", err
    }
    defer session.Close()
    var b bytes.Buffer  // import "bytes"
    session.Stdout = &b // get output
    // you can also pass what gets input to the stdin, allowing you to pipe
    // content from client to server
    //      session.Stdin = bytes.NewBufferString("My input")

    // Finally, run the command
    err = session.Run(cmd)
    return b.String(), err
}
Run Code Online (Sandbox Code Playgroud)


Kat*_*tie 6

这里的其他解决方案也可以工作,但我会抛出您可以尝试的另一个选项:simplessh。我认为它更容易使用。对于这个问题,我将使用下面的选项 3,您可以使用您的密钥进行 ssh。

选项 1:使用密码通过 SSH 连接到计算机,然后运行命令

import (
    "log"

    "github.com/sfreiberg/simplessh"
)

func main() error {
    var client *simplessh.Client
    var err error

    if client, err = simplessh.ConnectWithPassword("hostname_to_ssh_to", "username", "password"); err != nil {
        return err
    }

    defer client.Close()

    // Now run the commands on the remote machine:
    if _, err := client.Exec("cat /tmp/somefile"); err != nil {
        log.Println(err)
    }

    return nil
}
Run Code Online (Sandbox Code Playgroud)

选项 2:使用一组可能的密码通过 SSH 连接到计算机,然后运行命令

import (
    "log"

    "github.com/sfreiberg/simplessh"
)

type access struct {
    login    string
    password string
}

var loginAccess []access

func init() {
    // Initialize all password to try
    loginAccess = append(loginAccess, access{"root", "rootpassword1"})
    loginAccess = append(loginAccess, access{"someuser", "newpassword"})
}

func main() error {
    var client *simplessh.Client
    var err error

    // Try to connect with first password, then tried second else fails gracefully
    for _, credentials := range loginAccess {
        if client, err = simplessh.ConnectWithPassword("hostname_to_ssh_to", credentials.login, credentials.password); err == nil {
            break
        }
    }

    if err != nil {
        return err
    }

    defer client.Close()

    // Now run the commands on the remote machine:
    if _, err := client.Exec("cat /tmp/somefile"); err != nil {
        log.Println(err)
    }

    return nil
}
Run Code Online (Sandbox Code Playgroud)

选项 3:使用您的密钥通过 SSH 连接到计算机

import (
    "log"

    "github.com/sfreiberg/simplessh"
)

func SshAndRunCommand() error {
    var client *simplessh.Client
    var err error

    // Option A: Using a specific private key path:
    //if client, err = simplessh.ConnectWithKeyFile("hostname_to_ssh_to", "username", "/home/user/.ssh/id_rsa"); err != nil {

    // Option B: Using your default private key at $HOME/.ssh/id_rsa:
    //if client, err = simplessh.ConnectWithKeyFile("hostname_to_ssh_to", "username"); err != nil {

    // Option C: Use the current user to ssh and the default private key file:
    if client, err = simplessh.ConnectWithKeyFile("hostname_to_ssh_to"); err != nil {
        return err
    }

    defer client.Close()

    // Now run the commands on the remote machine:
    if _, err := client.Exec("cat /tmp/somefile"); err != nil {
        log.Println(err)
    }

    return nil
}
Run Code Online (Sandbox Code Playgroud)