J'ai essayé de me connecter à l'une de mes machines virtuelles à l'aide de SSH et Go. Cela fonctionne parfaitement bien via la ligne de commande si je le fais comme ça:
ssh root@my_Host
Je tape le mot de passe et ça marche bien. J'ai essayé de le faire dans Go, voici mon code:
package main
import (
"golang.org/x/crypto/ssh"
"fmt"
)
func connectViaSsh(user, Host string, password string) (*ssh.Client, *ssh.Session) {
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{ssh.Password(password)},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
client, err := ssh.Dial("tcp", Host, config)
fmt.Println(err)
session, err := client.NewSession()
fmt.Println(err)
return client, session
}
func main() {
client, _ := connectViaSsh("root", "Host:22", "password")
client.Close()
}
Si je l'exécute, il renvoie une erreur:
ssh: handshake failed: ssh: unable to authenticate, attempted methods [none], no supported methods remain
Quelqu'un at-il une idée de ce qui pourrait provoquer une telle erreur? Cela fonctionne très bien en utilisant paramiko en Python et dans Shell, mais échoue dans Go. Y a-t-il quelque chose qui me manque?
Comme indiqué par @JimB et @putu, mon serveur n'a pas activé l'authentification par mot de passe. Pour vérifier que j'ai exécuté ssh avec l'option verbose et qu'il m'a rendu toutes les méthodes d'authentification prises en charge. Dans mon cas, il s'est avéré être le suivant:
debug1: Authentications that can continue: publickey,keyboard-interactive,hostbased
J'ai donc eu 2 options pour aller, soit activer l'authentification par mot de passe sur le serveur ou utiliser une autre méthode pour s'authentifier.
Pour activer l'authentification par mot de passe, connectez-vous à votre serveur et ouvrez le fichier de configuration sshd comme ceci:
vi/etc/ssh/sshd_config
Rechercher une ligne disant: PasswordAuthentication no
Remplacez-le par oui, enregistrez les modifications et redémarrez le service sshd: service ssh restart
Après cette méthode d'authentification par mot de passe commence à fonctionner comme prévu. Alternativement, d'autres méthodes peuvent être utilisées, j'ai décidé d'essayer le clavier interactif, celui que l'utilisateur a généralement lorsqu'il se connecte via le terminal à l'aide de ssh. Voici l'extrait de code qui fait exactement cela, envoie le mot de passe après que la question du mot de passe est posée par le serveur distant:
package main
import (
"bytes"
"golang.org/x/crypto/ssh"
"fmt"
)
func connectViaSsh(user, Host string, password string) (*ssh.Client, *ssh.Session) {
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.KeyboardInteractive(SshInteractive),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
client, err := ssh.Dial("tcp", Host, config)
fmt.Println(err)
session, err := client.NewSession()
fmt.Println(err)
return client, session
}
func SshInteractive(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
answers = make([]string, len(questions))
// The second parameter is unused
for n, _ := range questions {
answers[n] = "your_password"
}
return answers, nil
}
func main() {
var b bytes.Buffer
client, session := connectViaSsh("root", "Host:22", "password")
session.Stdout = &b
session.Run("ls")
fmt.Println(b.String())
client.Close()
}
Dans mon cas, le serveur ne pose qu'une seule question qui est le mot de passe, si votre serveur demande plus que cela, vous auriez besoin de construire une chaîne entière de réponses pour y répondre.