1

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?

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes! Indeed you seem to be correct. I had scanned through the Net::SSH.start options and I somehow passed right over :keys. I think my eyes were grepping for something more like "IdentityFile" because that's what I'm used to seeing in the ssh-config.
0

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)

1 Comment

It might be worth pasting in answer the relevant code that actually makes tunneling possible. I assume it is just setting proxy command to ssh -W %h:%p bastion_user@bastion_host.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.