22

My company production servers (FOO, BAR...) are located behind two gateway servers (A, B). In order to connect to server FOO, I have to open a ssh connection with server A or B with my username JOHNDOE, then from A (or B) I can access any production server opening a SSH connection with a standard username (let's call it WEBBY).

So, each time I have to do something like:

ssh johndoe@a
...
ssh webby@foo
...
# now I can work on the server

As you can imagine, this is a hassle when I need to use scp or if I need to quickly open multiple connections.

I have configured a ssh key and also I'm using .ssh/config for some shortcuts.

I was wondering if I can create some kind of ssh configuration in order to type

ssh foo

and let SSH open/forward all the connections for me. Is it possible?

Edit

womble's answer is exactly what I was looking for but it seems right now I can't use netcat because it's not installed on the gateway server.

weppos:~ weppos$ ssh foo -vv
OpenSSH_5.1p1, OpenSSL 0.9.7l 28 Sep 2006
debug1: Reading configuration data /Users/xyz/.ssh/config
debug1: Applying options for foo
debug1: Reading configuration data /etc/ssh_config
debug2: ssh_connect: needpriv 0
debug1: Executing proxy command: exec ssh a nc -w 3 foo 22
debug1: permanently_drop_suid: 501
debug1: identity file /Users/xyz/.ssh/identity type -1
debug2: key_type_from_name: unknown key type '-----BEGIN'
debug2: key_type_from_name: unknown key type 'Proc-Type:'
debug2: key_type_from_name: unknown key type 'DEK-Info:'
debug2: key_type_from_name: unknown key type '-----END'
debug1: identity file /Users/xyz/.ssh/id_rsa type 1
debug2: key_type_from_name: unknown key type '-----BEGIN'
debug2: key_type_from_name: unknown key type 'Proc-Type:'
debug2: key_type_from_name: unknown key type 'DEK-Info:'
debug2: key_type_from_name: unknown key type '-----END'
debug1: identity file /Users/xyz/.ssh/id_dsa type 2
bash: nc: command not found
ssh_exchange_identification: Connection closed by remote host
gWaldo
  • 11,887
  • 8
  • 41
  • 68
Simone Carletti
  • 1,494
  • 3
  • 15
  • 30

8 Answers8

36

As a more concrete version of Kyle's answer, what you want to put in your ~/.ssh/config file is:

host foo
  User webby
  ProxyCommand ssh a nc -w 3 %h %p

host a
  User johndoe

Then, when you run "ssh foo", SSH will attempt to SSH to johndoe@a, run netcat (nc), then perform an SSH to webby@foo through this tunnel. Magic!

Of course, in order to do this, netcat needs to be installed on the gateway server; this package is available for every major distribution and OS.

womble
  • 95,029
  • 29
  • 173
  • 228
  • Excellent! I was trying to figure that out, I had never run into that exact situation before. I will keep my answer there, in case it might help someone else with a less specific situation in the future. – Kyle Brandt Aug 01 '09 at 13:38
  • I've updated my original question including the verbose output of my connection. It seems I can't use netcat. Should it be available by default? – Simone Carletti Aug 01 '09 at 16:36
  • Not always, do you have the power to install it? You might be able to do this with telnet too, I have never tried that... – Kyle Brandt Aug 01 '09 at 16:48
  • You also might be able to download netcat to your home directory and compile it there. You could then just use the full path in the proxy command, i.e. /home/userName/bin/nc – Kyle Brandt Aug 01 '09 at 16:51
  • I just checked the system settings. On Ubuntu netcat seems to be available by default, unfortunately the gateway servers are powered by OpenSUSE. I'm going to consider installing netcat on the gateway servers too. – Simone Carletti Aug 01 '09 at 19:35
  • I'm having trouble with this solution giving me a "Broken pipe" error, so I posted [a followup question](http://serverfault.com/questions/423960/what-is-the-purpose-of-netcats-w-timeout-option-when-ssh-tunneling). – jrdioko Sep 03 '12 at 18:36
7

You can use the ProxyCommand directive in your ~/.ssh/config file, for example to use netcat as the relay:

host server2
    ProxyCommand ssh server1 nc server2 22

The you would just use 'ssh server2'. The man page information for this directive is found in 'man ssh_config'

Kyle Brandt
  • 82,107
  • 71
  • 302
  • 444
5

I prefer a different approach that maintains a pre-authenticated tunnel to the gateway server. In ~/.ssh/config:

Host a
    ControlMaster auto
    ControlPath ~/.ssh/control-master/%r@%h:%p

Then in .bashrc:

s () {
        if ( ssh -O check a 2>&1 > /dev/null 2>&1 )
        then
                ssh -t a ssh $1
        else
                if [[ -S ~/.ssh/control-master/insyte@a:22 ]]
                then
                        echo "Deleting stale socket..."
                        rm ~/.ssh/control-master/insyte@a:22
                fi
                echo "Opening master session..."
                if ssh -Nf a
                then
                         ssh -t a ssh $1
                fi
        fi
 }

So to connect to foo:

s foo

The first time you connect it will authenticate you against "a" and open a persistent, backgrounded ssh tunnel. Subsequent calls to "s" will open almost instantaneously through the pre-authed tunnel.

Works great.

Insyte
  • 9,314
  • 2
  • 27
  • 45
2

This type of functionality exists in newer versions of OpenSSH and can be used by doing

ssh -W server2 server1

Where server2 is your intended destination and server1 is your proxy host. You can make this easier by using the ProxyCommand option in your ssh config, something like:

host = *.example.com
user = packs
port = 22
ProxyCommand ssh -W %h:%p server1
Scott Pack
  • 14,717
  • 10
  • 51
  • 83
  • It seems that for this to work, you need OpenSSH 5.4+ at all three locations: desktop, intermediary, destination. (Well, the first and last, certainly). – Steve Bennett Dec 20 '12 at 04:28
  • @SteveBennett: I've been using this method for a while now, it works pretty great. I had to revert back to the netcat method on a couple of RHEL5 systems, which was annoying. – Scott Pack Dec 20 '12 at 13:07
2

When netcat is not available on the proxy, try this trick:

host foo
  User webby      
  ProxyCommand ssh a 'exec 3<>/dev/tcp/foo/22; cat <&3 & cat >&3;kill $!'

host a
  User johndoe

Then you should be able to ssh foo.

Also, if you have a recent version of ssh on a (i.e., with the -W command for forwarding standard input and output), you may be able to use:

host foo
  User webby
  ProxyCommand ssh -W foo:%p a

host a
  User johndoe

Finally, just because I found it cool (and not because it will work in your particular case, due to username differences), a friend's blog post points out how to make this kind of thing dynamic and recursively chain SSH proxies (along with some things that don't work well):

host */*
  ProxyCommand ssh ${$(dirname %h)/\%%/@} nc ${$(basename %h)#*%%} %p

And then ssh machine1/machine2 should give you a shell on machine2, tunneled through machine1.

I wonder if using custom sed commands instead of dirname and basename might not solve the problem with different user names?

Paul Price
  • 123
  • 4
2

This can be accomplished by doing ssh -At johndoe@a ssh webby@foo. The -A command forwards your ssh agent (so you can avoid having to re-authenticate on the proxy), while the -t ensures a terminal exists on the proxy. The following bash function may be useful:

ssh-bounce () {
    local cmd=""
    for i in "$@"; do
        cmd+="ssh -At $i "
    done
    $cmd
}
Paul Price
  • 123
  • 4
Marcin
  • 2,281
  • 1
  • 16
  • 14
2

Since OpenSSH 7.3 (2016-08-01) the ProxyJump option and corresponding -J command-line flag have been available to allow more simple indirection through a one or more SSH bastions or "jump hosts".

That removes the dependancy on the external nc command as found in Womble's solution.

ssh -J johndoe@a webby@foo 

will establish an SSH connection from your workstation to the gateway server a as user johndoe and tunnel the SSH session to host foo for user Webby over that.

To simplify that create host definitions for both in your ~/.ssh/config and the you can simply execute ssh foo

Host a
    User johndoe

Host foo
    User Webby 
    ProxyJump a
HBruijn
  • 72,524
  • 21
  • 127
  • 192
0
weppos:~ weppos$ ssh foo -vv
[..]
bash: nc: command not found

Netcat isn't installed on a. When you run ssh host "command arg", command is executed on host, not on your local machine.

markdrayton
  • 2,429
  • 1
  • 20
  • 24