I am trying to ssh into Arista EOS Switch by using golang package: golang.org/x/crypto/ssh
, the idea is to ssh into switch, execute some commands and get output.
here is my code:
func ExecuteCommands(commands []string) string {
config := &ssh.ClientConfig{
User: n.Username,
Auth: []ssh.AuthMethod{
ssh.Password(n.Password),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
client, err := ssh.Dial("tcp", n.IpAddress + ":" + n.Port, config)
if err != nil {
msg := fmt.Sprintf("Failed to connect to host: %v on port 22, error: %v, Username: %v, Password: %v", n.IpAddress, err, n.Username, n.Password)
return msg
}
defer client.Close()
session, err := client.NewSession()
if err != nil {
msg := fmt.Sprintf("Failed to create a session with client: %v", err.Error())
return msg
}
defer session.Close()
stdin, err := session.StdinPipe()
if err != nil {
log.Fatalf("Unable to setup stdin for session: %v", err)
}
stdout, err := session.StdoutPipe()
if err != nil {
log.Fatalf("Unable to setup stdout for session: %v", err)
}
stderr, err := session.StderrPipe()
if err != nil {
log.Fatalf("Unable to setup stderr for session: %v", err)
}
output := ""
// Start the remote shell
if err := session.Shell(); err != nil {
log.Fatalf("Failed to start shell: %v", err)
}
// Goroutine to read stdout
go func() {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
output += scanner.Text()
}
}()
// Goroutine to read stderr
go func() {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
output += scanner.Text()
}
}()
// Send commands
writer := bufio.NewWriter(stdin)
for _, cmd := range commands {
_, err := writer.WriteString(cmd + "\n")
if err != nil {
log.Printf("Error writing command: %v", err)
break
}
writer.Flush()
time.Sleep(500 * time.Millisecond) // Give time for output to appear
}
// Close stdin to signal end of input
stdin.Close()
session.Wait()
return output
}
While this code works perfectly fine for linux device it fails with following error for Arista EOS Switch:
error: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none], no supported methods remain,
I am suspecting that there are some setting in golang crypto package with which we can solve this issue but I am unable to find such a configuration, please help.
As suggested by @kostix, I did ssh into server by using -v and found that it was asking for keyboard-interactive for Auth mode, so here is the updated method:
func ExecuteCommands(commands []string) string {
Ciphers := ssh.InsecureAlgorithms().Ciphers
Ciphers = append(Ciphers, ssh.SupportedAlgorithms().Ciphers...)
KeyExchanges := ssh.InsecureAlgorithms().KeyExchanges
KeyExchanges = append(KeyExchanges, ssh.SupportedAlgorithms().KeyExchanges...)
Macs := ssh.InsecureAlgorithms().MACs
Macs = append(Macs, ssh.SupportedAlgorithms().MACs...)
config := &ssh.ClientConfig{
User: n.Username,
Auth: []ssh.AuthMethod{
ssh.Password(n.Password),
ssh.KeyboardInteractive(func(user, instruction string, questions []string, echon []bool) ([]string, error) {
// The server is prompting for a password
if len(questions) == 1 && strings.Contains(strings.TrimSpace(strings.ToLower(questions[0])), "password:") {
return []string{n.Password}, nil
}
return nil, nil
}),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Config: ssh.Config{
Ciphers: Ciphers,
KeyExchanges: KeyExchanges,
MACs: Macs,
},
}
client, err := ssh.Dial("tcp", n.IpAddress + ":" + n.Port, config)
if err != nil {
msg := fmt.Sprintf("Failed to connect to host: %v on port 22, error: %v, Username: %v, Password: %v", n.IpAddress, err, n.Username, n.Password)
return msg
}
defer client.Close()
session, err := client.NewSession()
if err != nil {
msg := fmt.Sprintf("Failed to create a session with client: %v", err.Error())
return msg
}
defer session.Close()
stdin, err := session.StdinPipe()
if err != nil {
log.Fatalf("Unable to setup stdin for session: %v", err)
}
stdout, err := session.StdoutPipe()
if err != nil {
log.Fatalf("Unable to setup stdout for session: %v", err)
}
stderr, err := session.StderrPipe()
if err != nil {
log.Fatalf("Unable to setup stderr for session: %v", err)
}
output := ""
// Start the remote shell
if err := session.Shell(); err != nil {
log.Fatalf("Failed to start shell: %v", err)
}
// Goroutine to read stdout
go func() {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
output += scanner.Text()
}
}()
// Goroutine to read stderr
go func() {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
output += scanner.Text()
}
}()
// Send commands
writer := bufio.NewWriter(stdin)
for _, cmd := range commands {
_, err := writer.WriteString(cmd + "\n")
if err != nil {
log.Printf("Error writing command: %v", err)
break
}
writer.Flush()
time.Sleep(500 * time.Millisecond) // Give time for output to appear
}
// Close stdin to signal end of input
stdin.Close()
// Wait for the session to finish (optional, depending on your needs)
session.Wait()
return output
}