110

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!

3
  • 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? Commented Dec 3, 2011 at 5:25
  • 1
    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. Commented Dec 6, 2011 at 18:03
  • Without nc you can use ssh parameter inside ProxyCommand -W %h:%p Commented Oct 23, 2023 at 9:16

7 Answers 7

119

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$ 
22
  • 5
    Starting with openssh v.7.3, you can just use ProxyJump B. source: wikibooks Commented Nov 12, 2016 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' Commented Jan 27, 2017 at 1:37
  • 3
    How would the solution change if machine B doesn't have nc? Commented Mar 18, 2017 at 13:30
  • 8
    @DrewVS ProxyJump B doesn't seem to work if the private key for C is only present on B. Is there some way to do that as well? Commented Jul 18, 2017 at 13:36
  • 1
    @DrewVS Ok, one needs to add ForwardAgent yes before the ProxyJump command. Commented Jul 18, 2017 at 13:38
43

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.

12
  • 1
    This works but it does not pick up the IdentityFile from B. It still looks on A. Commented Dec 6, 2011 at 18:05
  • @DrewVS I have updated the answer. Please check if it is working for you. Commented Dec 6, 2011 at 18:41
  • Sachin, very clever. That worked perfectly. Thanks so much! Commented Dec 7, 2011 at 19:06
  • @DrewVS glad to hear that it worked for you. so please accept the answer. Commented Dec 7, 2011 at 19:10
  • 4
    FML, this works from the command line, but not when set up in a .ssh/config file using the ProxyCommand. I'm stuck. The whole idea here is to have all my id_rsa keys in a central location, and use the .ssh/config to create the shortcuts to ssh through this central box Commented Dec 9, 2011 at 22:55
12

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

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.

2
  • 6
    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. Commented Dec 6, 2011 at 17:36
  • 2
    This is fantastic. Exactly what I was looking for -- to be able to proxy through a jumpbox using keys locally (to avoid the keys proliferating on the intermediate) Commented May 1, 2020 at 0:26
7

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' 
1
  • if host B and C uses different key file, Can this be done by placing both the key files in the local system(Host A) Commented Dec 13, 2020 at 11:15
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 
2
  • I think the adding of a key can be treated as idempotent thereby eliminating the need for get key list. Commented Jun 26, 2015 at 15:15
  • You should accept serverfault.com/a/701884/127993 which does exactly what you want. Commented Sep 20, 2016 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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.