package ssh import ( "fmt" "io/ioutil" "log" "golang.org/x/crypto/ssh" ) type SSHConfig struct { User string Host string Port string Password string PrivateKey string } // ConnectSSH handles both key-based and password authentication dynamically. func ConnectSSH(config SSHConfig) error { log.Printf("Attempting SSH connection to %s@%s:%s", config.User, config.Host, config.Port) // Build SSH authentication methods var authMethods []ssh.AuthMethod // Add key-based authentication if a private key is provided if config.PrivateKey != "" { log.Println("Attempting key-based authentication...") key, err := ioutil.ReadFile(config.PrivateKey) if err != nil { log.Printf("Error reading private key: %v", err) return fmt.Errorf("failed to read private key: %w", err) } signer, err := ssh.ParsePrivateKey(key) if err != nil { log.Printf("Error parsing private key: %v", err) return fmt.Errorf("failed to parse private key: %w", err) } authMethods = append(authMethods, ssh.PublicKeys(signer)) } // Add password-based authentication if a password is provided if config.Password != "" { log.Println("Attempting password-based authentication...") authMethods = append(authMethods, ssh.Password(config.Password)) } // Ensure at least one authentication method is configured if len(authMethods) == 0 { return fmt.Errorf("no authentication method provided (password or private key)") } // Configure SSH client clientConfig := &ssh.ClientConfig{ User: config.User, Auth: authMethods, HostKeyCallback: ssh.InsecureIgnoreHostKey(), // Use a proper host key callback for production! } // Dial the SSH server address := fmt.Sprintf("%s:%s", config.Host, config.Port) log.Printf("Connecting to SSH server at %s...", address) client, err := ssh.Dial("tcp", address, clientConfig) if err != nil { log.Printf("Failed to connect to SSH server: %v", err) return fmt.Errorf("failed to connect to SSH server: %w", err) } defer client.Close() log.Printf("Successfully connected to %s@%s:%s", config.User, config.Host, config.Port) return nil }