Question

I need some suggestions on how to use the Ruby Net::SSH and Net::SCP gem to proxy through several systems in order to execute commands or copy files.

It's very similar (if not almost exactly the same) as this previous post I made, using basic ssh from the linux command line.

How to script multiple ssh and scp commands to various systems

For example, LOCAL is my local system.

System A is a second system connected to LOCAL

System B is a third system connected to System A only. Also, System B is configured to only allow access from System A by way of it's ssh key.

For normal ssh from the command line, I have my .ssh/config file set up in this way:

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

From this point, as long as my pub key is in the authorized_hosts of sysA (let's assume it always will be), and sysA's pub key is in the authorized_hosts sysB (same assumption), the following will work seamlessly:

ssh systemB

I would like to implement this exact behavior in Ruby. I have some code similar to the following:

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

Unfortunately, this isn't working. I get an authentication failure.

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

What am I missing here?

Was it helpful?

Solution

Did you verify that your proxy command actually works on its own from the command line? It seems you might have mixed the order of the identity keys.

SystemA already knows you(?), you should not need to specify an identity for it. This is also based on the config setup you posted.

Instead to me it seems you need to forward the identity of SystemA to SystemB in the start command:

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

And then skip just skip the identity file in the Proxy setup command.

OTHER TIPS

I solved this problem with Net::SSH, but without the need for external configuration files. Net::SSH::Gateway was also helpful in my solution. I wrapped the solution into a gem called tunneler.

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)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top