golang ssh替代方案:通过nc实现ssh ProxyCommand。

huangapple go评论93阅读模式
英文:

golang ssh replacement ssh ProxyCommand by nc

问题

我计划实现一个使用Golang编写的SSH客户端,通过堡垒机连接到目标服务器。但不幸的是,我在替换nc代理时失败了。

我的本地SSH配置如下:

Host bastion
    HostName xxx.xxx.xxx.xxx
    User ec2-user
    IdentityFile ~/.ssh/xxx-bastion.pem
Host 10.0.*.*
  User ec2-user
  IdentityFile ~/.ssh/xxx-dest.pem
  ProxyCommand ssh -q bastion "nc -w 3600 %h %p"

我的Golang实现如下:

var (
    Bastion    = "xxx.xxx.xxx.xxx:22"
    Target     = "xxx.xxx.xxx.xxx:22"
    BastionPem = "/Users/me/.ssh/xxx-bastion.pem"
    DestPem    = "/Users/me/.ssh/xxx-dest.pem"
    Timeout    = 30 * time.Second
)

func BastionConfig() (*ssh.ClientConfig, error) {
    pemBytes, err := ioutil.ReadFile(BastionPem)
    if err != nil {
        log.Fatal(err)
    }
    signer, err := ssh.ParsePrivateKey(pemBytes)
    if err != nil {
        log.Fatalf("parse key failed:%v", err)
    }
    config := &ssh.ClientConfig{
        User:    "ec2-user",
        Auth:    []ssh.AuthMethod{ssh.PublicKeys(signer)},
        Timeout: Timeout,
    }
    return config, err
}

func DestConfig() (*ssh.ClientConfig, error) {
    pemBytes, err := ioutil.ReadFile(DestPem)
    if err != nil {
        log.Fatal(err)
    }
    signer, err := ssh.ParsePrivateKey(pemBytes)
    if err != nil {
        log.Fatalf("parse key failed:%v", err)
    }
    config := &ssh.ClientConfig{
        User:    "ec2-user",
        Auth:    []ssh.AuthMethod{ssh.PublicKeys(signer)},
        Timeout: Timeout,
    }
    return config, err
}

func Connect() {
    config, _ := BastionConfig()
    bClient, err := ssh.Dial("tcp", Bastion, config)
    if err != nil {
        log.Fatal("dial bastion error:", err)
    }
    log.Println("dial bastion ok...")
    // Dial a connection to the service host, from the bastion
    conn, err := bClient.Dial("tcp", Target)
    if err != nil {
        log.Fatal("dial target error", err)
    }
    targetConfig, _ := DestConfig()
    ncc, chans, reqs, err := ssh.NewClientConn(conn, Target, targetConfig)
    if err != nil {
        log.Fatal("new target conn error:", err)
    }
    log.Printf("target conn[%s] ok\n", Target)

    targetClient := ssh.NewClient(ncc, chans, reqs)
    if err != nil {
        log.Fatalf("target ssh error:%v", err)
    }

    session, err := targetClient.NewSession()

    if err != nil {
        log.Fatalf("session failed:%v", err)
    }
    defer session.Close()
    var stdoutBuf bytes.Buffer
    session.Stdout = &stdoutBuf
    err = session.Run("hostname")
    if err != nil {
        log.Fatalf("Run failed:%v", err)
    }
    log.Printf(">%s", stdoutBuf)

}

但是我得到的是堡垒机服务器的主机名,而不是目标服务器的主机名。我是否遗漏了目标服务器的输入/输出,或者其他地方出错了?有人可以给我一些指导吗?

非常感谢。

英文:

I'm planning to implement a golang version ssh client to connect to destination server by a bastion.But unfortunately,I failed at the replacement for nc proxy.

At my local ssh config:

Host bastion
HostName xxx.xxx.xxx.xxx
User ec2-user
IdentityFile ~/.ssh/xxx-bastion.pem
Host 10.0.*.*
User ec2-user
IdentityFile ~/.ssh/xxx-dest.pem
ProxyCommand ssh -q bastion "nc -w 3600 %h %p"

my golang implementation is like the following:

<!-- language: go-->

var(
Bastion=&quot;xxx.xxx.xxx.xxx:22&quot;
Target=&quot;xxx.xxx.xxx.xxx:22&quot;
BastionPem =&quot;/Users/me/.ssh/xxx-bastion.pem&quot;
DestPem =&quot;/Users/me/.ssh/xxx-dest.pem&quot;
Timeout=30*time.Second
)
func BastionConfig() (*ssh.ClientConfig,error){
pemBytes, err := ioutil.ReadFile(BastionPem)
if err != nil {
log.Fatal(err)
}
signer, err := ssh.ParsePrivateKey(pemBytes)
if err != nil {
log.Fatalf(&quot;parse key failed:%v&quot;, err)
}
config := &amp;ssh.ClientConfig{
User: &quot;ec2-user&quot;,
Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
Timeout:Timeout,
}
return config,err
}
func DestConfig() (*ssh.ClientConfig,error){
pemBytes, err := ioutil.ReadFile(TargetPem)
if err != nil {
log.Fatal(err)
}
signer, err := ssh.ParsePrivateKey(pemBytes)
if err != nil {
log.Fatalf(&quot;parse key failed:%v&quot;, err)
}
config := &amp;ssh.ClientConfig{
User: &quot;ec2-user&quot;,
Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
Timeout:Timeout,
}
return config,err
}
func Connect(){
config,_:= BastionConfig()
bClient, err := ssh.Dial(&quot;tcp&quot;, Bastion, config)
if err != nil {
log.Fatal(&quot;dial bastion error:&quot;,err)
}
log.Println(&quot;dial bastion ok...&quot;)
// Dial a connection to the service host, from the bastion
conn, err := bClient.Dial(&quot;tcp&quot;, Target)
if err != nil {
log.Fatal(&quot;dial target error&quot;,err)
}
targetConfig,_:= DestConfig()
ncc, chans, reqs, err := ssh.NewClientConn(conn, Target, targetConfig)
if err != nil {
log.Fatal(&quot;new target conn error:&quot;,err)
}
log.Printf(&quot;target conn[%s] ok\n&quot;,Target)
targetClient := ssh.NewClient(ncc, chans, reqs)
if err != nil {
log.Fatalf(&quot;target ssh error:%v&quot;,err)
}
session,err:=targetClient.NewSession()
if err!=nil{
log.Fatalf(&quot;session failed:%v&quot;,err)
}
defer session.Close()
var stdoutBuf bytes.Buffer
session.Stdout = &amp;stdoutBuf
err = session.Run(&quot;hostname&quot;)
if err != nil {
log.Fatalf(&quot;Run failed:%v&quot;, err)
}
log.Printf(&quot;&gt;%s&quot;, stdoutBuf)
}

But I got the hostname of the bastion server not my destination one,did I miss to lead the input/output of the destionation server or something, I don't know where is wrong for my code,Can anybody give me some directions.

thanks a lot.

答案1

得分: 2

尝试使用这个包 https://github.com/appleboy/easyssh-proxy

ssh := &amp;easyssh.MakeConfig{
User:    &quot;drone-scp&quot;,
Server:  &quot;localhost&quot;,
Port:    &quot;22&quot;,
KeyPath: &quot;./tests/.ssh/id_rsa&quot;,
Proxy: easyssh.DefaultConfig{
User:    &quot;drone-scp&quot;,
Server:  &quot;localhost&quot;,
Port:    &quot;22&quot;,
KeyPath: &quot;./tests/.ssh/id_rsa&quot;,
},
}
英文:

Try this package https://github.com/appleboy/easyssh-proxy

ssh := &amp;easyssh.MakeConfig{
User:    &quot;drone-scp&quot;,
Server:  &quot;localhost&quot;,
Port:    &quot;22&quot;,
KeyPath: &quot;./tests/.ssh/id_rsa&quot;,
Proxy: easyssh.DefaultConfig{
User:    &quot;drone-scp&quot;,
Server:  &quot;localhost&quot;,
Port:    &quot;22&quot;,
KeyPath: &quot;./tests/.ssh/id_rsa&quot;,
},
}

答案2

得分: 1

我发现我的代码是正确的。之前,我在本地对pem文件感到困惑。在我的服务器配置中,堡垒机和目标服务器的pem文件是非常不同的。所以目前,代码是正常的。我可以使用golang ssh登录到目标服务器并执行命令。

英文:

I've found my code is right. previously ,I was confused by the pem file locally. In my server configuration, the bastion and dest server ,the pem is quite different.so currently, the code is ok now. I can execute commands by logging into the target server with golang ssh.

huangapple
  • 本文由 发表于 2016年11月18日 10:02:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/40668227.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定