57

I'm looking for a simple way to SSH from my local machine, A, through a proxy, B, to a destination host, C. The private key that goes with the public key on C is on B, and I can't put that key on my local machine. Any tips?

Also, I'd like to be able to do this using ~/.ssh/config.

Thanks!

  • 1
    Are you saying you want to ssh from A to B, and then SSH to C ? Or is proxy a true pass-thru situation? – thinice Dec 3 '11 at 5:25
  • I want to ssh from A to C, passing through B. My answer below works for the passing through part, but it still tries to look for the IdentityFile on my local computer instead of on B, the pass-through host. – wrangler Dec 6 '11 at 18:03
72

Schematic:

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

Preconditions:

  • 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
C$
  • 12
    It only took 4 years, but looks like we have an answer! Awesome – wrangler Sep 25 '16 at 17:28
  • 3
    Starting with openssh v.7.3, you can just use ProxyJump B. source: wikibooks – Keith Nov 12 '16 at 20:35
  • 2
    Can this be defined such that: Host user1@c ProxyCommand ssh -o 'ForwardAgent yes' user2@B 'ssh-add && nc %h %p' – Ravindranath Akila Jan 27 '17 at 1:37
  • 2
    How would the solution change if machine B doesn't have nc? – mjalajel Mar 18 '17 at 13:30
  • 1
    @DrewVS Ok, one needs to add ForwardAgent yes before the ProxyJump command. – Graipher Jul 18 '17 at 13:38
21

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.

  • This works but it does not pick up the IdentityFile from B. It still looks on A. – wrangler Dec 6 '11 at 18:05
  • @DrewVS I have updated the answer. Please check if it is working for you. – Sachin Divekar Dec 6 '11 at 18:41
  • Sachin, very clever. That worked perfectly. Thanks so much! – wrangler Dec 7 '11 at 19:06
  • @DrewVS glad to hear that it worked for you. so please accept the answer. – Sachin Divekar Dec 7 '11 at 19:10
  • However, it looks like this does not work with password protected rsa keys. The password input is hidden, forcing the user to have to add the key to their ssh-key in order for this approach to work. Any ideas? – wrangler Dec 7 '11 at 21:03
10

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

~/.ssh/config:

Host B
  HostName 1.2.3.4
  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
  HostName 2.3.4.5

'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'.

Hope this helps others.

  • 3
    I spoke too soon. This solution does not see to work. The key had been loaded in the ssh-agent, so I thought it was working. In the above, the key for C still needs to be on A, not B. – wrangler Dec 6 '11 at 17:36
2

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:

#!/usr/bin/ruby

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
  • I think the adding of a key can be treated as idempotent thereby eliminating the need for get key list. – dmourati Jun 26 '15 at 15:15
  • You should accept serverfault.com/a/701884/127993 which does exactly what you want. – sjas Sep 20 '16 at 18:14
1
#!/usr/bin/env bash
target_host=10.121.77.16
target_port=22
target_user=vagrant

bastion_user=yourusername
bastion_host=10.23.85.245
bastion_port=32780

scp -P $target_port -o ProxyCommand="ssh -o 'ForwardAgent yes' $bastion_user@$bastion_host -p $bastion_port 'ssh-add ~/.ssh/*.rsa && nc %h %p'" /tmp/x.txt $target_user@$target_host:/tmp/
1

To do:

ssh someuser@IP_D

such that

A -> B-> C -> D where A is the host you are on,

edit your local ~/.ssh/config like so:

Host IP_D
  ProxyCommand ssh -o 'ForwardAgent yes' userX@IP_C 'ssh-add && nc %h %p'
Host IP_C
  ProxyCommand ssh -o 'ForwardAgent yes' userY@IP_B 'ssh-add && nc %h %p'

This answer is based on the chosen answer. I had to figure out how various users fit in to the whole scenario.

This works for me. HTH.

0

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
 HostName b.mycompany.com

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

Host C
 User myusername
 HostName c.intranet.mycompany.com
 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
 HostName c.intranet.mycompany.com
 ProxyCommand ssh -T -q -o 'ForwardAgent yes' B 'ssh-add -t 1 ~/.ssh/mykey && nc %h %p'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.