Golang中SSH连接失败:Panic: Failed to dial: handshake failed问题排查

Golang中SSH连接失败:Panic: Failed to dial: handshake failed问题排查 大家好,

我有一个Go模块用于与远程主机建立SSH连接。

由于某些原因,在尝试建立初始连接时出现以下错误:

panic: Failed to dial: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remai`` goroutine 1 [running]: main.main()

config := &ssh.ClientConfig{
	User: os.Getenv("USER"),
	Auth: []ssh.AuthMethod{
		ssh.PublicKeys(signer),
	},
	HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

client, err := ssh.Dial("tcp", "<remotehost>:22", config)
if err != nil {
	panic("Failed to dial: " + err.Error())
}

更多关于Golang中SSH连接失败:Panic: Failed to dial: handshake failed问题排查的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

你好, 我是Go语言新手,所以请对我的话持保留态度,不过你试过直接运行SSH命令而不是通过脚本来手动访问服务器吗?

很久以前我用Perl写过一些脚本,当时遇到了很多失败错误。后来发现SSH连接无法建立,原因是一台服务器上禁用了SSH功能,另一台服务器上没有创建对应的用户名。 希望这个经验对你有帮助。

更多关于Golang中SSH连接失败:Panic: Failed to dial: handshake failed问题排查的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个典型的SSH认证失败问题。错误信息显示客户端尝试了nonepublickey两种认证方式,但都失败了。以下是几种可能的解决方案:

1. 检查私钥文件是否正确加载

确保私钥文件存在且格式正确:

import (
    "golang.org/x/crypto/ssh"
    "io/ioutil"
    "os"
)

func loadPrivateKey(keyPath string) (ssh.Signer, error) {
    key, err := ioutil.ReadFile(keyPath)
    if err != nil {
        return nil, err
    }
    
    signer, err := ssh.ParsePrivateKey(key)
    if err != nil {
        return nil, err
    }
    
    return signer, nil
}

// 使用示例
signer, err := loadPrivateKey("/path/to/private/key")
if err != nil {
    panic("Failed to parse private key: " + err.Error())
}

config := &ssh.ClientConfig{
    User: os.Getenv("USER"),
    Auth: []ssh.AuthMethod{
        ssh.PublicKeys(signer),
    },
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

2. 添加密码保护的私钥支持

如果私钥有密码保护:

func loadPrivateKeyWithPassword(keyPath, password string) (ssh.Signer, error) {
    key, err := ioutil.ReadFile(keyPath)
    if err != nil {
        return nil, err
    }
    
    var signer ssh.Signer
    if password != "" {
        signer, err = ssh.ParsePrivateKeyWithPassphrase(key, []byte(password))
    } else {
        signer, err = ssh.ParsePrivateKey(key)
    }
    
    if err != nil {
        return nil, err
    }
    
    return signer, nil
}

3. 添加多种认证方式

提供多种认证方式作为备选:

config := &ssh.ClientConfig{
    User: os.Getenv("USER"),
    Auth: []ssh.AuthMethod{
        ssh.PublicKeys(signer),
        // 添加密码认证作为备选
        ssh.Password("your-password"),
    },
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    // 设置超时
    Timeout: 30 * time.Second,
}

4. 完整的错误处理示例

package main

import (
    "fmt"
    "golang.org/x/crypto/ssh"
    "io/ioutil"
    "os"
    "time"
)

func main() {
    // 加载私钥
    signer, err := loadPrivateKey("/home/user/.ssh/id_rsa")
    if err != nil {
        fmt.Printf("私钥加载失败: %v\n", err)
        return
    }

    config := &ssh.ClientConfig{
        User: os.Getenv("USER"),
        Auth: []ssh.AuthMethod{
            ssh.PublicKeys(signer),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
        Timeout: 30 * time.Second,
    }

    client, err := ssh.Dial("tcp", "remotehost:22", config)
    if err != nil {
        fmt.Printf("SSH连接失败: %v\n", err)
        return
    }
    defer client.Close()
    
    fmt.Println("SSH连接成功")
}

func loadPrivateKey(keyPath string) (ssh.Signer, error) {
    key, err := ioutil.ReadFile(keyPath)
    if err != nil {
        return nil, fmt.Errorf("读取私钥文件失败: %w", err)
    }
    
    signer, err := ssh.ParsePrivateKey(key)
    if err != nil {
        return nil, fmt.Errorf("解析私钥失败: %w", err)
    }
    
    return signer, nil
}

5. 调试信息输出

添加详细的调试信息帮助定位问题:

func debugSSHConnection() {
    signer, err := loadPrivateKey("/path/to/private/key")
    if err != nil {
        fmt.Printf("私钥错误: %v\n", err)
        return
    }
    
    fmt.Printf("使用用户: %s\n", os.Getenv("USER"))
    fmt.Printf("连接目标: %s\n", "remotehost:22")
    
    config := &ssh.ClientConfig{
        User: os.Getenv("USER"),
        Auth: []ssh.AuthMethod{
            ssh.PublicKeys(signer),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
    
    client, err := ssh.Dial("tcp", "remotehost:22", config)
    if err != nil {
        fmt.Printf("详细错误: %v\n", err)
        return
    }
    defer client.Close()
    
    fmt.Println("连接成功")
}

主要检查点:

  • 私钥文件路径是否正确
  • 私钥格式是否有效
  • 远程服务器是否正确配置了对应的公钥
  • 用户名是否正确
  • 网络连接是否可达
回到顶部