98

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!

wrangler
  • 3,080
  • 5
  • 24
  • 20
  • 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 03 '11 at 05: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. – wrangler Dec 06 '11 at 18:03

7 Answers7

115

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$
Snowball
  • 1,503
  • 1
  • 12
  • 13
  • This works flawlessly. – sjas Sep 20 '16 at 18:06
  • 5
    Starting with openssh v.7.3, you can just use `ProxyJump B`. source: [wikibooks](https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_Jump_Hosts#Passing_Through_One_or_More_Gateways_Using_ProxyJump) – ki9 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 01:37
  • 2
    How would the solution change if machine B doesn't have `nc`? – mjalajel Mar 18 '17 at 13:30
  • 4
    @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? – Graipher Jul 18 '17 at 13:36
  • 1
    @DrewVS Ok, one needs to add `ForwardAgent yes` *before* the `ProxyJump` command. – Graipher Jul 18 '17 at 13:38
  • Unless I'm misunderstanding ProxyJump, -J and -W I don't think we can get ride of nc for this specific use-case. They allow to forward traffic in various ways, but here we need to fully login on the machine to leverage its private key (with ssh-add), the only way I could get it to work is through nc (same as per the accepted answer). I would love to be proven wrong though. – aymericbeaumet Mar 12 '18 at 10:31
  • 1
    This was the only solution for the particular case for me. All other solutions require gateway root credentials – Erdinç Çorbacı Jul 18 '18 at 14:49
  • I expect this probably works if the private key does not have a passphrase, but with a passphrase I do not get prompted for a passphrase and I get "Bad passphrase, try again". Using -t does not help. It is possible to add the key from B and ssh to C in two steps (ssh -A -t B ssh-add; ssh -J B C), though this (perhaps undesirably) adds the key from B to the agent on A. – Paul Brannan Aug 12 '18 at 10:35
  • This worked for me after a bit, I did have to add a `User` inside the `C` config, as it was using my `A` user (whoami). – Elijah Lynn Dec 18 '18 at 09:06
  • I also had to start `ssh-agent` on `B` as `ssh-add` needs that otherwise I got "Could not open a connection to your authentication agent". See https://stackoverflow.com/a/20403535/292408 – Elijah Lynn Dec 18 '18 at 09:07
  • Also, my key was in the standard location ~/.ssh/ but it was not named the standard id_rsa, so I did have to specify that, eg. `ssh-add ~/.ssh/special-key-name`. – Elijah Lynn Dec 18 '18 at 09:09
  • I added the comment above about needing `ssh-agent` on `B` to the answer as an edit. – Elijah Lynn Dec 18 '18 at 09:13
  • @ElijahLynn It is not necessary to run `ssh-agent` on `B`, only `sshd`. – Snowball Dec 19 '18 at 18:56
  • Hrm, I get this error if I don't https://stackoverflow.com/questions/17846529/could-not-open-a-connection-to-your-authentication-agent/20403535#20403535, even then I have a hard time getting that to work consistently. Wonder what is up with that. – Elijah Lynn Dec 19 '18 at 19:48
  • This solution forwards all ssh connections right? How to forward the agent only for the specific server? – zypro Apr 16 '19 at 06:19
  • Simply not true : https://serverfault.com/questions/724721/ssh-config-proxycommand-asks-for-public-key – MUY Belgium Dec 10 '19 at 13:36
  • Can anyone answer how to do the same without nc ? – Khurshid Alam Apr 06 '20 at 18:50
  • Anyone know how to do this without ssh-add? – yqrashawn May 24 '21 at 02:31
  • Could not open a connection to your authentication agent – Mithril Dec 07 '21 at 09:17
  • Another option (replace \n with newlines because SO comments dont support line breaks): Host C\n Hostname B\n RemoteCommand ssh %n\n RequestTTY yes – vbezhenar Jun 03 '22 at 19:13
  • 1
    A question on Stack Overflow motivated by the usage of single-quotes here, which does does not work for the SO asker: https://stackoverflow.com/q/75735262/11107541 – starball Mar 14 '23 at 18:42
40

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.

Sachin Divekar
  • 2,525
  • 2
  • 21
  • 23
  • 1
    This works but it does not pick up the IdentityFile from B. It still looks on A. – wrangler Dec 06 '11 at 18:05
  • @DrewVS I have updated the answer. Please check if it is working for you. – Sachin Divekar Dec 06 '11 at 18:41
  • Sachin, very clever. That worked perfectly. Thanks so much! – wrangler Dec 07 '11 at 19:06
  • @DrewVS glad to hear that it worked for you. so please accept the answer. – Sachin Divekar Dec 07 '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 07 '11 at 21:03
  • I am not getting your problem. Even if the key is passphrase protected, it is working for me. – Sachin Divekar Dec 07 '11 at 21:22
  • That is likely because the key is in your ssh-agent. If you try running 'ssh-add -D' first, that will clear your ssh-agent. Then, if you try the above again, instead of being prompted for the password to the identity key, it hangs. It looks like the password input is in another tty. Otherwise your solution is great. – wrangler Dec 09 '11 at 02:12
  • @DrewVS Actually I am not using ssh-agent. – Sachin Divekar Dec 09 '11 at 06:08
  • Sachin, you are right! My mistake, not sure what I did wrong before. Thanks for the help. – wrangler Dec 09 '11 at 19:54
  • 2
    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 – wrangler Dec 09 '11 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.

wrangler
  • 3,080
  • 5
  • 24
  • 20
  • 5
    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 06 '11 at 17:36
  • 1
    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) – Anew May 01 '20 at 00:26
6

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'
  • 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) – Cibin Dec 13 '20 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
sjas
  • 324
  • 1
  • 4
  • 13
wrangler
  • 3,080
  • 5
  • 24
  • 20
  • 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 http://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/
wcc526
  • 231
  • 2
  • 4
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.