web-dev-qa-db-fra.com

Comment exécuter une commande sur une machine distante dans une golang CLI?

Comment exécuter une commande sur une machine distante dans une golang CLI? Je dois écrire une CLI golang qui peut SSH sur une machine distante via une clé et exécuter une commande Shell. De plus, je dois être capable de faire ça un saut. par exemple. SSH dans une machine (comme un bastion de nuage), puis SSH dans une autre machine interne et exécutez une commande Shell.

Je n'ai pas (encore) trouvé d'exemples pour cela.

10
n8gard

Essayez avec os/exec https://golang.org/pkg/os/exec/ pour exécuter un 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)
    }
}

Pour sauter par dessus les machines, utilisez la directive ProxyCommand dans un fichier de configuration ssh.

Host remote_machine_name
  ProxyCommand ssh -q bastion nc remote_machine_ip 22
8
PerroVerd

Vous pouvez exécuter des commandes sur un ordinateur distant via SSH à l'aide du package "golang.org/x/crypto/ssh".

Voici un exemple de fonction démontrant l'utilisation simple d'exécuter une seule commande sur une machine distante et de renvoyer le résultat:

//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", 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
}
4
djd0

Les autres solutions ici fonctionneront, mais je jetterai une autre option que vous pourriez essayer:simplessh. Je pense que c'est plus facile à utiliser. Pour cette question, J'utiliserais l'option 3 ci-dessous où vous pouvez utiliser SSH avec votre clé.

Option 1: SSH sur une machine avec un mot de passe, puis exécutez une commande

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
}

Option 2: SSH sur une machine utilisant un ensemble de mots de passe possibles, puis exécutez une commande

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
}

Option 3: SSH sur une machine utilisant votre clé  

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
}
0
Katie S