SSH from A through B to C, using private key on B
Solution 1:
Schematic:
ssh ssh
A ------> B ------> C
^ ^
using A's using B's
ssh key ssh key
Preconditions:
A
is running ssh-agent;A
can accessB
;B
can accessC
;A
's ssh public key is present inB:~/.ssh/authorized_keys
B
's ssh public key is present inC:~/.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$
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:
~/.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.
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:
#!/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
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
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 ofA
throughssh-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 anetcat
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'