web-dev-qa-db-ja.com

GoのSSH:認証できない、試行されたメソッド[なし]、サポートされているメソッドが残っていない

SSHとGoを使用して、仮想マシンの1つに接続しようとしました。私がそうするなら、コマンドラインを介して完璧に動作します:

ssh root@my_Host

パスワードを入力すると、すべて正常に機能します。私はGoでそれをやろうとしました、ここに私のコードがあります:

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()
}

実行するとエラーが返されます:

ssh: handshake failed: ssh: unable to authenticate, attempted methods [none], no supported methods remain

誰がそのようなエラーを引き起こす可能性があるのか​​考えていますか? Pythonおよびシェルではparamikoを使用すると正常に動作しますが、Goでは失敗します。不足しているものはありますか?

15
midori

@JimBと@putuが指摘するように、私のサーバーではパスワード認証が有効になっていません。詳細オプションを使用してsshを実行し、サポートされているすべての認証方法が返されたことを確認します。私の場合、次のようになりました。

debug1: Authentications that can continue: publickey,keyboard-interactive,hostbased

そのため、サーバーでパスワード認証を有効にするか、他の方法を使用して認証するかの2つのオプションがありました。

パスワード認証を有効にするには、サーバーに接続し、次のようにsshd構成ファイルを開きます。

vi/etc/ssh/sshd_config

次の行を見つけます:PasswordAuthentication no

はいに変更し、変更を保存してsshdサービスを再起動します:service ssh restart

その後、パスワード認証方法が期待どおりに機能し始めます。または、他の方法を使用することもできます。キーボードインタラクティブを試すことにしました。通常、sshを使用して端末を介して接続するときに1人のユーザーがいます。リモートサーバーがパスワードの質問をした後にパスワードを送信するコードスニペットを次に示します。

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()
}

私の場合、サーバーはパスワードである質問を1つだけ要求します。サーバーがそれ以上を要求する場合、フィードバックするために一連の回答全体を構築する必要があります。

11
midori