文章目录
前言
类似Xshell的SSH工具大家肯定都使用过,本篇文章就是使用go语言写一个小demo,来调用SSH的终端发送命令并返回结果。
一、golang.org/x/crypto/ssh是什么?
包 ssh 实现 SSH 客户端和服务器。
SSH 是一种传输安全协议、一种身份验证协议和一系列应用程序协议。最典型的应用程序级协议是远程 shell,这是专门实现的。但是,SSH的多路复用性质暴露给希望支持他人的用户。
官方解析: golang.org/x/crypto/ssh
二、使用步骤
1.引入库
import (
"fmt"
"github.com/mitchellh/go-homedir"
"golang.org/x/crypto/ssh"
"io/ioutil"
"log"
"time"
)
2.主要实现
//创建sshp登陆配置
config := &ssh.ClientConfig{
Timeout: time.Second,//ssh 连接time out 时间一秒钟, 如果ssh验证错误 会在一秒内返回
User: sshUser,
HostKeyCallback: ssh.InsecureIgnoreHostKey(), //这个可以, 但是不够安全
//HostKeyCallback: hostKeyCallBackFunc(h.Host),
}
if sshType == "password" {
config.Auth = []ssh.AuthMethod{ssh.Password(sshPassword)}
} else {
config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(sshKeyPath)}
}
//dial 获取ssh client
addr := fmt.Sprintf("%s:%d", sshHost, sshPort)
sshClient, err := ssh.Dial("tcp", addr, config)
if err != nil {
log.Fatal("创建ssh client 失败",err)
}
defer sshClient.Close()
//创建ssh-session
session, err := sshClient.NewSession()
if err != nil {
log.Fatal("创建ssh session 失败",err)
}
defer session.Close()
//执行远程命令
combo,err := session.CombinedOutput("XXXXXX")
if err != nil {
log.Fatal("远程执行cmd 失败",err)
}
log.Println("命令输出:",string(combo))
3.完整示例
package main
import (
"fmt"
"github.com/mitchellh/go-homedir"
"golang.org/x/crypto/ssh"
"io/ioutil"
"log"
"time"
)
func main(){
sshHost := "home.xxx.cn"
sshUser := "x"
sshPassword := "xxxxxx"
sshType := "password"//password 或者 key
sshKeyPath := ""//在服务器生成keyFile"
sshPort := 22
//创建sshp登陆配置
config := &ssh.ClientConfig{
Timeout: time.Second,//ssh 连接time out 时间一秒钟, 如果ssh验证错误 会在一秒内返回,尽量短些
User: sshUser,
HostKeyCallback: ssh.InsecureIgnoreHostKey(), //这个可以, 但是不够安全
//HostKeyCallback: hostKeyCallBackFunc(h.Host),
}
if sshType == "password" {
config.Auth = []ssh.AuthMethod{ssh.Password(sshPassword)}
} else {
config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(sshKeyPath)}
}
//dial 获取ssh client
addr := fmt.Sprintf("%s:%d", sshHost, sshPort)
sshClient, err := ssh.Dial("tcp", addr, config)
if err != nil {
log.Fatal("创建ssh client 失败",err)
}
defer sshClient.Close()
//创建ssh-session
session, err := sshClient.NewSession()
if err != nil {
log.Fatal("创建ssh session 失败",err)
}
defer session.Close()
//执行远程命令
combo,err := session.CombinedOutput("XXXXXXXX")
if err != nil {
log.Fatal("远程执行cmd 失败",err)
}
log.Println("命令输出:",string(combo))
}
//读取文件的方法
func publicKeyAuthFunc(kPath string) ssh.AuthMethod {
keyPath, err := homedir.Expand(kPath)
if err != nil {
log.Fatal("find key's home dir failed", err)
}
key, err := ioutil.ReadFile(keyPath)
if err != nil {
log.Fatal("ssh key file read failed", err)
}
// Create the Signer for this private key.
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
log.Fatal("ssh key signer failed", err)
}
return ssh.PublicKeys(signer)
}
总结
1. ssh.ClientConfig配置
- 主要的连接参数不能为空
- ssh.InsecureIgnoreHostKey回调, 这种方式不安全
- publicKeyAuthFunc 如果使用key登陆 就需要着用这个函数量读取id_rsa私钥,建议把字符串存在数据库。