Golangでsshへの接続を行う際、ssh proxyはどうやってやるんだろうと思ったんで調べてみた。 実装は結構簡単で、以下のように一度Proxyにsshでログイン後、ログイン対象サーバへの接続をProxyで作成してやるという流れでいけるようだ。

抜粋。動作するコードはこちらに記載。

ssh_term_proxy.go
// proxy1の情報 proxy1Host := "proxy1.host.local" proxy1Port := "22" proxy1User := "user" proxy1Pass := "password" // targetの情報 targetHost := "target.host.local" targetPort := "22" targetUser := "user" targetPass := "password" // sshClientConfigの作成(proxy1) proxy1SshConfig := &ssh.ClientConfig{ User: proxy1User, Auth: []ssh.AuthMethod{ssh.Password(proxy1Pass)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } // sshClientConfigの作成(target) targetSshConfig := &ssh.ClientConfig{ User: targetUser, Auth: []ssh.AuthMethod{ssh.Password(targetPass)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } // Proxy1へのsshClientの作成 proxy1Client, err := ssh.Dial("tcp", net.JoinHostPort(proxy1Host, proxy1Port), proxy1SshConfig) if err != nil { fmt.Println(err) } // Proxy1経由でのtargetへの接続を実施 proxy1Conn, err := proxy1Client.Dial("tcp", net.JoinHostPort(targetHost, targetPort)) if err != nil { fmt.Println(err) } // TargetへのsshClientを作成 pConnect, pChans, pReqs, err := ssh.NewClientConn(proxy1Conn, net.JoinHostPort(targetHost, targetPort), targetSshConfig) if err != nil { fmt.Println(err) } client := ssh.NewClient(pConnect, pChans, pReqs)

マルチプロキシ(多段プロキシ)もできることを確認した。 以下、サンプルコード。動作コードはこちら

ssh_term_multiple_proxy.go
// proxy1の情報 proxy1Host := "proxy1.host.local" proxy1Port := "22" proxy1User := "user" proxy1Pass := "password" // proxy2の情報 proxy2Host := "proxy2.host.local" proxy2Port := "22" proxy2User := "user" proxy2Pass := "password" // targetの情報 targetHost := "target.host.local" targetPort := "22" targetUser := "user" targetPass := "password" // sshClientConfigの作成(proxy1) proxy1SshConfig := &ssh.ClientConfig{ User: proxy1User, Auth: []ssh.AuthMethod{ssh.Password(proxy1Pass)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } // sshClientConfigの作成(proxy2) proxy2SshConfig := &ssh.ClientConfig{ User: proxy2User, Auth: []ssh.AuthMethod{ssh.Password(proxy2Pass)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } // sshClientConfigの作成(target) targetSshConfig := &ssh.ClientConfig{ User: targetUser, Auth: []ssh.AuthMethod{ssh.Password(targetPass)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } // Proxy1へのsshClientの作成 proxy1Client, err := ssh.Dial("tcp", net.JoinHostPort(proxy1Host, proxy1Port), proxy1SshConfig) if err != nil { fmt.Println(err) } // Proxy1経由でのProxy2への接続を実施 proxy1Conn, err := proxy1Client.Dial("tcp", net.JoinHostPort(proxy2Host, proxy2Port)) if err != nil { fmt.Println(err) } // Proxy2へのsshClientを作成 pConnect, pChans, pReqs, err := ssh.NewClientConn(proxy1Conn, net.JoinHostPort(proxy2Host, proxy2Port), proxy2SshConfig) if err != nil { fmt.Println(err) } proxy2Client := ssh.NewClient(pConnect, pChans, pReqs) // Proxy2経由でのtargetへの接続を実施 proxy2Conn, err := proxy2Client.Dial("tcp", net.JoinHostPort(targetHost, targetPort)) if err != nil { fmt.Println(err) } // TargetへのsshClientを作成 p2Connect, p2Chans, p2Reqs, err := ssh.NewClientConn(proxy2Conn, net.JoinHostPort(targetHost, targetPort), targetSshConfig) if err != nil { fmt.Println(err) } client := ssh.NewClient(p2Connect, p2Chans, p2Reqs)

多段プロキシとかが必要環境は多くはないと思うけど、とりあえず↑のようにしてやればできる。 地味にProxyCommandが必要無いのが個人的には気に入ってる。