SSH from A through B to C, using private key on B

Solution 1:


    ssh       ssh
A ------> B ------> C
    ^          ^
 using A's   using B's
 ssh key     ssh key


  • A is running ssh-agent;
  • A can access B;
  • B can access C;
  • A's ssh public key is present in B:~/.ssh/authorized_keys
  • B's ssh public key is present in C:~/.ssh/authorized_keys

In ~/.ssh/config on A, add

Host C
    ProxyCommand ssh -o 'ForwardAgent yes' B 'ssh-add && nc %h %p'

If your ssh private key on B is in a nonstandard location, add its path after ssh-add.

You should now be able to access C from A:

A$ ssh C

Solution 2:

Check if following is working.

ssh -t B ssh C

Use following command if you want to use key stored on B.

ssh -t B ssh -i /path/to/identity_on_B C

Here we are specifying command i.e ssh -i /path/to/identity_on_B C to be executed on B instead of a login shell.

Solution 3:

I've worked this out now. Here is the solution, which is rather straightforward. I should have seen it sooner:


Host B
  User myuser
  IdentityFile ~/.ssh/rsa_key
  ControlMaster auto
  ControlPath ~/.ssh/socket/master-%l-%r@%h:%p

Host C.*
  User customer_username
  Port customer_port
  IdentityFile remote/path/to/ssh/key
  ForwardAgent yes
  ProxyCommand ssh accessable.server nc %h %p

Host C.server-1

'B' is the Proxy server that you are jumping through. It should be configured as you normally would configure access to a server.

'C' is the destination host. It needs to be configured to use 'B' in the connection process. The identity file in 'C' is the path to the ssh-key on 'B'. The ProxyCommand uses Netcat to open the connection to 'C' from 'B'. Netcat, or nc, will need to be installed on 'B'.

NOTE1: For this to work, you need to copy the identity file of B (usually ~/.ssh/rd_isa) to A. I usually change its name to rd_isa_B.

NOTE2: This solution also works for scp.

Hope this helps others.

Solution 4:

I wrote a simple script to basically list my ssh keys on the remote instance, and then add the one I selected to my local ssh agent. This is not very clean, but allows me to keep all keys on a remote location rather than locally.

Here's the script if anyone is interested:


require "rubygems"
require "fileutils"

# Get key list
key_list = (`ssh jumpbox "cd ~/.ssh/ ; ls id_rsa*" | sed 's/id_rsa_/  /g' | sed     's/id_rsa//g'`)
puts ' '
puts 'Available customer keys:'
puts key_list

# Get customer name input
puts ' '
puts 'Enter customer name: '
customer_name = gets.chomp

# Add key to ssh-agent
key_name = "~/.ssh/id_rsa_#{customer_name}"
puts ' '
puts "Adding #{key_name} to local ssh-agent"
`ssh jumpbox "ssh-add ~/.ssh/id_rsa_#{customer_name}"`
exit 0

Solution 5:

Snowball's answer helped a lot. However, I made some modifications to the command and wanted to explain how it works. Given this situation:

    ssh        ssh
A -------> B -------> C
     ^          ^
  using A's  using B's
  ssh key    ssh key

Modify your ~/.ssh/config file and add the host B through which you want to jump, just how you would normally configure a host:

Host B
 User myusername

Then you add the host C that you want to end up on:

Host C
 User myusername
 ProxyCommand ssh -T -q -o 'ForwardAgent yes' B 'ssh-add -t 1 && nc %h %p'

Note the ProxyCommand, where:

  • ssh -T -q indicates that it should not allocate a pseudo-TTY (-T) and be quiet (-q);
  • once on the jump host B, we add the key to the SSH keys of A through ssh-add;
  • which only works because we forwarded the SSH agent using -o 'ForwardAgent yes'.
  • ssh-add -t 1 indicates that I want the key to be added only for the 1 second needed to authenticate to the final host C;
  • and finally, nc %h %p initiates a netcat connection to the final host %h at port %p (both which will be filled out by SSH based on the information in the ~/.ssh/config file).

If you need to specify a custom key on B to use, you can do that by modifying the ssh-add part:

Host C
 User myusername
 ProxyCommand ssh -T -q -o 'ForwardAgent yes' B 'ssh-add -t 1 ~/.ssh/mykey && nc %h %p'