【问题标题】:Proxy tunnel through multiple systems with Ruby Net::SSH使用 Ruby Net::SSH 通过多个系统的代理隧道
【发布时间】:2014-10-11 02:14:26
【问题描述】:

我需要一些关于如何使用 Ruby Net::SSH 和 Net::SCP gem 通过多个系统进行代理以执行命令或复制文件的建议。

它与我之前的这篇文章非常相似(如果不是几乎完全相同),使用的是 linux 命令行中的基本 ssh。

How to script multiple ssh and scp commands to various systems

例如,LOCAL 是我的本地系统。

系统 A 是连接到 LOCAL 的第二个系统

系统 B 是仅连接到系统 A 的第三个系统。此外,系统 B 被配置为仅允许系统 A 通过其 ssh 密钥进行访问。

对于来自命令行的普通 ssh,我以这种方式设置了我的 .ssh/config 文件:

Host systemA
        HostName        192.168.0.10
        User            A-user

Host systemB
        ProxyCommand    ssh -e none systemA exec /bin/nc %h %p 2>/dev/null
        HostName        192.168.0.11
        User            B-user
        IdentityFile    ~/.ssh/systemA_id_dsa

从这一点来看,只要我的 pub key 在 sysA 的 authorized_hosts 中(假设它总是如此),并且 sysA 的 pub key 在 authorized_hosts sysB 中(相同的假设),以下将无缝工作:

ssh systemB

我想在 Ruby 中实现这种精确的行为。我有一些类似于以下的代码:

require 'net/ssh'
require 'net/ssh/proxy/command'

str = 'ssh -l A-user -i /home/A-user/.ssh/id_dsa -e none 192.168.0.10 exec /bin/nc %h %p 2>/dev/null'
proxy = Net::SSH::Proxy::Command.new(str)

Net::SSH.start('192.168.0.11', 'B-user', :proxy => proxy) do |ssh|
  ssh.exec! "ls -lA"
end

很遗憾,这不起作用。我遇到了身份验证失败。

~/.rvm/gems/ruby-1.9.3-p327/gems/net-ssh-2.6.2/lib/net/ssh.rb:201:in `start': root (Net::SSH::AuthenticationFailed)

我在这里错过了什么?

【问题讨论】:

    标签: ruby ssh net-ssh


    【解决方案1】:

    您是否验证了您的代理命令实际上可以在命令行中独立运行?看来您可能混淆了身份密钥的顺序。

    SystemA 已经认识你(?),你不需要为它指定一个身份。这也是基于您发布的config 设置。

    在我看来,您似乎需要在 start 命令中将 SystemA 的身份转发给 SystemB:

    Net::SSH.start('192.168.0.11', 'B-user', 
                   :proxy => proxy, 
                   :keys  => [ "~/.ssh/systemA_id_dsa" ] ) do |ssh|
      ssh.exec! "ls -lA"
    end
    

    然后跳过只是跳过代理设置命令中的身份文件。

    【讨论】:

    • 是的!确实,您似乎是正确的。我扫描了 Net::SSH.start 选项,不知何故我通过了 :keys。我想我的眼睛正在寻找更像“IdentityFile”的东西,因为那是我习惯在 ssh-config 中看到的东西。
    【解决方案2】:

    我用 Net::SSH 解决了这个问题,但不需要外部配置文件。 Net::SSH::Gateway 在我的解决方案中也很有帮助。我将解决方案包装到一个名为 tunneler 的 gem 中。

    require "tunneler"
    
    # Create SSH tunnel
    tunnel = Tunneler::SshTunnel.new(bastion_user, bastion_host, {:keys => [bastion_key]})
    
    # Establish remote connection
    destination_host_connection = tunnel.remote(destination_user, destination_host, {:keys => [destination_key]})
    
    # Upload file to destination host via tunnel
    destination_host_connection.scp(local_file_path, destination_file_path)
    
    # Execute command on destination host via tunnel
    response = destination_host_connection.ssh(command)
    

    【讨论】:

    • 在答案中可能值得粘贴实际上使隧道成为可能的相关代码。我假设它只是将代理命令设置为ssh -W %h:%p bastion_user@bastion_host
    猜你喜欢
    • 2021-03-07
    • 2017-04-15
    • 1970-01-01
    • 2021-10-28
    • 2018-03-23
    • 1970-01-01
    • 2020-02-09
    • 2014-12-12
    • 2020-06-17
    相关资源
    最近更新 更多